# ThecosomataETH: Oracle price can be better secured (freshness + tamper-resistance)

ThecosomataETH trusts Curve pool EMA price_oracle without freshness or deviation checks, letting a manipulator skew BTRFLY price before performUpkeep to misprice liquidity deposits.

- Payout: Audit contest
- Severity: medium
- Program: Redacted Cartel
- Found by: hickuphh3
- Disclosed: 2022-05-11
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2022-02-redacted-cartel#m-17
- Library page: https://bugbountylibrary.com/r/c4%3A2022-02-redacted-cartel%3AM-17
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** ThecosomataETH.calculateAmountRequiredForLP() reading Curve ETH-BTRFLY price_oracle
**Root cause:** calculateAmountRequiredForLP() consumes the Curve v2 EMA price_oracle with no staleness bound and no check that last_prices deviates within a tolerance from price_oracle, so a skewed or stale oracle directly drives deposit sizing.
**Steps:**
1. Read price_oracle from the ETH-BTRFLY Curve crypto pool inside calculateAmountRequiredForLP() (L94-L110).
2. Note EMA half-time T1/2 = 600s; after 10 minutes pLast and p_old carry equal weight.
3. Observe no require on last_prices_timestamp() freshness and no deviation check between last_prices() and price_oracle().
4. Attacker inflates BTRFLY price a couple of blocks before performUpkeep() so the treasury deposits more ETH / burns more BTRFLY than necessary.
**How found:** Reasoned from the Curve v2 whitepaper EMA formula: freshness and tamper-resistance trade off, and the contract applies neither a staleness bound nor a last_prices-vs-price_oracle deviation bound before sizing deposits.
**Exploitation:** A sophisticated attacker skews the BTRFLY price in the pool a few blocks before performUpkeep(), so the EMA oracle feeds an inflated price into calculateAmountRequiredForLP() and the treasury over-deposits ETH or over-burns BTRFLY. Flash loans are ineffective because t=0 makes pLast ignored in the EMA update.
**Insight:** When a contract consumes a Curve v2 EMA oracle, check both last_prices_timestamp() freshness and the last_prices/price_oracle deviation; a multi-block skew before a keeper call (performUpkeep) can misprice treasury actions even when flash loans are neutralized by t=0.

## Proof of concept (copied exactly from the original report)

**Stale price freshness check require**

```
// eg. last price update / trade must have been executed within the past hour
uint256 lastPricesTimestamp = ICurveCryptoPool(CURVEPOOL).last_prices_timestamp();
require(block.timestamp - lastPricesTimestamp <= 1 hours, 'stale price');
```

**Deviation check between last and oracle price**

```
uint256 lastPrice = ICurveCryptoPool(CURVEPOOL).last_prices();
uint256 oraclePrice = ICurveCryptoPool(CURVEPOOL).price_oracle();
uint256 percentDiff;
// eg. require difference in prices to be within 5%
if (lastPrice > oraclePrice) {
 percentDiff = (lastPrice - oraclePrice) * 1e18 / oraclePrice;
} else {
 percentDiff = (oraclePrice - lastPrice) * 1e18 / oraclePrice;
}
require(percentDiff <= 5e16, 'volatile market');
```

