2026-03-15 17:54:33 +00:00
|
|
|
|
# Red-team mission: extract ETH from the KRAIKEN LiquidityManager
|
|
|
|
|
|
|
|
|
|
|
|
## Goal
|
|
|
|
|
|
**Extract ETH from the LiquidityManager.** Make the LM end up with less total ETH than it started with.
|
|
|
|
|
|
|
|
|
|
|
|
Total LM ETH before: {{LM_ETH_BEFORE}} wei
|
|
|
|
|
|
(free ETH + free WETH + ETH locked in all 3 Uni V3 positions)
|
|
|
|
|
|
|
|
|
|
|
|
The protocol's ETH is like gold in a cold-backed currency — it's "put to work" in Uniswap positions,
|
|
|
|
|
|
but it should NEVER be extractable by an adversary. Your job is to prove otherwise.
|
|
|
|
|
|
|
|
|
|
|
|
The metric is simple: if LM total ETH goes down, you win.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Current Attack Target
|
|
|
|
|
|
|
|
|
|
|
|
| Field | Value |
|
|
|
|
|
|
|-------|-------|
|
|
|
|
|
|
| Candidate | {{CANDIDATE_NAME}} |
|
|
|
|
|
|
| Optimizer Profile | {{OPTIMIZER_PROFILE}} |
|
|
|
|
|
|
|
|
|
|
|
|
Use the optimizer profile to reason about this candidate's behavior:
|
|
|
|
|
|
- **CI** (concentration index %): higher → optimizer recenters more aggressively → more KRK minting opportunities
|
|
|
|
|
|
- **AW** (anchorWidth ticks): wider → liquidity spread over larger price range → less ETH per tick
|
|
|
|
|
|
- **AS** (anchorShare %): higher → more ETH locked in anchor position → different rebalancing behavior
|
|
|
|
|
|
- **DD** (discoveryDepth %): higher → more ETH in discovery position (above-price) → price-sensitive exposure
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Contract addresses (local Anvil)
|
|
|
|
|
|
|
|
|
|
|
|
| Contract | Address |
|
|
|
|
|
|
|--------------------|---------|
|
|
|
|
|
|
| Kraiken (KRK) | {{KRK}} |
|
|
|
|
|
|
| Stake | {{STAKE}} |
|
|
|
|
|
|
| LiquidityManager | {{LM}} |
|
|
|
|
|
|
| OptimizerProxy | {{OPT}} |
|
|
|
|
|
|
| Pool (WETH/KRK 1%) | {{POOL}} |
|
|
|
|
|
|
| NonfungiblePosManager (NPM) | {{NPM}} |
|
|
|
|
|
|
| WETH | {{WETH}} |
|
|
|
|
|
|
| SwapRouter02 | {{SWAP_ROUTER}} |
|
|
|
|
|
|
|
|
|
|
|
|
RPC: http://localhost:8545
|
|
|
|
|
|
CAST binary: /home/debian/.foundry/bin/cast
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Your accounts
|
|
|
|
|
|
|
|
|
|
|
|
### Adversary — Anvil account 8 (your main account)
|
|
|
|
|
|
- Address: {{ADV_ADDR}}
|
|
|
|
|
|
- Private key: {{ADV_PK}}
|
|
|
|
|
|
- Balance: ~9000 ETH (10k minus 1000 ETH used to fund LM), 0 KRK
|
|
|
|
|
|
|
|
|
|
|
|
### Recenter caller — Anvil account 2
|
|
|
|
|
|
- Address: {{RECENTER_ADDR}}
|
|
|
|
|
|
- Private key: {{RECENTER_PK}}
|
|
|
|
|
|
- Can call recenter() (public, TWAP-enforced)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Protocol mechanics
|
|
|
|
|
|
|
|
|
|
|
|
### ethPerToken (the floor)
|
|
|
|
|
|
```
|
|
|
|
|
|
ethPerToken = (LM_native_ETH + LM_WETH) * 1e18 / adjusted_supply
|
|
|
|
|
|
adjusted_supply = KRK.outstandingSupply() - KRK_at_Stake
|
|
|
|
|
|
```
|
|
|
|
|
|
To DECREASE the floor you must either:
|
|
|
|
|
|
- Reduce LM's ETH/WETH holdings, OR
|
|
|
|
|
|
- Increase the adjusted outstanding supply of KRK
|
|
|
|
|
|
|
|
|
|
|
|
### Three LM positions
|
|
|
|
|
|
The LiquidityManager maintains three Uniswap V3 positions:
|
|
|
|
|
|
1. **ANCHOR** — straddles the current price; provides two-sided liquidity
|
|
|
|
|
|
2. **DISCOVERY** — above current price; captures upside momentum
|
|
|
|
|
|
3. **FLOOR** — a floor bid: ETH in, KRK out. Backing the floor price.
|
|
|
|
|
|
|
|
|
|
|
|
### recenter()
|
|
|
|
|
|
Calling `LiquidityManager.recenter()` removes all three positions, mints or burns KRK
|
|
|
|
|
|
to rebalance, then re-deploys positions at the current price. It:
|
|
|
|
|
|
- Can mint NEW KRK (increasing supply → decreasing floor)
|
|
|
|
|
|
- Can burn KRK (decreasing supply → increasing floor)
|
|
|
|
|
|
- Moves ETH between positions
|
|
|
|
|
|
Any account can call it (public). TWAP oracle enforces safety.
|
|
|
|
|
|
|
|
|
|
|
|
### Staking
|
2026-03-16 09:46:55 +00:00
|
|
|
|
`Stake.snatch(assets, receiver, taxRate, positionsToSnatch)`
|
|
|
|
|
|
- taxRate: 0–29 (index into the 30-element TAX_RATES array — not a raw percentage)
|
2026-03-15 17:54:33 +00:00
|
|
|
|
- KRK staked is held by the Stake contract (excluded from adjusted_supply)
|
|
|
|
|
|
- KRK in Stake does NOT count against the floor denominator
|
|
|
|
|
|
|
|
|
|
|
|
### outstandingSupply() vs totalSupply()
|
|
|
|
|
|
`KRK.outstandingSupply() = totalSupply() - balanceOf(liquidityManager)`
|
|
|
|
|
|
LM-held KRK (in pool positions) is excluded from outstandingSupply.
|
|
|
|
|
|
The floor formula then additionally subtracts KRK at Stake to get adjusted_supply.
|
|
|
|
|
|
feeDestination is set to LM itself, so its KRK is already excluded by outstandingSupply().
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Source Code (read-only reference)
|
|
|
|
|
|
|
|
|
|
|
|
Use the source code below to reason about internal state transitions, edge cases in tick math,
|
|
|
|
|
|
exact mint/burn logic, optimizer parameter effects, and floor formula details.
|
|
|
|
|
|
Do NOT attempt to deploy or modify contracts — these are for reference only.
|
|
|
|
|
|
|
|
|
|
|
|
### LiquidityManager.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_LM}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### ThreePositionStrategy.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_THREE_POS}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Optimizer.sol (base)
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_OPTIMIZER}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### OptimizerV3.sol (current candidate — reflects inject.sh output)
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_OPTIMIZERV3}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### VWAPTracker.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_VWAP}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### PriceOracle.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_PRICE_ORACLE}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-15 18:41:57 +00:00
|
|
|
|
### Kraiken.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_KRAIKEN}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Stake.sol
|
|
|
|
|
|
```solidity
|
|
|
|
|
|
{{SOL_STAKE}}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-15 17:54:33 +00:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Cast command patterns
|
|
|
|
|
|
|
|
|
|
|
|
### Check total LM ETH (run after each strategy)
|
|
|
|
|
|
Measures free ETH + free WETH + ETH locked in all 3 Uni V3 positions.
|
|
|
|
|
|
```bash
|
|
|
|
|
|
CAST=/home/debian/.foundry/bin/cast
|
|
|
|
|
|
LM_ETH=$($CAST balance {{LM}} --rpc-url http://localhost:8545 | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
LM_WETH=$($CAST call {{WETH}} "balanceOf(address)(uint256)" {{LM}} --rpc-url http://localhost:8545 | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
SLOT0=$($CAST call {{POOL}} "slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)" --rpc-url http://localhost:8545)
|
|
|
|
|
|
CUR_TICK=$(echo "$SLOT0" | sed -n '2p' | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
TOKEN0_IS_WETH=$(python3 -c "print(1 if '{{WETH}}'.lower() < '{{KRK}}'.lower() else 0)")
|
|
|
|
|
|
POS_ETH=0
|
|
|
|
|
|
for STAGE in 0 1 2; do
|
|
|
|
|
|
POS=$($CAST call {{LM}} "positions(uint8)(uint128,int24,int24)" $STAGE --rpc-url http://localhost:8545)
|
|
|
|
|
|
LIQ=$(echo "$POS" | sed -n '1p' | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
TL=$(echo "$POS" | sed -n '2p' | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
TU=$(echo "$POS" | sed -n '3p' | sed 's/\[.*//;s/[[:space:]]//g')
|
|
|
|
|
|
POS_ETH=$(python3 -c "
|
|
|
|
|
|
import math
|
|
|
|
|
|
L,tl,tu,tc,t0w=int('$LIQ'),int('$TL'),int('$TU'),int('$CUR_TICK'),bool($TOKEN0_IS_WETH)
|
|
|
|
|
|
prev=int('$POS_ETH')
|
|
|
|
|
|
if L==0: print(prev); exit()
|
|
|
|
|
|
sa=math.sqrt(1.0001**tl); sb=math.sqrt(1.0001**tu); sc=math.sqrt(1.0001**tc)
|
|
|
|
|
|
if t0w:
|
|
|
|
|
|
e=L*(1/sa-1/sb) if tc<tl else (0 if tc>=tu else L*(1/sc-1/sb))
|
|
|
|
|
|
else:
|
|
|
|
|
|
e=L*(sb-sa) if tc>=tu else (0 if tc<tl else L*(sc-sa))
|
|
|
|
|
|
print(prev+int(e))
|
|
|
|
|
|
")
|
|
|
|
|
|
done
|
|
|
|
|
|
TOTAL=$(python3 -c "print(int('$LM_ETH')+int('$LM_WETH')+int('$POS_ETH'))")
|
|
|
|
|
|
echo "Total LM ETH: $TOTAL wei (free: $LM_ETH + $LM_WETH, positions: $POS_ETH)"
|
|
|
|
|
|
echo "Started with: {{LM_ETH_BEFORE}} wei"
|
|
|
|
|
|
python3 -c "b={{LM_ETH_BEFORE}}; a=int('$TOTAL'); d=b-a; print(f'Delta: {d} wei ({d*100//b if b else 0}% extracted)' if d>0 else f'Delta: {d} wei (LM gained ETH)')"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Wrap ETH to WETH
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{WETH}} "deposit()" --value 100ether \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Approve token spend
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send <TOKEN> "approve(address,uint256)" <SPENDER> \
|
|
|
|
|
|
115792089237316195423570985008687907853269984665640564039457584007913129639935 \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Buy KRK (WETH → KRK via SwapRouter)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Must wrap ETH and approve WETH first
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{SWAP_ROUTER}} \
|
|
|
|
|
|
"exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \
|
|
|
|
|
|
"({{WETH}},{{KRK}},{{POOL_FEE}},{{ADV_ADDR}},<WETH_AMOUNT>,0,0)" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Sell KRK (KRK → WETH via SwapRouter)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Must approve KRK first
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{SWAP_ROUTER}} \
|
|
|
|
|
|
"exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \
|
|
|
|
|
|
"({{KRK}},{{WETH}},{{POOL_FEE}},{{ADV_ADDR}},<KRK_AMOUNT>,0,0)" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Stake KRK (snatch with no snatching)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Approve KRK to Stake first
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{STAKE}} \
|
|
|
|
|
|
"snatch(uint256,address,uint32,uint256[])" \
|
|
|
|
|
|
<KRK_AMOUNT> {{ADV_ADDR}} 0 "[]" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Unstake KRK
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{STAKE}} \
|
|
|
|
|
|
"exitPosition(uint256)" <POSITION_ID> \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Advance time (REQUIRED before each recenter call)
|
|
|
|
|
|
recenter() has a 60-second cooldown AND requires 300s of TWAP oracle history.
|
2026-03-15 19:51:52 +00:00
|
|
|
|
<!-- Source constants: MIN_RECENTER_INTERVAL = 60 (LiquidityManager.sol), PRICE_STABILITY_INTERVAL = 300 (PriceOracle.sol) -->
|
2026-03-15 17:54:33 +00:00
|
|
|
|
You MUST advance time before calling recenter:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast rpc evm_increaseTime 600 --rpc-url http://localhost:8545
|
|
|
|
|
|
for i in $(seq 1 10); do /home/debian/.foundry/bin/cast rpc evm_mine --rpc-url http://localhost:8545; done
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-15 19:17:16 +00:00
|
|
|
|
### Trigger recenter (via account 2 — any address may call)
|
2026-03-15 17:54:33 +00:00
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{LM}} "recenter()" \
|
|
|
|
|
|
--private-key {{RECENTER_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Read KRK balance
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast call {{KRK}} "balanceOf(address)(uint256)" {{ADV_ADDR}} \
|
|
|
|
|
|
--rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Read ETH balance
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast balance {{ADV_ADDR}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Add LP position via NPM (mint)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Must approve both tokens to NPM first. tickLower/tickUpper must be multiples of 200 (pool tickSpacing).
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{NPM}} \
|
|
|
|
|
|
"mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))" \
|
|
|
|
|
|
"({{WETH}},{{KRK}},{{POOL_FEE}},<TICK_LOWER>,<TICK_UPPER>,<AMOUNT0>,<AMOUNT1>,0,0,{{ADV_ADDR}},<DEADLINE>)" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Remove LP position via NPM (decreaseLiquidity then collect)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{NPM}} \
|
|
|
|
|
|
"decreaseLiquidity((uint256,uint128,uint256,uint256,uint256))" \
|
|
|
|
|
|
"(<TOKEN_ID>,<LIQUIDITY>,0,0,<DEADLINE>)" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
|
|
|
|
|
|
/home/debian/.foundry/bin/cast send {{NPM}} \
|
|
|
|
|
|
"collect((uint256,address,uint128,uint128))" \
|
|
|
|
|
|
"(<TOKEN_ID>,{{ADV_ADDR}},340282366920938463463374607431768211455,340282366920938463463374607431768211455)" \
|
|
|
|
|
|
--private-key {{ADV_PK}} --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Mine a block
|
|
|
|
|
|
```bash
|
|
|
|
|
|
/home/debian/.foundry/bin/cast rpc evm_mine --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Snapshot and revert (for resetting between strategies)
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Take snapshot (returns ID — save it):
|
|
|
|
|
|
SNAP=$(/home/debian/.foundry/bin/cast rpc anvil_snapshot --rpc-url http://localhost:8545 | tr -d '"')
|
|
|
|
|
|
# Revert to snapshot (one-shot — take a new snapshot immediately after):
|
|
|
|
|
|
/home/debian/.foundry/bin/cast rpc anvil_revert $SNAP --rpc-url http://localhost:8545
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Constraints
|
|
|
|
|
|
|
|
|
|
|
|
- **feeDestination = LM itself** — fees are NOT extracted, they accrue as LM liquidity.
|
|
|
|
|
|
When computing ethPerToken, do NOT subtract KRK at feeDestination (it's the same as LM,
|
|
|
|
|
|
and outstandingSupply() already excludes LM-held KRK).
|
|
|
|
|
|
- **LM has ~1000 ETH reserve** — proportional to your 10,000 ETH (10:1 ratio). This is a
|
|
|
|
|
|
realistic attack scenario, not an empty vault.
|
|
|
|
|
|
- **You MUST NOT call anvil_reset, anvil_setCode, or anvil_setStorageAt.** These are infra
|
|
|
|
|
|
cheats that invalidate the test. Use only swap/stake/LP/recenter protocol operations.
|
|
|
|
|
|
|
|
|
|
|
|
## Rules
|
|
|
|
|
|
|
|
|
|
|
|
1. You have ~9000 ETH (after funding LM with 1000 ETH). Start by wrapping some if you need WETH for swaps.
|
|
|
|
|
|
2. Your goal is to make the LM's total ETH DECREASE vs the starting value ({{LM_ETH_BEFORE}} wei).
|
|
|
|
|
|
3. Try at least 3 distinct strategies. After each attempt:
|
|
|
|
|
|
a. Run the total LM ETH check command above.
|
|
|
|
|
|
b. If total LM ETH DECREASED — report this as a SUCCESS and describe the exact steps.
|
|
|
|
|
|
c. If LM ETH held or INCREASED — revert to the snapshot and try a new strategy.
|
|
|
|
|
|
Remember: `anvil_revert` is one-shot. Take a new snapshot immediately after reverting.
|
|
|
|
|
|
4. You may chain multiple actions in one strategy (e.g. large buy → recenter → large sell).
|
|
|
|
|
|
5. Be methodical. Report every strategy tried even if it failed.
|
|
|
|
|
|
6. If Previous Findings are provided, DO NOT repeat those strategies. Use their insights to design new approaches.
|
|
|
|
|
|
7. Prioritize untried COMBINATIONS: staking + LP, staking + recenter timing, LP + multi-step swaps, etc.
|
|
|
|
|
|
8. Start executing immediately. No lengthy planning — act, measure, iterate.
|
|
|
|
|
|
9. For EVERY strategy attempted, record:
|
|
|
|
|
|
- **Pattern**: abstract op sequence (e.g., "buy → stake_all → recenter_multi → unstake → sell")
|
|
|
|
|
|
- **Insight**: WHY this worked or failed, referencing the optimizer profile ({{OPTIMIZER_PROFILE}}).
|
|
|
|
|
|
For HELD/INCREASED: which mechanism defended the floor? How did CI/AW/AS/DD cause it?
|
|
|
|
|
|
For DECREASED: which parameter combination created the vulnerability? Is it universal or optimizer-specific?
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
{{CROSS_CANDIDATE_SECTION}}
|
|
|
|
|
|
|
|
|
|
|
|
{{MEMORY_SECTION}}
|
|
|
|
|
|
|
|
|
|
|
|
## Final report format
|
|
|
|
|
|
|
|
|
|
|
|
After trying all strategies, output a clearly structured report:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
=== RED-TEAM REPORT ===
|
|
|
|
|
|
|
|
|
|
|
|
Candidate: {{CANDIDATE_NAME}}
|
|
|
|
|
|
Optimizer Profile: {{OPTIMIZER_PROFILE}}
|
|
|
|
|
|
lm_eth_before: <value> wei (total: free + positions)
|
|
|
|
|
|
|
|
|
|
|
|
STRATEGY 1: <name>
|
|
|
|
|
|
Pattern: <abstract op sequence e.g. "buy → recenter → sell">
|
|
|
|
|
|
Steps: <what you did>
|
|
|
|
|
|
lm_eth_after: <value> wei
|
|
|
|
|
|
Result: ETH_EXTRACTED / ETH_SAFE / ETH_GAINED
|
|
|
|
|
|
Insight: <WHY this worked/failed given the optimizer profile>
|
|
|
|
|
|
|
|
|
|
|
|
STRATEGY 2: ...
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
=== CONCLUSION ===
|
|
|
|
|
|
ETH extracted: YES / NO
|
|
|
|
|
|
Winning strategy: <describe if YES, else "None">
|
|
|
|
|
|
Universal pattern: <would this likely work on other candidates? Why or why not?>
|
|
|
|
|
|
lm_eth_before: {{LM_ETH_BEFORE}} wei
|
|
|
|
|
|
lm_eth_after: <final value> wei
|
|
|
|
|
|
```
|