diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 2e101bb50..7bee5edfe 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -289,6 +289,7 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional require(_value.compareTo(userBalance) <= 0, TAG + ": Insufficient balance"); Address quoteToken = poolQuote.get(_id.intValue()); + require(!baseToken.equals(quoteToken), TAG + ": Invalid same-token pool, removal blocked"); DictDB
totalTokensInPool = poolTotal.at(_id.intValue()); BigInteger totalBase = totalTokensInPool.get(baseToken); BigInteger totalQuote = totalTokensInPool.get(quoteToken); @@ -350,7 +351,7 @@ public void addInternal(NetworkAddress _from, Address _baseToken, Address _quote // If none is found (return 0), we create a new pool. Integer id = poolId.at(_baseToken).getOrDefault(_quoteToken, 0); - require(_baseToken != _quoteToken, TAG + ": Pool must contain two token contracts"); + require(!_baseToken.equals(_quoteToken), TAG + ": Pool must contain two token contracts"); // Check base/quote balances are valid require(_baseValue.compareTo(BigInteger.ZERO) > 0, TAG + ": Cannot send 0 or negative base token"); diff --git a/recovery/README.md b/recovery/README.md new file mode 100644 index 000000000..34ef182d0 --- /dev/null +++ b/recovery/README.md @@ -0,0 +1,39 @@ +# Incident recovery — governance execute batch + +`governance-execute.json` is a Governance `execute(transactions)` batch (ArbitraryCallManager +format: `[{address, method, parameters:[{type,value}], value}]`) that contains the protocol +while the DEX same-token fix in this PR is deployed. It targets contracts owned by Balanced +Governance (`cx44250a…`), so the calls pass their `onlyOwner`/`onlyGovernance` checks. All 58 +actions are admin/config setters and run fine while the protocol is under global shutdown. + +## What it does (58 actions) + +- **Block cross-chain transfers** — `setSpokeLimit(net, 0)` on **bnUSD** (12 chains) and **BALN** + (10 chains). `HubTokenImpl.crossTransfer` has no `checkStatus`, so bridging works even during + the shutdown; zeroing the spoke limits is what actually stops it. (`removeChain` only edits the + `connectedChains` list, not `spokeContracts`/`spokeLimits`, so it does **not** block bridging.) +- **Loans lockdown** — `setRedemptionExemption(token, true)` ×18 disables redemption for every + collateral, which neutralizes the `redeemCollateral` decimals bug **config-side (no Loans + redeploy)**; `setDebtCeiling(symbol, 0)` ×18 blocks new borrows. `repay` / `withdraw` / + `liquidate` remain available (verified decimals-safe in the deployed v1.3.0). + +## Sequence + +1. Execute this batch (works under the current global shutdown). +2. Deploy the DEX **v1.1.9** upgrade (this PR). +3. `enable()` on Governance to lift the shutdown — migration + repayment resume; redeem, borrow, + and bridging stay blocked by the settings above. + +## Not covered here — owned by OMM, not Balanced Governance + +- **sICX cross-chain block** (`setSpokeLimit(net, 0)` on sICX) and the **Staking exchange-rate + fix** (it divides by native `totalSupply` instead of `xTotalSupply`, so bridged sICX inflates + the rate). sICX and the staking manager are owned by a separate account — these must be done by + OMM. + +## Notes + +- **Redemption stays disabled** until a corrected Loans is shipped (fix `redeemCollateral` to use + `10^tokenDecimals` instead of hardcoded `EXA`, matching `_liquidate`/`removeCollateral`). The + exemptions are load-bearing — **do not clear them before that fix**, or the decimals bug + re-arms (10^(18−d)× over-payout on sub-18-decimal collateral such as SUI/SOL/XLM). diff --git a/recovery/governance-execute.json b/recovery/governance-execute.json new file mode 100644 index 000000000..b98550bf9 --- /dev/null +++ b/recovery/governance-execute.json @@ -0,0 +1,872 @@ +[ + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "archway-1" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x100.icon" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x38.bsc" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa86a.avax" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "injective-1" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa4b1.arbitrum" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x2105.base" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa.optimism" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x89.polygon" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "sui" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "stellar" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "solana" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa86a.avax" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x2105.base" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa.optimism" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0xa4b1.arbitrum" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x38.bsc" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "stellar" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "solana" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "sui" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "injective-1" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cxf61cd5a45dc9f91c15aa65831a30a90d59a09619", + "method": "setSpokeLimit", + "parameters": [ + { + "type": "String", + "value": "0x89.polygon" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx27fa4bdb0522e3be5a51daab06eb39889fb4c8da" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx66a031cc3bd305c76371fb586e93801b948254f0" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx2d552c485ec8bcaa75aac02424e2aca6ffdb2f1b" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx07b184a37f03c6ab681fcbd0b45aec6dc3eafbeb" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx5b5a03cb525a1845d0af3a872d525b18a810acb0" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx288d13e1b63563459a2ac6179f237711f6851cb5" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx0664cceb34d391ba78a897200fab94b9b49443d0" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx4297f4b63262507623b6ad575d0d8dd2db980e4e" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx4b48a4789636aa737285feec8908c765d8bc8042" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx65c9e3d4fea842e00add0d32a5b4c5e4e04c7a6b" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx508002ec116fbf3ab406329c0df28e70d7e75fb3" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cxb9d0727849a6ce6453f8c9dda2dec2fd543075d4" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx518f64edcd35db9044a2de63fdc10abfd5f7d611" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cxb8cf9a4700e0c804b780978bf9d9de759c62e787" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx2609b924e33ef00b648a409245c7ea394c467824" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cx15ddac8c2663bd7e71ca1688dffa426070752fbd" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cxce7b23917ddf57656010decd6017fe5016de681b" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setRedemptionExemption", + "parameters": [ + { + "type": "Address", + "value": "cxb940dbfbc45c92f3a0cde464c4331102e7a84da8" + }, + { + "type": "boolean", + "value": true + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "AFSUI" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "AVAX" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "BNB" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "BTC" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "BTCB" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "ETH" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "HASUI" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "INJ" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "JITOSOL" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "SOL" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "SUI" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "VSUI" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "XLM" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "mSUI" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "sICX" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "tBTC" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "weETH" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + }, + { + "address": "cx66d4d90f5f113eba575bf793570135f9b10cece1", + "method": "setDebtCeiling", + "parameters": [ + { + "type": "String", + "value": "wstETH" + }, + { + "type": "int", + "value": "0x0" + } + ], + "value": "0x0" + } +] \ No newline at end of file diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index 14de8c230..0274c351b 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -30,7 +30,7 @@ public class Versions { public final static String STABILITY = "v1.1.1"; public final static String BALANCEDORACLE = "v1.2.0"; public final static String DAOFUND = "v1.1.4"; - public final static String DEX = "v1.1.8"; + public final static String DEX = "v1.1.9"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; public final static String ROUTER = "v1.2.4";