Tectonic: direct token donations inflated the exchange rate
Published Oct 19, 2026
- Project
- Tectonic
- Chain
- Cronos
- Date
- Aug 30, 2026
- Loss
- $120.40M
- Class
- Donation Attack
- Basis
- Project post-mortem or audit firm analysis
What happened
On August 30, 2026, Tectonic on Cronos was exploited for approximately $120.4M across nine lending markets. The attacker supplied USDC, borrowed TONIC, and repeatedly redeposited it while transferring TONIC directly into the tTONIC market contract. These unsolicited transfers increased the market's cash balance, which in turn inflated the tTONIC exchange rate. Combined with DEX price manipulation of the low-liquidity TONIC token, the attacker's collateral value grew far beyond its real worth, allowing them to drain the protocol's liquid assets. Cronos validators halted the chain and rolled back roughly $111.2M, but $9.19M had already left the network.
Why it was possible
The tTONIC market used a Compound-style exchange rate formula where the numerator included getCash(), which reads the raw ERC-20 token balance of the contract. No check ensured that this balance only changed through the controlled supply path. A direct transfer of TONIC to the market contract increased getCash() without minting any corresponding tTONIC receipt tokens, silently raising the exchange rate for all existing holders. Formal verification later confirmed that transfer, transferFrom, and borrowOnBehalf could all increase the accounted supply outside the intended mint function. This accounting defect was compounded by using a thin-liquidity token as collateral with an oracle susceptible to spot-price manipulation.
How to protect your protocol
- Track cash with internal counters instead of raw balances. Never derive the exchange rate numerator from the contract's live ERC-20 balance. Maintain an internal variable that increments only when the controlled supply or repay functions execute, so unsolicited transfers cannot alter the rate.
- Formally verify that only mint grows supply. Write a formal property asserting that the accounted supply cannot increase unless the call passes through the designated mint function. Run this against every state-changing method to catch paths like direct transfers or delegated borrows that bypass accounting.
- Reject low-liquidity tokens as primary collateral. A collateral factor alone does not protect against price manipulation if the underlying asset can be moved cheaply on DEXs. Restrict borrowing power for tokens with shallow liquidity or require deep, manipulation-resistant oracle feeds before enabling them as collateral.
- Sweep unexpected token balances automatically. If tokens arrive at the contract outside the normal flow, they should not sit idle and distort math. Implement a sweep mechanism that moves unaccounted tokens to a treasury or fee recipient, keeping the contract's actual balance aligned with internal records.
- Decouple oracle pricing from manipulable spot venues. Do not rely solely on DEX spot prices for collateral valuation, especially for native or low-volume tokens. Use time-weighted average prices, multiple independent sources, or off-chain signed feeds with staleness bounds to prevent localized price spikes from inflating borrowing power.
Check your own code
- Does the exchange rate calculation use an internal cash tracker rather than the raw token balance?
- Is there a formal or tested invariant proving that only the mint function increases the accounted supply?
- Can a direct ERC-20 transfer to the market contract change any user-facing accounting values?
- Are collateral tokens evaluated for DEX liquidity depth before being approved for borrowing?
- Does the oracle feed resist short-term spot price manipulation on thin markets?
- Is there a mechanism to sweep or ignore unsolicited token deposits so they do not inflate share prices?
- Do delegated borrow functions validate that the receiver is not the market contract itself?
Sources
How this was prepared: compiled from the sources above with the help of automated tools, then reviewed by the Foothold security team before publication.
Give Atlant a task
Could the same thing happen in your code?
Get it checked →