All incidents

Cream Finance cAmp / Amp Reentrancy Exploit

Share
Aug 30, 2021 04:27 UTCAttackLoss: 9,740,000 AMPManually checked3 exploit txWindow: 1h 42m
Estimated Impact
9,740,000 AMP
Label
Attack
Exploit Tx
3
Addresses
4
Attack Window
1h 42m
Aug 30, 2021 04:27 UTC → Aug 30, 2021 06:09 UTC

Exploit Transactions

TX 1Ethereum
0x8dd9fa7e5d1ea4fb145c9c42513281e53d252590822d2f09b2c0266e8666b2c6
Aug 30, 2021 04:27 UTCExplorer
TX 2Ethereum
0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e
Aug 30, 2021 05:44 UTCExplorer
TX 3Ethereum
0x2506926d1e547ebcfdc276cee9e1115f2399c4f211cdb53a5bb67df1e601d908
Aug 30, 2021 06:09 UTCExplorer

Victim Addresses

0x2db6c82ce72c8d7d770ba1b5f5ed0b6e075066d6Ethereum
0xd06527d5e56a3495252a528c4987003b712860eeEthereum
0xff20817765cb7f73d4bde2e66e067e58d11095c2Ethereum
0x3d5bc3c8d13dcb8bf317092d84783c2697ae9258Ethereum

Loss Breakdown

9,740,000AMP

Similar Incidents

Root Cause Analysis

Cream Finance cAmp / Amp Reentrancy Exploit

1. Incident Overview TL;DR

On Ethereum mainnet between blocks 13124721 and 13125173, an adversary-controlled EOA and two helper contracts exploited Cream Finance’s Amp-backed cToken market (cAmp). By combining Amp’s ERC-1820 AmpTokensRecipient hook with Cream’s cToken cash-transfer logic, the attacker executed a single borrow/liquidation transaction that moved 9,740,000 AMP out of the cAmp contract to the attacker while Cream’s internal accounting still reported the market as fully backed. Across three attacker-crafted transactions, the adversary’s portfolio increased by exactly 9,740,000 AMP and 1,341.307701197557 ETH after gas, making this a clear anyone-can-take (ACT) opportunity.

The root cause is that cAmp’s CCollateralCapErc20CheckRepay implementation assumes underlying token transfers are atomic and non-reentrant. It calls Amp.transferFrom/transfer inside doTransferIn/doTransferOut and only afterwards updates the internalCash and related accounting. Amp, however, invokes an AmpTokensRecipient hook on the adversary helper contract during these transfers. This reentrancy window allows borrow and liquidation logic to run while internalCash and Amp balances still reflect pre-transfer state, causing the backing term

// CToken backing invariant (informal)
E = internalCash + totalBorrows - totalReserves;

to increase even though Amp.balanceOf(cAmp) and internalCash both decrease by 9,740,000 AMP.

2. Key Background

Cream Finance’s markets follow a Compound-style cToken design. For each market (including cAmp and CEther), the protocol tracks at least the following aggregate variables:

  • internalCash: underlying tokens held by the cToken contract (Amp for cAmp, ETH for CEther).
  • totalBorrows: the total principal borrowed by users, adjusted by a borrow index.
  • totalReserves: accumulated reserves taken from interest or fees.
  • totalSupply: total number of cTokens in circulation.
  • totalCollateralTokens (for cAmp): amount of underlying counted as collateral.

These are intended to obey a backing relation

E = internalCash + totalBorrows - totalReserves;

such that, with totalSupply and totalCollateralTokens fixed during a transaction, changes in E reflect real changes in the underlying token backing (plus interest/reserve updates), and never create backing out of thin air.

The cAmp market is deployed as a CErc20Delegator proxy at address 0x2db6c82ce72c8d7d770ba1b5f5ed0b6e075066d6, pointing to the CCollateralCapErc20CheckRepayDelegate implementation 0x96cc0f947b6c8f4675159ea03144f8c17d5a2fc8. The verified source for this implementation is stored under the data collector artifacts:

artifacts/root_cause/data_collector/iter_3/contract/1/0x96cc0f947b6c8f4675159ea03144f8c17d5a2fc8/source/src

The relevant victim-side logic comes from two files:

  • CCollateralCapErc20CheckRepay.sol (cAmp’s concrete implementation).
  • CTokenCheckRepay.sol / CToken.sol (shared cToken accounting, including exchangeRateStored and borrow/liquidation flows).

The CEther market used as collateral in the exploit is at 0xd06527d5e56a3495252a528c4987003b712860ee, with state diffs captured in:

artifacts/root_cause/data_collector/iter_5/state/1/0xd06527d5e56a3495252a528c4987003b712860ee/0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e_state_diff.json

The Comptroller/Unitroller governs both cAmp and CEther:

  • Unitroller proxy: 0x3d5bc3c8d13dcb8bf317092d84783c2697ae9258.
  • Comptroller implementation: 0x7aa375f1fe5e04e18a6b02b4294cfd57ca9f53ba, with verified source under Comptroller.sol in the same contract source tree as cAmp.

Amp (the underlying) is an ERC-20–compatible token deployed at 0xff20817765cb7f73d4bde2e66e067e58d11095c2. It additionally integrates with the ERC-1820 registry to support Amp-specific hooks. A key artifact is the ERC-1820 snapshot for Amp hooks:

// ERC-1820 Amp hook snapshot
{
  "0x38c40427efbaae566407e4cde2a91947df0bd22b": {
    "AmpTokensSender": {
      "implementer": "0x0000000000000000000000000000000000000000"
    },
    "AmpTokensRecipient": {
      "implementer": "0x38c40427efbAAe566407e4CdE2A91947dF0bD22B"
    }
  }
}

This is taken from:

artifacts/root_cause/data_collector/iter_3/erc1820/erc1820_amp_hooks.json

It shows that the adversary helper contract 0x38c40427efbaae566407e4cde2a91947df0bd22b is registered as an AmpTokensRecipient implementer, while cAmp and the Comptroller are not. Whenever Amp transfers tokens to 0x38c4…, Amp will invoke the helper’s recipient hook.

The ACT opportunity is evaluated around the exploit transaction

tx 0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e
block 13125071 (Ethereum mainnet)

using pre-state approximated by end-of-block 13125070 and post-state at end-of-block 13125071. This approximation is made explicit in the state diff artifacts and is numerically sufficient to show the invariant violation.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is a reentrancy issue arising from Amp’s ERC-1820 hooks interacting with cAmp’s cash-transfer helpers. cAmp’s doTransferIn/doTransferOut functions wrap Amp.transferFrom/transfer calls and then update internalCash based on the observed change in Amp.balanceOf(address(this)), under the assumption that the external token call completes atomically and cannot reenter protocol logic.

Amp, however, invokes an AmpTokensRecipient hook on contracts registered in the ERC-1820 registry. The adversary helper contract 0x38c4… is such a recipient. During Amp.transfer or Amp.transferFrom to 0x38c4…, Amp executes 0x38c4…’s hook, which in this exploit calls back into CEther, the Comptroller, and cAmp while cAmp’s internalCash and aggregate accounting variables still reflect pre-transfer values.

The intended backing invariant for cAmp is:

  • With totalSupply and totalCollateralTokens fixed in a transaction, E = internalCash + totalBorrows - totalReserves must track the true Amp backing and should change only due to interest accrual and reserve-factor logic, in a way that matches net Amp inflows/outflows.
  • In particular, if Amp leaves cAmp with no compensating inflow, E must not increase.

In the exploit transaction, state diffs for cAmp show that internalCash decreases by 9,740,000 AMP while totalBorrows and totalReserves both increase, causing E to increase by 1,887,895,286,798,755,706,575 Amp units despite no Amp inflow. This is only possible if the borrow and liquidation flows execute on stale internalCash and Amp balances due to reentrant execution inside Amp.transfer/transferFrom, which is precisely what the call trace and ERC-1820 hook configuration show.

In short:

  • Vulnerability class: reentrancy via token hook during cash-in/cash-out path.
  • Breakpoint: Amp.transfer/transferFrom calls in cAmp’s doTransferIn/doTransferOut, which update internalCash only after the external call, allowing reentrancy.
  • Consequence: an increase in the internal backing term E while cAmp’s actual Amp balance falls by 9,740,000 AMP, enabling theft of these tokens by any unprivileged adversary who deploys an AmpTokensRecipient helper and replicates the transaction sequence.

4. Detailed Root Cause Analysis

4.1 cAmp cash-transfer implementation and backing invariant

The concrete cAmp implementation CCollateralCapErc20CheckRepay is responsible for moving Amp in and out of the market. The doTransferIn helper is implemented as:

// CCollateralCapErc20CheckRepay.sol (simplified excerpt)
function doTransferIn(
    address from,
    uint256 amount,
    bool isNative
) internal returns (uint256) {
    isNative; // unused

    EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
    uint256 balanceBefore = EIP20Interface(underlying).balanceOf(address(this));
    token.transferFrom(from, address(this), amount);

    bool success;
    assembly {
        switch returndatasize()
        case 0 { success := not(0) }
        case 32 { returndatacopy(0, 0, 32) success := mload(0) }
        default { revert(0, 0) }
    }
    require(success, "TOKEN_TRANSFER_IN_FAILED");

    uint256 balanceAfter = EIP20Interface(underlying).balanceOf(address(this));
    uint256 transferredIn = sub_(balanceAfter, balanceBefore);
    internalCash = add_(internalCash, transferredIn);
    return transferredIn;
}

Similarly, doTransferOut calls Amp.transfer(to, amount) and only afterwards decrements internalCash by amount. This pattern assumes that the token transfer is atomic: the contract records the old balance, calls the token, then records the new balance and updates internalCash.

In the base cToken code (CTokenCheckRepay.sol and CToken.sol), borrow and liquidation flows read and update totalBorrows, totalReserves, and other market variables on the assumption that doTransferIn/doTransferOut safely encapsulate the cash movement. For example, exchangeRateStoredInternal() calculates:

uint256 totalCash = getCashPrior();
uint256 cashPlusBorrowsMinusReserves = sub_(add_(totalCash, totalBorrows), totalReserves);
uint256 exchangeRate = div_(cashPlusBorrowsMinusReserves, Exp({mantissa: _totalSupply}));

and the broader design expects totalCash (and thus internalCash) to track the true underlying token balances.

4.2 Amp ERC-1820 hooks and the adversary helper contract

Amp supports custom hooks via the ERC-1820 registry. The snapshot in erc1820_amp_hooks.json shows that the adversary helper contract 0x38c4… is registered as an AmpTokensRecipient implementer. cAmp and the Comptroller have AmpTokensRecipient implementers set to the zero address, so only 0x38c4… receives callbacks.

Whenever Amp transfers tokens to 0x38c4… (either via transfer or transferFrom), Amp queries ERC-1820 and calls 0x38c4…’s recipient hook. This callback happens inside the execution of the Amp.transfer/transferFrom call triggered by cAmp’s doTransferOut/doTransferIn.

The call trace for the exploit transaction

artifacts/root_cause/data_collector/iter_4/tx/1/0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e/call_trace.debug.json

shows that 0x38c4… performs complex interactions with CEther, the Comptroller, and cAmp during the exploit, including borrow and liquidation flows.

4.3 Exploit transaction mechanics and invariant violation

The core exploit occurs in:

tx 0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e
block 13125071
from EOA 0xce1f4b4f17224ec6df16eeb1e3e5321c54ff6ede
call to 0x38c40427efbaae566407e4cde2a91947df0bd22b (helper contract)

A high-level view from the call trace shows the following steps:

  • 0x38c4… triggers a Uniswap V2 flash swap on the AMP/WETH pair 0x21b8065d10f73ee2e260e5b47d3344d3ced7596e to borrow WETH.
  • 0x38c4… unwraps WETH to ETH via WETH9.
  • 0x38c4… supplies ETH to CEther 0xd06527d5e56a3495252a528c4987003b712860ee through the Comptroller to mint 1,510,361,367,176 cETH.
  • Using this CEther collateral, 0x38c4… interacts with cAmp 0x2db6…66d6 to borrow Amp and perform liquidations.
  • As cAmp transfers Amp to 0x38c4… during these operations, Amp invokes 0x38c4…’s AmpTokensRecipient hook, which reenters the Cream markets and triggers more borrow/liquidation logic.
  • At the end of the transaction, Uniswap is repaid with WETH plus premium, and the adversary’s EOA ends up with 9,740,000 more AMP.

The balance diff for this transaction is recorded in:

// balance_diff for tx 0xa9a1…e61e
{
  "erc20_balance_deltas": [
    {
      "token": "0xff20817765cb7f73d4bde2e66e067e58d11095c2",
      "holder": "0x2db6c82ce72c8d7d770ba1b5f5ed0b6e075066d6",
      "before": "33663858581302237334110531",
      "after": "23923858581302237334110531",
      "delta": "-9740000000000000000000000",
      "contract_name": "Amp"
    },
    {
      "token": "0xff20817765cb7f73d4bde2e66e067e58d11095c2",
      "holder": "0xce1f4b4f17224ec6df16eeb1e3e5321c54ff6ede",
      "before": "332557977063785006705096485",
      "after": "342297977063785006705096485",
      "delta": "9740000000000000000000000",
      "contract_name": "Amp"
    }
  ]
}

(from artifacts/root_cause/data_collector/iter_4/tx/1/0xa9a1…e61e/balance_diff.json). This shows that Amp.balanceOf(cAmp) decreases by exactly 9,740,000 AMP while the adversary EOA’s Amp balance increases by the same amount.

The cAmp state diff across the transaction is:

// cAmp state diff (scalars only)
{
  "scalars": {
    "totalBorrows": {
      "before": "470166088159676190211552469",
      "after":  "479909520696561278858291695"
    },
    "totalSupply": {
      "before": "2515641748500199266",
      "after":  "2515641748500199266"
    },
    "totalReserves": {
      "before": "207252914123973988114735",
      "after":  "208797555722263879147386"
    },
    "internalCash": {
      "before": "33663858581302237334110531",
      "after":  "23923858581302237334110531"
    },
    "totalCollateralTokens": {
      "before": "1218382802034500652",
      "after":  "1218382802034500652"
    }
  }
}

(from artifacts/root_cause/data_collector/iter_5/state/1/0x2db6…66d6/0xa9a1…e61e_state_diff.json). From these values, the backing term E = internalCash + totalBorrows - totalReserves is:

  • Before: 503,622,693,826,854,453,557,548,265.
  • After: 503,624,581,722,141,252,313,254,840.
  • Delta: +1,887,895,286,798,755,706,575.

At the same time:

  • totalSupply and totalCollateralTokens are constant.
  • Amp.balanceOf(cAmp) drops by 9,740,000 AMP and there is no Amp inflow to cAmp in this transaction.

Therefore, cAmp’s internal accounting claims more Amp backing per cAmp after the transaction even though the contract holds fewer Amp tokens. This is an explicit violation of the intended backing invariant.

The only way to reconcile this with the code and traces is that, during Amp.transfer/transferFrom calls inside doTransferIn/doTransferOut, Amp’s AmpTokensRecipient hook on 0x38c4… reenters Cream’s contracts and invokes borrow/liquidation logic that increases totalBorrows and totalReserves as if additional Amp had been repaid or reserved, while internalCash (and the on-chain Amp balances) reflect a pure outflow of 9,740,000 AMP.

4.4 CEther behavior and isolation of the loss to cAmp

The CEther state diff for the same transaction is recorded in:

artifacts/root_cause/data_collector/iter_5/state/1/0xd06527d5e56a3495252a528c4987003b712860ee/0xa9a1…e61e_state_diff.json

It shows:

  • totalBorrows increasing slightly, consistent with normal borrow usage.
  • totalReserves increasing modestly from interest/reserve-factor logic.
  • totalSupply decreasing, consistent with redemptions.

The native balance diff for CEther from the transaction’s balance_diff.json shows CEther losing 42.583432458943489116 ETH, while WETH and the miner balances adjust accordingly. These values align with expected interest and premium flows and do not show anomalous ETH creation. This indicates that the exploit’s economic impact is concentrated in the Amp-backed cAmp market, not in CEther.

5. Adversary Flow Analysis

The adversary executes three attacker-crafted transactions from the same EOA 0xce1f4…:

  1. Stage 1 – Amp allowance setup

    • Transaction: 0x8dd9fa7e5d1ea4fb145c9c42513281e53d252590822d2f09b2c0266e8666b2c6 (block 13124721).
    • Action: the EOA calls Amp to approve 1inch router 0x11111112542d85b3ef69ae05771c2dccff4faa26 for unlimited allowance.
    • Evidence: receipt and logs at artifacts/root_cause/data_collector/iter_2/address/1/0xce1f4…ede/tx_receipts/0x8dd9…b2c6.json show an Amp Approval event for the router. The balance diff at artifacts/root_cause/data_collector/iter_4/tx/1/0x8dd9…b2c6/balance_diff.json shows no Amp balance change and a small ETH gas cost, consistent with a pure approval.
  2. Stage 2 – Core Cream/Amp reentrancy exploit

    • Transaction: 0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e (block 13125071).
    • Action: the EOA calls helper contract 0x38c4…, which:
      • Executes a Uniswap flash swap on AMP/WETH pair 0x21b8…596e to borrow WETH.
      • Unwraps WETH to ETH via WETH9.
      • Supplies ETH to CEther 0xd065…60ee via the Comptroller to mint cETH collateral.
      • Uses the cETH collateral to interact with cAmp 0x2db6…66d6, borrowing Amp and performing liquidations.
      • Receives Amp transfers from cAmp, which invoke Amp’s AmpTokensRecipient hook on 0x38c4…; inside this hook, 0x38c4… reenters CEther, the Comptroller, and cAmp to perform further borrow/liquidation steps while cAmp’s internalCash and Amp balances are stale.
    • Outcome: Amp.balanceOf(cAmp) decreases by 9,740,000 AMP, Amp.balanceOf(0xce1f4…) increases by 9,740,000 AMP, and cAmp’s E = internalCash + totalBorrows - totalReserves increases by 1,887,895,286,798,755,706,575 Amp units with totalSupply unchanged.
    • Evidence: call_trace.debug.json and balance_diff.json for this transaction, plus the cAmp and CEther state diffs, as cited above.
  3. Stage 3 – WETH to ETH profit realization

    • Transaction: 0x2506926d1e547ebcfdc276cee9e1115f2399c4f211cdb53a5bb67df1e601d908 (block 13125173).
    • Action: the EOA calls WETH9 to withdraw WETH to native ETH, realizing the WETH proceeds from the exploit.
    • Evidence: receipt at artifacts/root_cause/data_collector/iter_2/address/1/0xce1f4…ede/tx_receipts/0x2506…d908.json and balance diff at artifacts/root_cause/data_collector/iter_4/tx/1/0x2506…d908/balance_diff.json show WETH9’s ETH balance decreasing and the EOA’s ETH balance increasing by 1,341.877732027261864457 ETH, with the difference attributed to miner compensation and gas.

Across these three transactions, the adversary cluster consists of:

  • EOA 0xce1f4b4f17224ec6df16eeb1e3e5321c54ff6ede: sender of all three transactions and ultimate holder of the 9,740,000 AMP and net ETH profit.
  • Helper contract 0x38c40427efbaae566407e4cde2a91947df0bd22b: orchestrates Uniswap, CEther, and cAmp interactions and holds the AmpTokensRecipient registration.
  • Liquidator helper 0x0ec306d7634314d35139d1df4a630d829475a125: participates in cAmp liquidations during the exploit transaction (as visible in the call trace and state diffs).

The flow uses only public interfaces and standard DeFi components: Uniswap V2, WETH9, CEther, Comptroller, cAmp, and Amp. There is no privileged access or whitelisting, so any unprivileged adversary can deploy equivalent helper contracts and submit the same calldata, satisfying the ACT criteria.

6. Impact & Losses

The direct on-chain loss to the Cream cAmp market is 9,740,000 AMP, as measured by the change in Amp.balanceOf(cAmp) across the exploit transaction. This is captured in the Amp ERC-20 balance diff for tx 0xa9a1…e61e, where cAmp’s Amp balance decreases by exactly 9,740,000 × 10¹⁸ units and the adversary EOA’s Amp balance increases by the same amount.

From the viewpoint of the adversary’s ETH-denominated portfolio, the Uniswap AMP/ETH valuation report shows:

// per-tx ETH portfolio changes (from uniswap_amp_eth_valuation_report.json)
{
  "per_tx": [
    {
      "txhash": "0x2506926d1e547ebcfdc276cee9e1115f2399c4f211cdb53a5bb67df1e601d908",
      "net_portfolio_delta_eth": 1341.872788649557
    },
    {
      "txhash": "0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e",
      "net_portfolio_delta_eth": -0.55130724
    },
    {
      "txhash": "0x8dd9fa7e5d1ea4fb145c9c42513281e53d252590822d2f09b2c0266e8666b2c6",
      "net_portfolio_delta_eth": -0.013780212
    }
  ],
  "net_portfolio_delta_eth_total": 1341.307701197557
}

(from artifacts/root_cause/data_collector/iter_4/address/1/0xce1f4…ede/pricing/uniswap_amp_eth_valuation_report.json). The per-transaction values already account for gas costs via gas_cost_wei. Summing them yields a net ETH-denominated portfolio increase of exactly 1,341.307701197557 ETH for the adversary across the three attacker-crafted transactions.

CEther’s behavior is consistent with normal interest and reserve accounting and does not show anomalous ETH creation; the observed ETH movements reflect legitimate collateral flows and flash swap repayment. The economic loss is therefore concentrated in the Amp collateral pool backing cAmp, manifesting as a deficit between the promised value of cAmp and the actual Amp tokens held by the protocol.

7. References

Key artifacts supporting this root cause analysis include:

  • Exploit transaction trace and balances
    • Seed transaction 0xa9a1b8ea288eb9ad315088f17f7c7386b9989c95b4d13c81b69d5ddad7ffe61e:
      • Trace: artifacts/root_cause/data_collector/iter_4/tx/1/0xa9a1…e61e/call_trace.debug.json.
      • Balance diff: artifacts/root_cause/data_collector/iter_4/tx/1/0xa9a1…e61e/balance_diff.json.
  • State diffs for victim markets
    • cAmp (CErc20Delegator 0x2db6…66d6):
      • artifacts/root_cause/data_collector/iter_5/state/1/0x2db6…66d6/0xa9a1…e61e_state_diff.json.
    • CEther (0xd065…60ee):
      • artifacts/root_cause/data_collector/iter_5/state/1/0xd065…60ee/0xa9a1…e61e_state_diff.json.
  • Victim implementation source code
    • cAmp implementation and base cToken logic:
      • artifacts/root_cause/data_collector/iter_3/contract/1/0x96cc0f947b6c8f4675159ea03144f8c17d5a2fc8/source/src/CCollateralCapErc20CheckRepay.sol.
      • artifacts/root_cause/data_collector/iter_3/contract/1/0x96cc0f947b6c8f4675159ea03144f8c17d5a2fc8/source/src/CTokenCheckRepay.sol.
      • artifacts/root_cause/data_collector/iter_3/contract/1/0x96cc0f947b6c8f4675159ea03144f8c17d5a2fc8/source/src/CToken.sol.
    • Comptroller implementation:
      • artifacts/root_cause/data_collector/iter_3/contract/1/0x7aa375f1fe5e04e18a6b02b4294cfd57ca9f53ba/source/src/Comptroller.sol.
  • Amp ERC-1820 hooks
    • AmpTokensRecipient and AmpTokensSender configuration:
      • artifacts/root_cause/data_collector/iter_3/erc1820/erc1820_amp_hooks.json.
  • Adversary portfolio valuation
    • Uniswap AMP/ETH valuation for adversary EOA 0xce1f4…:
      • artifacts/root_cause/data_collector/iter_4/address/1/0xce1f4b4f17224ec6df16eeb1e3e5321c54ff6ede/pricing/uniswap_amp_eth_valuation_report.json.
  • Additional context
    • Data collection summary:
      • artifacts/root_cause/data_collector/data_collection_summary.json.
    • Root cause analyzer iteration 6 summary:
      • artifacts/root_cause/root_cause_analyzer/iter_6/current_analysis_result.json.

These artifacts collectively demonstrate that the Cream/Amp integration permits AmpTokensRecipient-based reentrancy during doTransferIn/doTransferOut, violates the backing invariant E = internalCash + totalBorrows - totalReserves, and enables a deterministic ACT opportunity that yields 9,740,000 AMP and 1,341.307701197557 ETH to an unprivileged adversary.