Radiant Capital Native USDC Empty-Market liquidityIndex Exploit (2024-01-02)
- Name: Radiant Capital native USDC empty-market liquidityIndex exploit
- Date: 2024-01-02
- Protocol: Radiant Capital
- Chain: Arbitrum
- Category: empty-market liquidityIndex inflation / precision-loss burn / cross-market lending drain
- Loss: about 1,900 WETH (roughly $4.5 million at the time)
- Summary: The attacker waited for Radiant to activate a brand-new native USDC market on Arbitrum, then became the first meaningful user of that reserve while it was still empty. They deposited USDC, repeatedly took flash loans from Radiant’s own pool so flash-loan fees accrued almost entirely to the one rUSDCn position that mattered, and drove the reserve’s
liquidityIndexto an absurd level. With the empty market now making a dust rUSDCn balance look enormously valuable, the attacker borrowed WETH from sibling markets and used Aave-v2-style precision loss in the burn path to withdraw far more USDC than the protocol should have allowed while burning only a handful of rUSDCn units per loop. Radiant’s own postmortem is unusually explicit that the attack was only viable when there were effectively no deposits besides the one used to mint1 rToken. That makes the lasting lesson sharper thanseed new markets better:someone deposited firstis not the same thing as an irreversible supply floor or a reserve that remains economically irrelevant until real supplier breadth exists. - Trigger / entry point:
- Radiant activated its new Arbitrum native USDC reserve in transaction
0x0e5330ad77b9b806cb9f6ea595d58552f341dbad0691e0599ab5f1caf214c247at rUSDCn0x3a2d44e354f2d88ef6da7a5a4646fd70182a7f55without any protective seed deposit. - The attacker deployed exploit contract
0x39519c027b503f40867548fb0c890b11728faa8fin transaction0x81a1414641bc823cd623208ba4c19a6cfc94f363050487bb122c15dceadc8937only seconds after market activation. - Because the market was still empty, nearly all early fee accrual and index growth could be concentrated into the attacker’s microscopic rUSDCn balance.
- Radiant activated its new Arbitrum native USDC reserve in transaction
- Root cause:
- Radiant left a newly listed Aave-v2-style reserve live and borrow-relevant while empty, with no irreversible seed floor and no enforced quarantine that would have kept the first depositor from monopolizing fee accrual.
- Its rebasing aToken model let flash-loan fees push the reserve
liquidityIndexsharply upward even though the market had no healthy base of outside depositors. - The burn path rounded in favor of the user when converting underlying withdrawals into scaled rToken burns, which became catastrophic once the inflated index made each wei of rUSDCn represent huge paper collateral.
- In short: an empty reserve, fee-driven index inflation, and attacker-favorable precision loss formed one exploit pipeline.
- Exploit path:
- The attacker watched governance execution for the new market and struck within seconds of reserve activation.
- Using the exploit contract, they sourced millions of USDC via external flash liquidity, including Aave.
- They deposited into the empty Radiant native USDC market so they controlled essentially all meaningful rUSDCn supply.
- They then repeatedly took flash loans from Radiant’s own lending pool. The flash-loan premium accrued to the reserve and therefore to the
liquidityIndex, but with almost no other rUSDCn holders present that fee growth was effectively credited to the attacker. - Public writeups show the index being pushed from the normal
1e27scale to roughly2.718e38, turning a few wei of rUSDCn into enormous notional collateral. - With that distorted collateral value, the attacker borrowed WETH from the broader pool in three exploit transactions:
0x1ce7e9a9e3b6dd3293c9067221ac3260858ce119ecb7ca860eac28b2474c7c9b,0x2af556386c023f7ebe7c662fd5d1c6cc5ed7fba4723cbd75e00faaa98cd14243, and0xc5c4bbddec70edb58efba60c1f27bce6515a45ffcab4236026a5eeb3e877fc6d. - The cash-out step used precision loss in the burn math: after depositing carefully chosen USDC amounts that minted only a handful of rUSDCn units, the attacker withdrew much larger USDC amounts while the protocol rounded the required burn down. One public reconstruction preserves the shape cleanly: deposit
543.600000002USDC, withdraw407.700000000USDC, and burn only15rUSDCn under the inflated index. - By repeating the deposit / withdraw loop under the inflated index, the attacker extracted USDC they had no right to and converted the fake collateral into about 1,900 WETH of bad debt for Radiant.
- What the attacker needed to be true:
- The reserve had to launch empty, with no seed deposit or non-burnable minimum liquidity to dilute the first depositor.
- Flash-loan fees had to accrue into the same reserve’s
liquidityIndexquickly enough to matter in one transaction. - Radiant had to accept the artificially inflated rUSDCn balance as valid collateral against liquid WETH liquidity elsewhere in the protocol.
- Burn math had to round scaled-balance reductions down in the user’s favor once the index became extreme.
- The attacker needed enough flash liquidity to ratchet the index high enough before the team could pause markets.
- Technical anatomy worth remembering:
- This was the Aave-v2 empty-market cousin of the Compound-fork empty-market share-price exploits. The printable accounting variable was
liquidityIndex, not a cToken exchange rate. - The attacker did not need an external oracle failure. Radiant’s own reserve-accounting machinery generated the fake solvency.
- Fresh-market timing was decisive. Radiant’s bug window existed because a new reserve went live before anyone seeded it or set safer temporary parameters.
- Radiant’s postmortem preserves the decisive denominator fact unusually clearly: the exploit only works when fee accrual is effectively being socialized over the one position used to mint
1 rToken, not over a real supplier base. - The exploit is a good reminder that flash-loan revenue is not always benign protocol income; in an empty rebasing market, it can become attacker-controlled collateral inflation.
- This was the Aave-v2 empty-market cousin of the Compound-fork empty-market share-price exploits. The printable accounting variable was
- Representative transactions and artifacts:
- Attacker EOA:
0x826d5f4d8084980366f975e10db6c4cf1f9dde6d - Attack contract:
0x39519c027b503f40867548fb0c890b11728faa8f - Reserve activation tx:
0x0e5330ad77b9b806cb9f6ea595d58552f341dbad0691e0599ab5f1caf214c247 - Exploit contract deployment tx:
0x81a1414641bc823cd623208ba4c19a6cfc94f363050487bb122c15dceadc8937 - Main exploit txs:
0x1ce7e9a9e3b6dd3293c9067221ac3260858ce119ecb7ca860eac28b2474c7c9b,0x2af556386c023f7ebe7c662fd5d1c6cc5ed7fba4723cbd75e00faaa98cd14243,0xc5c4bbddec70edb58efba60c1f27bce6515a45ffcab4236026a5eeb3e877fc6d - rUSDCn:
0x3a2d44e354f2d88ef6da7a5a4646fd70182a7f55 - Radiant lending pool:
0xf4b1486dd74d07706052a33d31d7c0aafd0659e1
- Attacker EOA:
- Response / mitigation:
- Radiant paused Arbitrum lending markets after the exploit and later kept the native USDC market frozen pending a
liquidityIndexreset and further review. - The protocol’s postmortem says new markets now require a small initial deposit before going live and can launch with collateral factor
0until hardening is complete. - That remediation is useful as an operational baseline, but the stronger lifecycle lesson is that a reversible seed is not enough by itself: either the floor has to survive runtime reality, or the reserve has to remain economically irrelevant until real supply breadth exists.
- Radiant also framed the incident as a fork-maintenance failure: the exploit path was a known empty-market risk in Aave-style forks, not a genuinely novel primitive.
- Radiant paused Arbitrum lending markets after the exploit and later kept the native USDC market frozen pending a
Three reserve-authority promotions this incident collapsed
-
A newly listed reserve was still allowed to remain attacker-owned denominator state
- Radiant’s own postmortem makes the decisive setup unusually explicit: the exploit is only possible when there are no deposits besides the one used to mint
1 rToken. - That means the dangerous fact was not merely
native USDC market exists. It was that a just-listed reserve had crossed into live deployment while its next unit of fee income still belonged economically to one dust supplier.
- Radiant’s own postmortem makes the decisive setup unusually explicit: the exploit is only possible when there are no deposits besides the one used to mint
-
That attacker-shaped denominator was still promoted into canonical supplier-side solvency truth
- Same-reserve flash-loan fees then raised
liquidityIndex, and the reserve’s rebasing math treated that index jump as ordinary supplier value even though the supplier set was effectively one attacker-owned unit. - Radiant therefore promoted
fresh reserve with one meaningful rTokeninto canonical collateral truth rather than treating the abnormalliquidityIndexgrowth as launch-state accounting that was still too immature to underwrite anything outside the reserve.
- Same-reserve flash-loan fees then raised
-
That published supplier-side truth still deserved immediate reserve-spending authority elsewhere
- The inflated
scaledBalance * liquidityIndexoutput was accepted quickly enough to borrow real WETH from sibling markets. - The later under-burn mattered because the protocol had already crossed the decisive boundary: a fresh reserve whose collateral meaning was still attacker-authored retained live cross-market borrowing and withdrawal authority instead of staying locally observable but economically quarantined.
- The inflated
The durable lesson is that the market is live, the reserve has published a supplier-side value, and that value deserves immediate cross-market borrowing power are three separate promotions. Radiant failed all three in the same launch window.
Pattern tags
- supplier-index-inflation
- fresh-market-initialization-failure
- The preserved shape is sharper than generic
new reserve got exploited: Radiant let one address own essentially the whole meaningful supplier set of a just-activated market, let flash-loan premiums compound intoliquidityIndexover that microscopic denominator, and then let the printed supplier-side mark become immediate WETH borrow power. - This was also a clean
small first deposit != durable opening-state hardeningfailure. The postmortem’s own mitigation language is directionally right, but the incident only closes once the floor is irreversible or the reserve remains economically quarantined until real supplier breadth exists.
Why the exploit worked
- Radiant crossed the dangerous line from
new market existstonew market can define cross-market solvencywithout first creating either a non-burnable supply floor or a quarantine that made first-supplier economics harmless. That meant the attacker did not need to discover a hidden edge case; they only needed to arrive before any honest deposit base existed. - In that empty-state regime, flash-loan fees stopped behaving like ordinary protocol revenue and became attacker-directed supplier-index inflation. The postmortem states the exploit was only viable when there were effectively no deposits besides the one used to mint
1 rToken, which is the clearest statement of the real invariant break: one residual wei of supplier state still controlled the meaning of the next unit of fee accrual. - The burn path then completed the exploit pipeline. Once
liquidityIndexhad been pushed to an absurd level, the same accounting that had printed collateral value also made tiny rounding errors economically enormous, letting the attacker withdraw more USDC than the protocol should have allowed while burning only1or2wei of rUSDCn. - Downstream borrowing treated the resulting
scaledBalance * liquidityIndexoutput as ordinary collateral truth. There was no second distrust boundary where a fresh reserve, a reserve with one meaningful supplier, or a reserve showing impossibleliquidityIndexgrowth had to stay locally observable but still economically irrelevant to sibling WETH liquidity. - The preserved lesson is therefore broader than
seed new markets better: launch-state hardening, fee-socialization rules, burn rounding, and collateral admission all belonged to one security object, and Radiant split them apart.
Detection and audit pivots
- Ask the launch-state question explicitly: what onchain fact proves a newly listed reserve has passed out of its dangerous opening state, and what keeps that fact true if the first deposit is withdrawn later? If the answer is only
someone deposited first, the floor is still reversible. - Reconstruct the whole supplier-value pipeline, not only
liquidityIndex: seed liquidity,scaledTotalSupply, flash-loan premium routing, burn math, collateral factor, and sibling-market borrow caps should all tell one coherent story before the reserve can matter system-wide. - Simulate the exact empty-state regime the postmortem itself describes: one meaningful supplier, effectively no other deposits besides the one used to mint
1 rToken, repeated flash loans, fee accrual concentrated into that supplier, and withdrawals under extreme index values. If the reserve becomes exploitable only when everyone else leaves, the test harness still needs to cover that state. - Treat production-impossible growth as a control signal. A reserve whose
liquidityIndexjumps orders of magnitude inside one exploit window, or whose supplier-side mark grows far faster than any real borrower demand could justify, should trip automated quarantine rather than merely analytics dashboards. - Check the two lifecycle states Radiant itself ended up admitting were dangerous: brand-new reserves and naturally emptied reserves. If the same math can revive after users withdraw down to dust, launch hardening alone is not enough.
- Check for a downstream distrust boundary. Can a fresh reserve stay observable while collateral factor remains
0, correlated borrows stay disabled, flash loans stay off, or per-market debt caps stay too small for one accounting lie to drain sibling WETH liquidity?
Failure-prevention checklist
- Do not let a newly listed reserve become borrow-relevant until a non-burnable seed floor or another irreversible denominator guard is already in place onchain.
Someone deposited firstis not a control if that opening state can be unwound. - Treat flash-loan fee routing as solvency code in empty markets. If fee accrual can move
liquidityIndexwhile one actor owns essentially allscaledTotalSupply, quarantine the reserve or redirect / cap that value until supplier breadth exists. - Separate local reserve initialization from cross-market collateral authority. Fresh reserves should default to collateral factor
0, tight debt caps, or another downstream quarantine until healthy supplier breadth and ordinary index behavior are observed. - Put explicit growth sanity checks around supplier-side accounting. A reserve whose
liquidityIndexjumps faster than any plausible borrower demand should freeze, de-collateralize, or disable the accrual path rather than continue publishing borrowable truth. - Make burn math safe at pathological index values and minimal-unit asset granularities. If the economically correct burn is just under
2minimum rToken units, the protocol still needs to consume enough state that the withdrawal cannot mint value. - Re-run launch-state protections when a reserve drifts back toward dust supply. A market that later becomes effectively empty again should lose the same authorities a fresh reserve lacks.
- Fuzz the full exploit pipeline, not just isolated functions: reserve launch, first-supplier concentration, repeated fee accrual, collateral publication, sibling-market borrowing, and under-burned withdrawals should be tested as one joined cash-out path.
- Keep blast-radius controls underneath the market anyway: per-reserve debt caps, fast pauses, flash-loan toggles, and correlated-borrow restrictions should stop one empty reserve from turning fake USDC solvency into protocol-wide WETH bad debt.
Audit prompts
- What exact onchain fact proves this reserve is out of its dangerous opening state, and what preserves that fact if the first supplier later redeems back toward dust?
- Can one actor still own essentially all
scaledTotalSupplywhile flash-loan premiums, reserve fees, or other accrual paths continue to raiseliquidityIndex? - Which paths let a fresh or low-breadth reserve publish collateral truth to the rest of the system: direct collateral factor, eMode-style correlations, liquidation thresholds, borrow caps, or cross-asset debt ceilings?
- At extreme
liquidityIndexvalues, how many rToken units should a withdrawal burn economically, and where does floor rounding let the protocol destroy less supplier state than the withdrawal consumes? - Can the same reserve both print the manipulated supplier mark and provide the flash-loan flow that amplifies it, or is there any enforced separation between fee generation and supplier-value publication?
- What automated signal would catch this before sibling markets are drained: one meaningful supplier, abnormal index growth, impossible APY, reserve cash changes with tiny supply, or extreme collateral-value jumps from a dust balance?
- If the reserve later becomes dormant or nearly empty again, does it automatically fall back into the same quarantine a fresh reserve should start in, or is age still being treated as a substitute for live breadth?
Lessons that should already be standard
- The first depositor is not seed liquidity. If that position can redeem away, the protocol has not created a durable security boundary; it has only assigned opening-state authorship to whoever arrived first.
- Flash-loan fees are not harmless protocol income in an empty rebasing reserve. They are supplier-side solvency inputs, and in dust-supply states they become attacker-controlled collateral printers.
- Fresh-market hardening is not complete when the reserve is merely listed. It is complete when the reserve cannot turn one microscopic supplier position into cross-market borrow power.
- Burn rounding is treasury policy once supplier units get tiny and index values get huge. Calling it a precision issue hides that the protocol is deciding how much real value a dust balance may withdraw.
- Launch-state bugs and accounting bugs are often the same bug in lending forks. The unsafe part is not just one arithmetic branch; it is the decision to let a reversible opening state publish borrow truth.
- Empty-market failures are systemic because cross-market lending monetizes local accounting lies. A tiny reserve should not get to define WETH borrow power for the rest of the book without extra distrust boundaries.
Why this incident matters
- Radiant broadens the empty-market corpus beyond Compound-v2 forks. It shows the same empty-state and rounding logic reappearing in Aave-v2-style rebasing reserves, with
liquidityIndexreplacing exchange-rate math as the attack surface. - The incident is also a clean example of launch sequencing as security model: even correct-looking parameters can be fatal if a reserve is collateral-eligible before it has either an irreversible floor or a real quarantine from cross-market solvency.
- It preserves a reusable lesson for lending forks: flash-loan fee accrual, rebasing accounting, and empty-market launch windows can combine into a solvency exploit every bit as dangerous as direct donation attacks.
- It is also a good reminder that
small initial depositis only a partial remedy. The healthier design question is whether the opening state can still be unwound back into attacker-ownable dust supply before the reserve earns protocol-wide borrow authority.
Internal linkages
- Closest recurring pattern: supplier-index-inflation.
- Broader empty-market family: empty-market-exchange-rate-inflation.
- Launch-window subpattern: fresh-market-initialization-failure.
- Positive-design companion: fresh-market-seeding-and-activation-discipline — the sharper upstream follow-up is why a new reserve needs either an irreversible floor or a still-binding quarantine before first-supplier accounting can matter system-wide.
- Positive-design companion: bootstrap-state-irreversibility-and-supply-floor-design — the sharper lifecycle question is why
someone deposited firststill was not a durable security object once that opening state could be unwound back into attacker-ownable dust. - Positive-design companion: collateral-admission-lag-and-borrow-side-quarantine — the downstream follow-up is why a brand-new native USDC reserve was allowed to publish borrowable collateral truth before any protected seed deposit or empty-reserve sanity window existed.
- Adjacent pattern: solvency-check-bypass.
Control surface
-
The decisive leverage sat in reserve initialization, first-depositor concentration, flash-loan-fee accounting inside
liquidityIndex, burn rounding, and collateral admission for a fresh reserve. -
Radiant did not fail because flash loans exist. It failed because an empty market was allowed to transform fee accrual into protocol-wide borrow power.
-
Sources:
- https://medium.com/@RadiantCapital/post-mortem-report-radiant-capital-aea46cb985ae
- https://rekt.news/radiant-capital-rekt
- https://blog.verichains.io/p/radiant-lending-pool-hack-analysis
- https://metatrust.io/blogs/post/radiant-protocol-on-arbitrum-suffers-flashloan-attack-resulting-in-45m-loss-indepth-analysis-reveals-exploit-details
- https://mixbytes.io/blog/aave-and-compound-forking-empty-pool-attacks
- https://arbiscan.io/tx/0x0e5330ad77b9b806cb9f6ea595d58552f341dbad0691e0599ab5f1caf214c247
- https://arbiscan.io/tx/0x81a1414641bc823cd623208ba4c19a6cfc94f363050487bb122c15dceadc8937
- https://arbiscan.io/tx/0x1ce7e9a9e3b6dd3293c9067221ac3260858ce119ecb7ca860eac28b2474c7c9b
- https://arbiscan.io/tx/0x2af556386c023f7ebe7c662fd5d1c6cc5ed7fba4723cbd75e00faaa98cd14243
- https://arbiscan.io/tx/0xc5c4bbddec70edb58efba60c1f27bce6515a45ffcab4236026a5eeb3e877fc6d
-
Last reviewed: 2026-08-02 UTC