feat(thorchain): mainnet Migrate19to20 store migration
Summary
Fills the mainnet Migrate19to20 store migration (consensus version 19 → 20). It
runs four independent steps, each inside its own cache context so a state drift in
one step logs and skips only that step and never applies it partially — the
other three still run.
- Bond slash reversal. Credit
0.53258717 BTCback to the BTC pool, debit the corresponding56,773.63556220 RUNE, move that RUNE Asgard → Reserve, then refund113,547.27112439 RUNEto the 218 affected bond providers (20 nodes). Pre-flight checks the Reserve covers the total; the per-address amounts are pinned inmigration_data.goand sum-checked in a test. - Low-synth-pool retirement. Reclaim to the module and burn the entire synth supply of seven
pools whose synth share is under ~1% (
BSC.USDC,BSC.USDT,ETH.LUSD,ETH.USDP,ETH.WBTC,ETH.XRUNE,ETH.YFI); the pools' synth units are cleared so freed backing accrues to their LPs. Nothing is paid to holders. All seven have zero savers depth. - LP donations + treasury repayment (carried from the base commits): donate the
BSC.USDC/BSC.USDT/BASE.ETHSecured Ops LP positions and repay the treasury247,622.29462483 RUNEfor their value at h28,076,056 (bound to the donations, 1000 bps tolerance). - ETH.THOR pool restore. Donate the Secured Ops
ETH.THORLP; credit the unaccounted Asgard-held surplus (3,959,373.5995 THOR) into the pool paired with Reserve RUNE at the pinned reference THOR/USD price; cap the one later LP entrant to the asset it contributed (so the donated + surplus value accrues to the earlier LPs); and repay the treasury the position's163,344.81856806 RUNEcapital. The surplus credit is solvency-guarded (it excludes asset backing trade and secured accounts, and skips if the live state has drifted), and the RUNE pairing is bounded by a ±30% sanity band on the liveDollarsPerRune.
Ships guarded
mainnetDonationSpecComplete is false, so Migrate19to20 logs and SKIPS
(returns nil, applies nothing) as this MR stands — the guard test covers both
states. The module version still advances to 20, so a release shipped with the
flag still false would drop the migration permanently (it would then need a new
20->21 migration). The amounts above are pinned from a state snapshot; they must
be re-pinned at the release cut and the flag flipped to true then.
Pinned decisions
- Low-synth burn = RETIRE (not compensate). The entire in-scope synth supply of the 7 low-utilization pools is reclaimed and burned, uncompensated; the amount is bounded (live utilization ≤1% AND a per-pool pinned supply ceiling), currently ~$7.9k, mostly ETH.WBTC synth. Pools that drift beyond either bound are skipped for a re-pin.
- ETH.THOR restore price band = 10% (WIDE). The live pre-credit pool THOR/USD
price is bounded ±10% of the pinned reference (two-sided); wider than the 1%
capital tripwires so a normal THOR move between the re-pin and the upgrade does
not skip the whole restore.
ethThorPinnedUsdTormust be re-pinned to market at the cut, not left at the snapshot price. - Surplus guard = canonical
calculateNetworkSolvency. The ETH.THOR surplus credit and the donation pairings are bounded by the live network-solvency amount (nets pool, trade/secured, queued/streaming swaps, deficits, scheduled outbounds). It refuses to run mid-churn, so the upgrade height must be scheduled off a churn boundary or the ETH.THOR restore soft-skips. - Slash reversal is solvency-gated too. The 0.53 BTC credited back into the BTC pool is now held to the same unaccounted-BTC check as every other credit: if the active vaults don't hold that BTC free (or mid-churn), the slash refund soft-skips — the 218 RUNE refunds only pay when the reversed BTC is actually there.
- Launch plan: set
HaltSigningTRON,HaltSigningZEC(step 5) andHaltSigningSOL(step 7) at a height ≤ the upgrade height. Steps 5/6/7 enforce the signing halt at run time, not merely document it: if the halt is unset when the upgrade block executes, the step soft-skips and its refund is dropped permanently (a 20→21 migration). The halt needn't run for weeks — it can be voted in shortly before the cut and lifted after the upgrade block.HALTSIGNINGTRONis currently0on mainnet (h28,226,576), so this belongs on the release checklist.
Tests
-tags mainnet: slash-refund sum, ETH.THOR happy-path / insolvency-reject / post-entrant
cap, and low-synth burn all pass. Default and mocknet builds are green. The migration
steps add zero new failures to the full -tags mainnet package run (the 30 failures
there are pre-existing on develop — the package's normal test tag is mocknet).