Acala iBTC/aUSD Deprecated DexSaving Reward-Rate Misconfiguration / Recursive Unbacked aUSD Mint (2022-08-14)
- Name: Acala iBTC/aUSD deprecated
DexSavingreward-rate misconfiguration / recursive unbacked aUSD mint - Date: 2022-08-14
- Protocol: Acala
- Chain: Acala (Polkadot parachain)
- Category: parameter misconfiguration / deprecated reward path abuse / unbacked stablecoin issuance / recursive liquidity-loop amplifier
- Loss:
3.022B aUSDerroneously minted; Acala later said about2.97Bwas recovered or identified onchain, while public reporting put the value that escaped before shutdown in the low millions to roughly$10M - Summary: On 2022-08-14, Acala’s newly launched iBTC/aUSD LP incentive program accidentally activated a deprecated
DexSavingrewards path that could mint unbacked aUSD from the Honzon / CDP treasury. The intended iBTC/aUSD LP rewards wereINTRandACA, but the liveincentivespallet still containedaccumulate_dex_saving(), which computed aUSD rewards asDexSavingRewardRates[pool] * stable-side liquidityfor any DEX LP containing Acala’s stable currency. Because the new pool was an aUSD pair, the misconfigured rate turned ordinaryclaim_rewardscalls by iBTC/aUSD LPs into direct aUSD issuance. Some LPs then added the error-minted aUSD back into the iBTC/aUSD pool and claimed again, so the pool’s own growing aUSD side became the base for the next round of unbacked issuance. - Trigger / entry point:
- Acala launched an iBTC/aUSD pool on Acala Swap and publicly intended to reward LPs with
INTRandACA. - The entry point was not a custom attacker contract or an exotic runtime exploit; it was the normal LP rewards path in the
incentivespallet. - LP contributors who had staked iBTC/aUSD LP shares called
incentives.claim_rewards, expecting ordinary liquidity-mining payouts. - Instead, because
DexSavingRewardRateshad been misconfigured for the pool and the oldDexSavingpath was still live, those claims paid out large amounts of freshly issued aUSD.
- Acala launched an iBTC/aUSD pool on Acala Swap and publicly intended to reward LPs with
- Root cause:
- Acala’s
incentivespallet still exposed a deprecatedDexSavingmechanism that was originally meant to distribute stablecoin rewards to certain aUSD-related DEX pools. - In the vulnerable code,
accumulate_dex_saving(lp_currency_id, pool_id)split the LP token into its two underlying assets, checked whether either side equaledStableCurrencyId, then setdex_saving_reward_baseto the pool’s current stable-side reserve. - It then computed
dex_saving_reward_amount = DexSavingRewardRates[pool_id] * dex_saving_reward_baseand calledCDPTreasury::issue_debit(..., false)to issue that stable currency to the incentives vault without fresh backing. - The runtime accumulated these rewards automatically in
on_initializeeveryAccumulatePeriod; on Acala, that period wasMINUTES, i.e. one minute at 12-second blocks. - The code did contain a generic rate bound
rate <= 1, but that only limited the damage per accumulation period to at most the pool’s full aUSD side. It did not stop explosive growth once error-minted aUSD itself was repeatedly re-added as liquidity. - Acala’s own incident report says the parameter should have remained
0and that the code should have prevented the misconfiguration from taking effect at all. The eventual fix was simply to removeaccumulate_dex_saving,update_dex_saving_rewards, and theDexSavingRewardRatesstorage entirely.
- Acala’s
- Exploit path:
- Acala launched the iBTC/aUSD pool and configured intended LP incentives in
INTRandACA, but a deprecated aUSD-saving reward parameter was also left nonzero for that LP pool. - Because the LP token was an aUSD pair,
accumulate_dex_saving()treated the pool as eligible for stable-side saving rewards and began issuing unbacked aUSD into the incentives vault on each accumulation period. - iBTC/aUSD LP contributors called
incentives.claim_rewardsand received these aUSD error mints as if they were legitimate pool rewards. - Some recipients swapped the newly minted aUSD into
DOT,IBTC,INTR, and other assets through Acala Swap, immediately damaging aUSD pair ratios across the DEX. - Some LPs also added the error-minted aUSD back into the same iBTC/aUSD pool, obtained more LP exposure, and claimed again, so the pool’s expanding aUSD reserve mechanically increased the base for later
DexSavingreward issuance. - Other traders then bought or routed the distorted aUSD inventory at dislocated prices, and some of the resulting assets were transferred to Moonbeam, Interlay, Astar, Polkadot, and centralized exchanges before emergency governance pauses fully stopped outflow.
- Acala launched the iBTC/aUSD pool and configured intended LP incentives in
- What the attacker needed to be true:
- The iBTC/aUSD LP pool had to be live and have staked LP shares eligible for
incentives.claim_rewards. DexSavingRewardRatesfor thatPoolId::Dex(...)entry had to be nonzero.- The LP token had to contain Acala’s stable currency, so the deprecated
DexSavingbranch would treat the pool’s aUSD side as the reward base. - The chain had to remain operational long enough for at least one
on_initializeaccumulation and one or more reward claims / swaps before governance paused the relevant pallets and transfers. - No parameter safeguard or pallet-level isolation could block the misconfigured reward path before it started issuing aUSD.
- The iBTC/aUSD LP pool had to be live and have staked LP shares eligible for
- Technical anatomy worth remembering:
- This was not a smart-contract exploit in the usual
overflow,reentrancy, orforged proofsense. The dangerous primitive was an operator-controlled onchain parameter wired into still-live deprecated code with mint authority. - The misconfigured path did not merely over-distribute prefunded rewards. It used
issue_debit(..., false)to create new aUSD without backing, so the reward system itself became a stablecoin mint surface. - The recursive amplifier mattered. Once error-minted aUSD was re-added to the iBTC/aUSD pool, the pool’s own stable-side balance became the base for the next reward accumulation. The payout rail and the growth rail were the same object.
- Acala’s response is analytically useful because it did not try to salvage the deprecated feature with tighter settings. The protocol removed the whole
DexSavingbranch, which is a strong sign that the real problem was letting old reward logic keep live mint authority at all.
- This was not a smart-contract exploit in the usual
- Representative modules, functions, and trace anchors:
- Vulnerable incentives code (historical Acala source):
modules/incentives/src/lib.rs, especiallyupdate_dex_saving_rewards(...)andaccumulate_dex_saving(...) - Runtime accumulation cadence:
runtime/acala/src/lib.rsandruntime/acala/src/constants.rs, whereAccumulatePeriod = MINUTESandSECS_PER_BLOCK = 12 - User-facing payout call:
incentives.claim_rewards - Removal / fix: Acala PR
#2341(Remove dex savings) - Acala trace counts from the incident report:
3.022B aUSDtotal error mints2.96Btraced to the original 16 LP contributor addresses12.38M aUSDtraced to the top 35 significant recipient / linked addresses- remaining
52.068Mtraced in the full report
- Vulnerable incentives code (historical Acala source):
- Response / mitigation:
- Acala rapidly passed urgent governance votes to reset the bad parameter, pause the incentives pallet, halt the DEX, pause Honzon, restrict non-ACA transfers and XCM outflows, and freeze other sensitive surfaces while tracing funds.
- The community later burned large amounts of recovered aUSD and pursued return / bounty processes for funds that had already moved to other chains or venues.
- The permanent code fix was to remove the deprecated
DexSavinglogic and clearDexSavingRewardRatesin a runtime upgrade. - Acala’s published roadmap after the incident emphasized parameter-safeguard mechanisms, pallet isolation, and better monitoring, which is exactly where the real control failure sat.
Pattern tags
- Core recurring pattern: deprecation-without-deauthorization.
- The preserved shape is sharper than generic
misconfiguration: a deprecated rewards rail still held stablecoin mint authority, and one operator-set parameter let ordinary LP claims spend that authority. - This is also a balance-sheet publication incident. The protocol’s own incentives machinery was allowed to publish fresh aUSD into circulation and that publication was immediately honored by Acala Swap, XCM exits, and downstream recipients.
- The recursive amplifier matters enough to remember separately: the same aUSD that the deprecated rail printed could be re-added to the iBTC/aUSD pool, which then raised the stable-side reserve used to calculate later
DexSavingissuance.
Why the exploit worked
- Acala did not merely leave dead code around. It left a deprecated
accumulate_dex_saving()branch live inside the block-initialization rewards path, still able to callCDPTreasury::issue_debit(..., false)and therefore still able to author fresh aUSD. - The bad parameter did more than overpay a rewards budget. Because the reward base was the pool’s current stable-side reserve, the mis-set
DexSavingRewardRatesvalue turned normal iBTC/aUSD LP participation into direct stablecoin issuance. - The incident report makes the recursive loop explicit: some LPs claimed error-minted aUSD, added it back into the same pool, and then claimed again. That meant pool balance, reward base, and newly issued asset were one joined object rather than separate surfaces.
- Acala’s emergency response also reveals the real security boundary. The team did not just tweak one number; it reset the parameter, paused the incentives pallet, paused the DEX and Honzon, restricted transfers and XCM outflows, and later removed the whole
DexSavingfeature. That is strong evidence that the dangerous object was a live mint rail, not a cosmetic rewards misconfiguration. - In other words, the protocol had already socially decided the feature was legacy, but the runtime had not actually deauthorized it. The exploit path existed because
deprecatedandunable to mint balance-sheet assetswere still different states.
Detection and audit pivots
- Trace the full authority chain from operator-set reward parameters to balance-sheet issuance:
parameter write -> deprecated accumulator -> treasury issuance -> claimable rewards -> swap / exit path. If that chain ends in money-good assets or bridgeable value, it is not a harmless incentives setting. - Ask whether deprecated code can still publish new assets, new debt, or new collateral-recognition state even when product owners believe the feature is retired. If yes, decommissioning has not actually happened.
- Review any reward formula that depends on live pool balances or other attacker-recyclable state. If the reward asset can be reintroduced into the same base used for later reward computation, recursive self-amplification is already part of the threat model.
- Inspect
on_initializeand other automated accumulation hooks with the same skepticism usually reserved for user-callable functions. A time-based background path with mint authority is still an externally monetizable entrypoint once users can claim or route the resulting balances. - Separate
rate boundedfromsafe. Acala’srate <= 1ceiling only limited one period’s issuance relative to the current pool balance; it did not stop the current pool balance itself from being recursively inflated by prior error mints. - Re-audit every path that can turn protocol-authored accounting objects into immediately transferable or swappable assets. Once Acala Swap and XCM exits honored the printed aUSD, the incentives bug had already become a systemwide solvency event.
Failure-prevention checklist
- Extinguish deprecated rails, do not merely mark them unused. If a legacy reward path can still mint, issue debt, or publish collateral truth, remove it or hard-disable it before new programs go live.
- Put hard semantic bounds on risk parameters, not just numeric bounds. A setting that can redirect a rewards path into stablecoin issuance should default to impossible unless a narrowly scoped governance action explicitly enables it.
- Treat block-initialization reward accumulation as a minting surface. Subject
on_initializeissuance paths to the same threat modeling, caps, and blast-radius controls as user-triggered mint functions. - Require recursive-amplification review whenever rewards depend on live balances. If the emitted asset can be re-added to the state that defines the next reward base, the formula needs explicit anti-recursion safeguards or hard issuance caps.
- Keep new reward programs separated from legacy mint authority until rollout review proves the two cannot interact.
Legacy feature present but set to zerois not an adequate safety claim. - Add automatic invariant checks for
unexpected supply growth from incentivesand forreward asset equals stable-side reserve asset. Those conditions should page operators before users can run repeated claim / swap / re-liquify loops. - Predefine degraded-mode responses for balance-sheet publication mistakes: pause claiming, pause swap venues, constrain bridge / XCM exits, and freeze only the surfaces that let newly printed claims escape into stronger assets.
- Prefer pallet-level and feature-level authority isolation. A liquidity-mining pallet should not quietly inherit the power to mint system-stable liabilities unless that power is deliberate, visible, and tightly bounded.
- Audit retirement and migration plans explicitly. The review question should be
what authority still survives here?, not justdoes anyone intend to use this feature?. - Test
claim -> re-add liquidity -> claim againloops in simulation whenever reward math touches live reserves, LP balances, or treasury-issued assets.
Audit prompts
- Which deprecated or little-used modules can still mint, issue debt, publish collateral value, or otherwise write balance-sheet truth?
- What exact parameter writes can redirect a rewards path into stablecoin issuance, and why are those writes even available in production?
- If a reward asset is paid from a live reserve-dependent formula, can that same asset be recycled into the reserve that sets the next reward amount?
- Does the protocol distinguish
legacy code still compiledfromlegacy code still authorized, or are those currently the same state? - What monitoring would detect
incentives growthbecomingunexpected base-asset supply growthwithin one accumulation period? - If a malformed reward payout begins today, what is the first bounded-loss control: claim pause, DEX pause, bridge pause, transfer restriction, issuance cap, or none?
- Which automated hooks run without a user transaction but still create assets users can later claim or route out of the system?
- Are numeric parameter bounds validating the real economic invariant, or only preventing one-step extremes while leaving recursive amplification untouched?
- When a feature is called
deprecated, where is the proof that its authority is extinguished rather than merely socially ignored? - If the newly issued asset were swapped out immediately into stronger assets, what mechanism would stop the error from becoming permanent bad collateral / reserve loss?
Lessons that should already be standard
- Deprecated code is still live financial infrastructure if configuration can still route mint authority through it.
- A rewards system that can issue balance-sheet assets is part of the solvency core, even if operators think of it as an auxiliary incentives feature.
- Recursive balance-dependent rewards are dangerous whenever the paid asset can flow back into the balance that sets the next payout.
Rate cap existsis not a meaningful defense if the denominator or reward base can be attacker-amplified between periods.- Offchain operational intent does not matter once the runtime still honors the old authority path.
We meant to pay INTR and ACAdid not constrain what the live pallet could actually mint. - Emergency pauses across swaps, issuance paths, and exits are not overreactions when a protocol has accidentally published unbacked stablecoin claims; they are evidence that the whole claim-recognition chain shares one security boundary.
- The right decommissioning question is not
is this feature deprecated?butwhat money-moving authority still survives if a parameter is wrong tomorrow?.
Why this incident matters
- Acala is a useful reminder that deprecated code is still production code if it retains mint authority and can still be reached by configuration.
- The incident also preserves a specific recursive failure shape: reward issuance depended on live pool balance, and the newly issued reward asset could itself be recycled into that same pool to increase the next issuance round.
- It is also a clean decommissioning failure: the real missing control was not
monitor parameters better, butprove the deprecated reward rail no longer had authority to issue balance-sheet assets before operators treated it as legacy. - For the exploit corpus, this is a cleaner example than many generic
misconfigurationstories because the exact control path is legible:parameter -> deprecated reward accumulator -> unbacked stable issuance -> claim_rewards -> DEX swaps / recursive re-liquidity.
Internal linkages
- Lifecycle control frame: deprecation-without-deauthorization — the decisive mistake was not just
bad parameter; it was letting a deprecated reward branch keep stablecoin mint authority at all. - Positive-design decommissioning companion: decommissioning-authority-extinguishment-discipline — the healthier retirement boundary was to extinguish or quarantine the old
DexSavingmint rail before the new LP program went live, not merely to socially regard it as deprecated. - Positive-design operations companion: operator-experimentation-separation-from-live-balance-sheet-authority — the more reusable production lesson is that a deprecated parameter rail was still able to publish live reward and mint authority on the main balance sheet.
- Closest reserve-drain frame: issuance-redemption-solvency-asymmetry — the immediate payout rail was not a formal redeem function, but the system still let one side print unbacked aUSD while other DEX pools and exit routes honored that claim against real liquidity.
- Launch-state amplifier: fresh-market-initialization-failure — the misconfigured path became especially dangerous because it was attached to a freshly launched LP program before operators or market depth could absorb the mistake.
- Operational cousin: LP overmint (2024-01-04) — both incidents show that offchain configuration and operator-set parameters are part of the live security boundary when they decide what the protocol may mint or accept as safe.
Control surface
-
The decisive leverage sat in
DexSavingRewardRates, the still-live deprecatedaccumulate_dex_saving()branch, the CDP treasury’s ability to issue aUSD from that branch without new backing, the one-minute accumulation cadence, and the DEX path that let freshly minted aUSD both exit into stronger assets and re-enter the same pool as new reward base. -
The deeper lifecycle control surface was the retirement boundary between
legacy reward code still presentandlegacy reward code still authorized to mint. Acala failed on the second half. -
Acala did not fail because LP rewards are inherently unsafe. It failed because a deprecated reward mechanism retained stablecoin mint authority and a mis-set parameter could still aim that authority at a fresh pool whose own balance then amplified the next issuance step.
-
Sources:
- https://medium.com/acalanetwork/acala-incident-report-14-08-2022-392089588642
- https://www.coindesk.com/tech/2022/08/22/inside-the-3b-defi-exploit-of-acalas-crypto-platform/
- https://github.com/AcalaNetwork/Acala/pull/2341
- https://github.com/AcalaNetwork/Acala/blob/68d7cfcbe4be01c25c76431617580b3262f086fc/modules/incentives/src/lib.rs
- https://github.com/AcalaNetwork/Acala/blob/68d7cfcbe4be01c25c76431617580b3262f086fc/runtime/acala/src/lib.rs
- https://github.com/AcalaNetwork/Acala/blob/68d7cfcbe4be01c25c76431617580b3262f086fc/runtime/acala/src/constants.rs
-
Last reviewed: 2026-07-21 UTC