Exploiter (EOA with EIP-7702 delegation): https://etherscan.io/address/0x935bfb495E33f74d2E9735DF1DA66acE442ede48
Execution proxy (delegatecall executor) https://etherscan.io/address/0x454d03b2a1D52F5F7AabA8E352225335a1b724E8#code
Exploit Contract
Contract 0x454d03b2… does not contain any protocol business logic. It is a general-purpose bytecode interpreter/proxy that:
- executes scripts encoded either in msg.data or stored in storage[keccak256(msg.data)];
- supports: call / staticcall / delegatecall, ETH transfer, balance reading;
- has privileged mode for one address — 0x935bfb495E33f74d2E9735DF1DA66acE442ede48;
- implements coinbase bribe (MEV payment);
- does not contain named Solidity functions — one entrypoint.
Role Machine (Makina)
Machine — is the central accounting/AUM aggregator of the Makina protocol.
- accounting core;
- Total AUM repository;
- share token issuer/burner; AUM aggregator from other chains (Spoke Caliber);
It is the source of:
- convertToAssets
- convertToShares
- getSharePrice
- an indirect oracle source for external protocols (including Curve);
- has permissionless updateTotalAum.
Flashloan — Start of the exploit
Morpho Flashloan
"FlashLoan": {
"token": "USDC",
"assets": "160590920349812"
}USDC has 6 decimals => ≈ 160.6 million USDC
Aave Flashloan (inside of the callback)
Exploiter immediatly execute second flashloan:
Сallback (Aave executeOperation)

This is where the entire attack occurs.
You can immediately see the cyclical nature of the function calls, indicating that the exploit is designed to configure parameters that will allow the tokens to be withdrawn.

First step— Curve DUSD / USDC
Add liquidity

DUSDUSDC.add_liquidity(
amounts = [100_000_000_000_000, 0],
min_mint_amount = 0
) => reulted in ≈ 9.9206722150127812419545815e22 LPCurve recalculates the price
Call swap
DUSDUSDC.exchange(
i = 0,
j = 1,
dx = 10_000_000_000_000,
min_dy = 0
)inside Curve:
@internal
@view
def _stored_rates() -> DynArray[uint256, MAX_COINS]:
for i in range(N_COINS):
if asset_types[i] == 1 and not rate_oracles[i] == 0:
oracle_response = raw_call(rate_oracles[i], method_id)
fetched_rate = convert(oracle_response, uint256)
rates[i] = rates[i] * fetched_rate / PRECISIONWe have:
- asset_types[i] == 1 → Oracle token
- In our case oracle = MachineShareOracle
MachineShareOracle → getSharePrice
function getSharePrice(
uint256 aum,
uint256 supply,
uint256 shareTokenDecimalsOffset
) public pure returns (uint256) {
return SHARE_TOKEN_UNIT.mulDiv(
aum + 1,
supply + 10 ** shareTokenDecimalsOffset
);
}Price depends on:
- lastTotalAum
- shareSupply
Next deformation in the Curve 3Pool
Curve.fi DAI/USDC/USDT.add_liquidity(
[0, 170000000000000, 0]
)After that several calls to Frax MIM-3LP3CRV-f

Add liquidity
MIM-3LP3CRV-f.add_liquidity(
[0, 30_000_000e18]
)Remove liquidity one coin
remove_liquidity_one_coin(
amount = ~15_000_000e18,
i = 0 or 1
)Exchange
exchange(
i = 1,
j = 0,
dx = 120_000_000e18
)CRITICAL POINT— accountForPosition

accountForPosition(
positionId = ...,
isDebt = false,
instructionType = 1
)getSharePrice is used
fixed:
- new position price
- new AUM
- temporary becomes permanent
updateTotalAum — commit фаза
/// @inheritdoc IMachine
function updateTotalAum() external override nonReentrant notRecoveryMode returns (uint256) {
MachineStorage storage $ = _getMachineStorage();
uint256 _lastTotalAum = MachineUtils.updateTotalAum($, IHubCoreRegistry(registry).oracleRegistry());
emit TotalAumUpdated(_lastTotalAum);
uint256 _mintedFees = MachineUtils.manageFees($);
if (_mintedFees != 0) {
emit FeesMinted(_mintedFees);
}
return _lastTotalAum;
}This is a commit function:
- it commits the effect of the manipulation;
it is used for:
- the next convertToShares;
- the next arbitration cycle.
Why does the cycle repeat?
Each cycle:
- Moves the Curve price slightly
- Increases the sharePrice slightly
- Increases the AUM slightly
Next cycle:
- Starts from an already distorted base
- Provides an even more favorable ratio
Final
- All flashloans are closed
- USDC → WETH via Uniswap V3
- WETH → ETH
- ≈ 1,299.04 ETH → MEV builder (coinbase bribe)
- ≈ 0.13 ETH → exploiter's net profit
Root Cause
- Doesn't protect updateTotalAum;
- Doesn't introduce delays/TWAP;
- Doesn't separate accounting and pricing.