From 0ce9f2741dcb1f4779f27dff4d5ee6d3422d6e58 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Tue, 16 Jun 2026 19:29:59 +0530 Subject: [PATCH 1/8] feat(vip-664): add Phase-4 market deprecation Part 1 RF to 100%, push-out IRM repoint, and cap/CF gap closures for BNB Core, BNB BTC/DeFi/GameFi/Meme isolated pools, opBNB, Optimism, Unichain and Ethereum Core. Includes the shared market dataset + command generator and reusable pre/post simulation checks. 53 governor ops. --- simulations/vip-664/bscmainnet.ts | 18 + simulations/vip-664/ethereum.ts | 16 + simulations/vip-664/opbnbmainnet.ts | 16 + simulations/vip-664/opmainnet.ts | 16 + simulations/vip-664/unichainmainnet.ts | 16 + simulations/vip-664/utils/checkPhase4.ts | 160 +++++++++ vips/vip-664/bscmainnet.ts | 67 ++++ vips/vip-664/phase4Markets.ts | 401 +++++++++++++++++++++++ 8 files changed, 710 insertions(+) create mode 100644 simulations/vip-664/bscmainnet.ts create mode 100644 simulations/vip-664/ethereum.ts create mode 100644 simulations/vip-664/opbnbmainnet.ts create mode 100644 simulations/vip-664/opmainnet.ts create mode 100644 simulations/vip-664/unichainmainnet.ts create mode 100644 simulations/vip-664/utils/checkPhase4.ts create mode 100644 vips/vip-664/bscmainnet.ts create mode 100644 vips/vip-664/phase4Markets.ts diff --git a/simulations/vip-664/bscmainnet.ts b/simulations/vip-664/bscmainnet.ts new file mode 100644 index 000000000..9d9f476d2 --- /dev/null +++ b/simulations/vip-664/bscmainnet.ts @@ -0,0 +1,18 @@ +import { forking, testVip } from "src/vip-framework"; + +import vip664 from "../../vips/vip-664/bscmainnet"; +import { BNB_BTC, BNB_CORE, BNB_DEFI, BNB_GAMEFI, BNB_MEME } from "../../vips/vip-664/phase4Markets"; +import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; + +// BSC mainnet block (after the BNB push-out IRMs were deployed). +const FORK_BLOCK = 104562598; + +const BNB_POOLS = [BNB_CORE, BNB_BTC, BNB_DEFI, BNB_GAMEFI, BNB_MEME]; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip(BNB_POOLS); + + testVip("VIP-664 Market Deprecation Phase 4 (Part 1) — BNB Chain", await vip664()); + + checkPhase4PostVip(BNB_POOLS); +}); diff --git a/simulations/vip-664/ethereum.ts b/simulations/vip-664/ethereum.ts new file mode 100644 index 000000000..5d57b4aed --- /dev/null +++ b/simulations/vip-664/ethereum.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip664 from "../../vips/vip-664/bscmainnet"; +import { ETH_CORE } from "../../vips/vip-664/phase4Markets"; +import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; + +// Ethereum mainnet block (after the Ethereum push-out IRM was deployed). +const FORK_BLOCK = 25329944; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([ETH_CORE]); + + testForkedNetworkVipCommands("VIP-664 Ethereum Core", await vip664()); + + checkPhase4PostVip([ETH_CORE]); +}); diff --git a/simulations/vip-664/opbnbmainnet.ts b/simulations/vip-664/opbnbmainnet.ts new file mode 100644 index 000000000..7b76f68a7 --- /dev/null +++ b/simulations/vip-664/opbnbmainnet.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip664 from "../../vips/vip-664/bscmainnet"; +import { OPBNB } from "../../vips/vip-664/phase4Markets"; +import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; + +// opBNB mainnet block (after the opBNB push-out IRM was deployed). +const FORK_BLOCK = 153977309; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([OPBNB]); + + testForkedNetworkVipCommands("VIP-664 opBNB", await vip664()); + + checkPhase4PostVip([OPBNB]); +}); diff --git a/simulations/vip-664/opmainnet.ts b/simulations/vip-664/opmainnet.ts new file mode 100644 index 000000000..b19cb54c0 --- /dev/null +++ b/simulations/vip-664/opmainnet.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip664 from "../../vips/vip-664/bscmainnet"; +import { OPTIMISM } from "../../vips/vip-664/phase4Markets"; +import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; + +// Optimism mainnet block (after the Optimism push-out IRM was deployed). +const FORK_BLOCK = 153006241; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([OPTIMISM]); + + testForkedNetworkVipCommands("VIP-664 Optimism", await vip664()); + + checkPhase4PostVip([OPTIMISM]); +}); diff --git a/simulations/vip-664/unichainmainnet.ts b/simulations/vip-664/unichainmainnet.ts new file mode 100644 index 000000000..8ae67a7a3 --- /dev/null +++ b/simulations/vip-664/unichainmainnet.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip664 from "../../vips/vip-664/bscmainnet"; +import { UNICHAIN } from "../../vips/vip-664/phase4Markets"; +import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; + +// Unichain mainnet block (after the Unichain push-out IRM was deployed). +const FORK_BLOCK = 50862900; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([UNICHAIN]); + + testForkedNetworkVipCommands("VIP-664 Unichain", await vip664()); + + checkPhase4PostVip([UNICHAIN]); +}); diff --git a/simulations/vip-664/utils/checkPhase4.ts b/simulations/vip-664/utils/checkPhase4.ts new file mode 100644 index 000000000..8c3c43f42 --- /dev/null +++ b/simulations/vip-664/utils/checkPhase4.ts @@ -0,0 +1,160 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers } from "hardhat"; + +import { PUSHOUT_IRM, PoolDef, RF_FULL } from "../../../vips/vip-664/phase4Markets"; + +// Documented pre-VIP collateral factor on the two BNB Liquid Staked ETH markets (5%). +const CF_GAP = parseUnits("0.05", 18); + +const VTOKEN_ABI = [ + "function reserveFactorMantissa() view returns (uint256)", + "function interestRateModel() view returns (address)", +]; + +const COMPTROLLER_ABI = [ + "function supplyCaps(address) view returns (uint256)", + "function borrowCaps(address) view returns (uint256)", + "function markets(address) view returns (bool isListed, uint256 collateralFactorMantissa, uint256 liquidationThresholdMantissa)", +]; + +// Asserts the pre-VIP state for the given pools, proving the VIP is not a no-op. +// Every assertion mirrors exactly one action emitted by generatePoolCommands, and a +// test is only registered when that action touches at least one market in the pool — +// so no check asserts state for a market the VIP does not modify, and an empty filter +// never shows up as a vacuously-passing test: +// - reserve factor below 100% on markets being raised (skips already-100% markets) +// - interest rate model not yet the push-out IRM (skips PLANET / stkBNB) +// - leftover supply / borrow cap gaps still open (> 0) +// - the two collateral-factor gaps still read 5% +export const checkPhase4PreVip = (pools: PoolDef[]) => { + const provider = ethers.provider; + + describe("Pre-VIP behavior", () => { + for (const pool of pools) { + describe(pool.label, () => { + const comptroller = new Contract(pool.comptroller, COMPTROLLER_ABI, provider); + const rfMarkets = pool.markets.filter(m => !m.rfAlready100); + const irmMarkets = pool.markets.filter(m => !m.skipIrm); + const supplyGap = pool.markets.filter(m => m.supplyCapGap); + const borrowGap = pool.markets.filter(m => m.borrowCapGap); + const cfGap = pool.markets.filter(m => m.cfGapLiqThreshold !== undefined); + + if (rfMarkets.length > 0) { + it("reserve factor below 100% on markets being raised", async () => { + for (const m of rfMarkets) { + const vToken = new Contract(m.vToken, VTOKEN_ABI, provider); + expect((await vToken.reserveFactorMantissa()).lt(RF_FULL), m.symbol).to.be.true; + } + }); + } + + if (irmMarkets.length > 0) { + it("interest rate model is not yet the push-out IRM", async () => { + const pushout = PUSHOUT_IRM[pool.irmKey].toLowerCase(); + for (const m of irmMarkets) { + const vToken = new Contract(m.vToken, VTOKEN_ABI, provider); + expect((await vToken.interestRateModel()).toLowerCase(), m.symbol).to.not.equal(pushout); + } + }); + } + + if (supplyGap.length > 0) { + it("outstanding supply caps still open (> 0)", async () => { + for (const m of supplyGap) { + expect((await comptroller.supplyCaps(m.vToken)).gt(0), m.symbol).to.be.true; + } + }); + } + + if (borrowGap.length > 0) { + it("outstanding borrow caps still open (> 0)", async () => { + for (const m of borrowGap) { + expect((await comptroller.borrowCaps(m.vToken)).gt(0), m.symbol).to.be.true; + } + }); + } + + if (cfGap.length > 0) { + it("collateral-factor gaps still read 5% (liquidation threshold matches)", async () => { + for (const m of cfGap) { + const data = await comptroller.markets(m.vToken); + expect(data.collateralFactorMantissa.toString(), m.symbol).to.equal(CF_GAP.toString()); + expect(data.liquidationThresholdMantissa.toString(), m.symbol).to.equal(m.cfGapLiqThreshold); + } + }); + } + }); + } + }); +}; + +// Asserts the Phase-4 end state for the given pools. Every assertion mirrors exactly +// one action emitted by generatePoolCommands and is only registered when that action +// touches at least one market in the pool: +// - reserve factor raised to 100% (skips already-100% markets) +// - interest rate model repointed to the push-out IRM (skips PLANET / stkBNB) +// - leftover supply / borrow cap gaps closed to 0 +// - collateral-factor gaps closed to 0 with the liquidation threshold preserved +export const checkPhase4PostVip = (pools: PoolDef[]) => { + const provider = ethers.provider; + + describe("Post-VIP behavior", () => { + for (const pool of pools) { + describe(pool.label, () => { + const comptroller = new Contract(pool.comptroller, COMPTROLLER_ABI, provider); + const rfMarkets = pool.markets.filter(m => !m.rfAlready100); + const irmMarkets = pool.markets.filter(m => !m.skipIrm); + const supplyGap = pool.markets.filter(m => m.supplyCapGap); + const borrowGap = pool.markets.filter(m => m.borrowCapGap); + const cfGap = pool.markets.filter(m => m.cfGapLiqThreshold !== undefined); + + if (rfMarkets.length > 0) { + it("reserve factor raised to 100%", async () => { + for (const m of rfMarkets) { + const vToken = new Contract(m.vToken, VTOKEN_ABI, provider); + expect((await vToken.reserveFactorMantissa()).toString(), m.symbol).to.equal(RF_FULL.toString()); + } + }); + } + + if (irmMarkets.length > 0) { + it("interest rate model repointed to the push-out IRM", async () => { + const expected = PUSHOUT_IRM[pool.irmKey].toLowerCase(); + for (const m of irmMarkets) { + const vToken = new Contract(m.vToken, VTOKEN_ABI, provider); + expect((await vToken.interestRateModel()).toLowerCase(), m.symbol).to.equal(expected); + } + }); + } + + if (supplyGap.length > 0) { + it("outstanding supply caps closed to 0", async () => { + for (const m of supplyGap) { + expect((await comptroller.supplyCaps(m.vToken)).toString(), m.symbol).to.equal("0"); + } + }); + } + + if (borrowGap.length > 0) { + it("outstanding borrow caps closed to 0", async () => { + for (const m of borrowGap) { + expect((await comptroller.borrowCaps(m.vToken)).toString(), m.symbol).to.equal("0"); + } + }); + } + + if (cfGap.length > 0) { + it("outstanding collateral factors closed to 0 (liquidation threshold preserved)", async () => { + for (const m of cfGap) { + const data = await comptroller.markets(m.vToken); + expect(data.collateralFactorMantissa.toString(), m.symbol).to.equal("0"); + expect(data.liquidationThresholdMantissa.toString(), m.symbol).to.equal(m.cfGapLiqThreshold); + } + }); + } + }); + } + }); +}; diff --git a/vips/vip-664/bscmainnet.ts b/vips/vip-664/bscmainnet.ts new file mode 100644 index 000000000..a52b14615 --- /dev/null +++ b/vips/vip-664/bscmainnet.ts @@ -0,0 +1,67 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { + BNB_BTC, + BNB_CORE, + BNB_DEFI, + BNB_GAMEFI, + BNB_MEME, + ETH_CORE, + OPBNB, + OPTIMISM, + UNICHAIN, + generatePoolCommands, +} from "./phase4Markets"; + +const meta = { + version: "v2", + title: "VIP-664 Market Deprecation Phase 4 (Part 1 of 2)", + description: `#### Summary + +This proposal is the first of two VIPs implementing Phase 4 of the market deprecation outlined in the Venus community forum ([Deprecate Venus Core on opBNB / Optimism / Unichain + Isolated Pools](https://community.venus.io/t/deprecate-venus-core-on-opbnb-optimism-unichain-isolated-pools/5760) and [May 2026 Risk Parameter Update & Asset Off-boarding](https://community.venus.io/t/may-2026-risk-parameter-update-asset-off-boarding/5785)). + +The work is split across two VIPs to respect the governor's 100-operation limit and the LayerZero 10 KB per-message cap. Part 1 covers the BNB Core pool, the BNB BTC / DeFi / GameFi / Meme isolated pools, and the opBNB, Optimism, Unichain and Ethereum Core deployments. + +#### Description + +For each deprecated market this VIP: + +1. Sets the reserve factor to 100% (markets already at 100% are skipped). +2. Repoints the interest rate model to the chain's push-out deprecation curve (base 300% / slope1 0% / jump 363.64% / kink 0.45 — flat 300% below the kink, ramping to a 500% maximum at full utilization). PLANET and stkBNB are excluded (~$0 borrows, IRM moot). +3. Closes the leftover Phase-1 gaps by setting outstanding supply / borrow caps to 0. + +Liquidation thresholds are unchanged; no action reduces collateral factors of healthy positions in this part. + +#### Security and additional considerations + +- **VIP execution simulation**: validated in a fork environment that each market ends with the 100% reserve factor, the push-out IRM, and zeroed caps. +- **Cross-chain payload size**: each LayerZero message is verified below the 10 KB Relayer cap at build time.`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", +}; + +export const vip664 = () => + makeProposal( + [ + // ── BNB Core (legacy) ── + ...generatePoolCommands(BNB_CORE), + + // ── BNB isolated pools ── + ...generatePoolCommands(BNB_BTC), + ...generatePoolCommands(BNB_DEFI), + ...generatePoolCommands(BNB_GAMEFI), + ...generatePoolCommands(BNB_MEME), + + // ── Remote chains ── + ...generatePoolCommands(OPBNB), + ...generatePoolCommands(OPTIMISM), + ...generatePoolCommands(UNICHAIN), + ...generatePoolCommands(ETH_CORE), + ], + meta, + ProposalType.REGULAR, + ); + +export default vip664; diff --git a/vips/vip-664/phase4Markets.ts b/vips/vip-664/phase4Markets.ts new file mode 100644 index 000000000..6e434676c --- /dev/null +++ b/vips/vip-664/phase4Markets.ts @@ -0,0 +1,401 @@ +import { parseUnits } from "ethers/lib/utils"; +import { LzChainId } from "src/types"; + +// ───────────────────────────────────────────────────────────────────────────── +// Phase-4 market deprecation: RF → 100%, repoint to the per-chain push-out IRM, +// and close leftover Phase-1 cap / CF gaps. 87 markets across 8 chains. +// +// Source of truth for the per-market data below is the Phase-4 parameter table +// (community forum: deprecate-venus-core-on-opbnb-optimism-unichain-isolated-pools +// + may-2026-risk-parameter-update-asset-off-boarding). All values are on-chain +// reads dated 2026-06-16. +// ───────────────────────────────────────────────────────────────────────────── + +// 100% reserve factor. +export const RF_FULL = parseUnits("1", 18); + +// Liquidation threshold (unchanged) passed as the 3rd arg of setCollateralFactor +// when zeroing the collateral factor of the two BNB Liquid Staked ETH markets. +const LIQ_THRESHOLD_93 = parseUnits("0.93", 18); + +// ───────────────────────────────────────────────────────────────────────────── +// Push-out interest-rate models — one per chain (deprecation curve: +// base 300% / slope1 0% / jump 363.64% / kink 0.45). +// +// Isolated-pools JumpRateModelV2 deployments (incl. Ethereum, which covers +// ETH Core + Curve + LSEth): VenusProtocol/isolated-pools#555. +// BNB Core uses a dedicated legacy JumpRateModel (3-arg getBorrowRate ABI): +// VenusProtocol/venus-protocol#682. +// ───────────────────────────────────────────────────────────────────────────── +export const PUSHOUT_IRM = { + bscIsolated: "0x29d0f5503525df271880CB8Da84651405E545d6b", // JumpRateModelV2 (isolated-pools) + bscCore: "0xc255352947ef3594C45b0Fe8bcB690e51C3D744A", // legacy JumpRateModel (venus-protocol) + ethereum: "0xbEd8AAf2Ce423428ECeabfbdCdA92D961B7BE901", // covers ETH Core + Curve + LSEth + opbnb: "0xDA141Df6D89B83Db101F13C24174C2a3B6308962", + optimism: "0x00a7e1641077Bd0e70A87cA9b631523E1D4B7A91", + unichain: "0xf67b35d5201E48960D1262b043A815B3cb8AfAb7", + arbitrum: "0x2f58C87418d0F0E87922B4e915E1e968cE79B6F5", + base: "0xDd22bBbCC37d59483b7D42b040d435E1A0ee0E22", + zksync: "0x1f6e343B528B1374d1370E0F9dE99290AD3a22A9", +} as const; + +type IrmKey = keyof typeof PUSHOUT_IRM; + +export interface Mkt { + symbol: string; + vToken: string; + // true when RF is already 100% on-chain (RF command is a no-op and is skipped). + rfAlready100?: boolean; + // true for markets where the IRM repoint is omitted (PLANET, stkBNB — ~$0 borrows). + skipIrm?: boolean; + // leftover Phase-1 gaps to close → 0. + supplyCapGap?: boolean; + borrowCapGap?: boolean; + // CF gap → 0, preserving the existing liquidation threshold. + cfGapLiqThreshold?: string; +} + +export interface PoolDef { + label: string; + comptroller: string; + irmKey: IrmKey; + // BNB Core (legacy Unitroller / VBep20) uses the underscore-prefixed setters. + legacy?: boolean; + // omitted for BNB-local pools; set for remote chains routed via LayerZero. + dstChainId?: LzChainId; + markets: Mkt[]; +} + +// ───────────────────────────────────────────────────────────────────────────── +// BNB-local isolated pools (normal setter signatures) +// ───────────────────────────────────────────────────────────────────────────── + +export const BNB_BTC: PoolDef = { + label: "BNB BTC pool", + comptroller: "0x9DF11376Cf28867E2B0741348044780FbB7cb1d6", + irmKey: "bscIsolated", + markets: [ + { symbol: "BTCB", vToken: "0x8F2AE20b25c327714248C95dFD3b02815cC82302", supplyCapGap: true, borrowCapGap: true }, + ], +}; + +export const BNB_DEFI: PoolDef = { + label: "BNB DeFi pool", + comptroller: "0x3344417c9360b963ca93A4e8305361AEde340Ab9", + irmKey: "bscIsolated", + markets: [ + { symbol: "ALPACA", vToken: "0x02c5Fb0F26761093D297165e902e96D08576D344" }, + { symbol: "ANKR", vToken: "0x19CE11C8817a1828D1d357DFBF62dCf5b0B2A362" }, + { symbol: "ankrBNB", vToken: "0x53728FD51060a85ac41974C6C3Eb1DaE42776723" }, + { symbol: "BSW", vToken: "0x8f657dFD3a1354DEB4545765fE6840cc54AFd379" }, + { symbol: "PLANET", vToken: "0xFf1112ba7f88a53D4D23ED4e14A117A2aE17C6be", rfAlready100: true, skipIrm: true }, + { symbol: "TWT", vToken: "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F" }, + { symbol: "USDD", vToken: "0xA615467caE6B9E0bb98BC04B4411d9296fd1dFa0" }, + { symbol: "USDT", vToken: "0x1D8bBDE12B6b34140604E18e9f9c6e14deC16854" }, + ], +}; + +export const BNB_GAMEFI: PoolDef = { + label: "BNB GameFi pool", + comptroller: "0x1b43ea8622e76627B81665B1eCeBB4867566B963", + irmKey: "bscIsolated", + markets: [ + { symbol: "FLOKI", vToken: "0xc353B7a1E13dDba393B5E120D4169Da7185aA2cb" }, + { symbol: "RACA", vToken: "0xE5FE5527A5b76C75eedE77FdFA6B80D52444A465" }, + { symbol: "USDD", vToken: "0x9f2FD23bd0A5E08C5f2b9DD6CF9C96Bfb5fA515C" }, + { symbol: "USDT", vToken: "0x4978591f17670A846137d9d613e333C38dc68A37" }, + ], +}; + +export const BNB_LIQUID_STAKED_BNB: PoolDef = { + label: "BNB Liquid Staked BNB pool", + comptroller: "0xd933909A4a2b7A4638903028f44D1d38ce27c352", + irmKey: "bscIsolated", + markets: [ + { symbol: "ankrBNB", vToken: "0xBfe25459BA784e70E2D7a718Be99a1f3521cA17f" }, + { symbol: "asBNB", vToken: "0x4A50a0a1c832190362e1491D5bB464b1bc2Bd288" }, + { symbol: "BNBx", vToken: "0x5E21bF67a6af41c74C1773E4b473ca5ce8fd3791" }, + { symbol: "PT-clisBNB-24APR2025", vToken: "0xA537ACf381b12Bbb91C58398b66D1D220f1C77c8" }, + { symbol: "slisBNB", vToken: "0xd3CC9d8f3689B83c91b7B59cAB4946B063EB894A" }, + { symbol: "stkBNB", vToken: "0xcc5D9e502574cda17215E70bC0B4546663785227", rfAlready100: true, skipIrm: true }, + { symbol: "WBNB", vToken: "0xe10E80B7FD3a29fE46E16C30CC8F4dd938B742e2" }, + ], +}; + +export const BNB_LIQUID_STAKED_ETH: PoolDef = { + label: "BNB Liquid Staked ETH pool", + comptroller: "0xBE609449Eb4D76AD8545f957bBE04b596E8fC529", + irmKey: "bscIsolated", + markets: [ + { symbol: "ETH", vToken: "0xeCCACF760FEA7943C5b0285BD09F601505A29c05", supplyCapGap: true, borrowCapGap: true }, + { + symbol: "weETH", + vToken: "0xc5b24f347254bD8cF8988913d1fd0F795274900F", + supplyCapGap: true, + cfGapLiqThreshold: LIQ_THRESHOLD_93.toString(), + }, + { + symbol: "wstETH", + vToken: "0x94180a3948296530024Ef7d60f60B85cfe0422c8", + supplyCapGap: true, + cfGapLiqThreshold: LIQ_THRESHOLD_93.toString(), + }, + ], +}; + +export const BNB_MEME: PoolDef = { + label: "BNB Meme pool", + comptroller: "0x33B6fa34cd23e5aeeD1B112d5988B026b8A5567d", + irmKey: "bscIsolated", + markets: [ + { + symbol: "BabyDoge", + vToken: "0x52eD99Cd0a56d60451dD4314058854bc0845bbB5", + supplyCapGap: true, + borrowCapGap: true, + }, + { symbol: "USDT", vToken: "0x4a9613D06a241B76b81d3777FCe3DDd1F61D4Bd0", supplyCapGap: true, borrowCapGap: true }, + ], +}; + +export const BNB_STABLECOINS: PoolDef = { + label: "BNB Stablecoins pool", + comptroller: "0x94c1495cD4c557f1560Cbd68EAB0d197e6291571", + irmKey: "bscIsolated", + markets: [ + { symbol: "EURA", vToken: "0x795DE779Be00Ea46eA97a28BDD38d9ED570BCF0F", supplyCapGap: true, borrowCapGap: true }, + { symbol: "lisUSD", vToken: "0xCa2D81AA7C09A1a025De797600A7081146dceEd9", supplyCapGap: true, borrowCapGap: true }, + { symbol: "USDD", vToken: "0xc3a45ad8812189cAb659aD99E64B1376f6aCD035", supplyCapGap: true, borrowCapGap: true }, + { symbol: "USDT", vToken: "0x5e3072305F9caE1c7A82F6Fe9E38811c74922c3B", supplyCapGap: true, borrowCapGap: true }, + ], +}; + +export const BNB_TRON: PoolDef = { + label: "BNB Tron pool", + comptroller: "0x23b4404E4E5eC5FF5a6FFb70B7d14E3FabF237B0", + irmKey: "bscIsolated", + markets: [ + { symbol: "BTT", vToken: "0x49c26e12959345472E2Fd95E5f79F8381058d3Ee", supplyCapGap: true, borrowCapGap: true }, + { symbol: "TRX", vToken: "0x836beb2cB723C498136e1119248436A645845F4E", supplyCapGap: true, borrowCapGap: true }, + { symbol: "USDD", vToken: "0xf1da185CCe5BeD1BeBbb3007Ef738Ea4224025F7", supplyCapGap: true, borrowCapGap: true }, + { symbol: "USDT", vToken: "0x281E5378f99A4bc55b295ABc0A3E7eD32Deba059", supplyCapGap: true, borrowCapGap: true }, + { symbol: "WIN", vToken: "0xb114cfA615c828D88021a41bFc524B800E64a9D5", supplyCapGap: true, borrowCapGap: true }, + ], +}; + +// ───────────────────────────────────────────────────────────────────────────── +// BNB Core (legacy Unitroller — underscore-prefixed setters) +// ───────────────────────────────────────────────────────────────────────────── + +export const BNB_CORE: PoolDef = { + label: "BNB Core pool", + comptroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + irmKey: "bscCore", + legacy: true, + markets: [ + { symbol: "DOT", vToken: "0x1610bc33319e9398de5f57B33a5b184c806aD217", supplyCapGap: true, borrowCapGap: true }, + { symbol: "FIL", vToken: "0xf91d58b5aE142DAcC749f58A49FCBac340Cb0343" }, + { symbol: "TUSDOLD", vToken: "0x08CEB3F4a7ed3500cA0982bcd0FC7816688084c3", rfAlready100: true }, + { symbol: "THE", vToken: "0x86e06EAfa6A1eA631Eab51DE500E3D474933739f" }, + { symbol: "TUSD", vToken: "0xBf762cd5991cA1DCdDaC9ae5C638F5B5Dc3Bee6E" }, + { symbol: "BETH", vToken: "0x972207A639CC1B374B893cc33Fa251b55CEB7c07", rfAlready100: true, borrowCapGap: true }, + { symbol: "MATIC", vToken: "0x5c9476FcD6a4F9a3654139721c949c2233bBbBc8" }, + { symbol: "TRXOLD", vToken: "0x61eDcFe8Dd6bA3c891CB9bEc2dc7657B3B422E93", rfAlready100: true }, + { symbol: "BUSD", vToken: "0x95c78222B3D6e262426483D42CfA53685A67Ab9D", rfAlready100: true }, + { symbol: "SXP", vToken: "0x2fF3d0F6990a40261c66E1ff2017aCBc282EB6d0", rfAlready100: true }, + ], +}; + +// ───────────────────────────────────────────────────────────────────────────── +// Remote chains (routed via LayerZero / dstChainId) +// ───────────────────────────────────────────────────────────────────────────── + +export const OPBNB: PoolDef = { + label: "opBNB Core pool", + comptroller: "0xD6e3E2A1d8d95caE355D15b3b9f8E5c2511874dd", + irmKey: "opbnb", + dstChainId: LzChainId.opbnbmainnet, + markets: [ + { symbol: "BTCB", vToken: "0xED827b80Bd838192EA95002C01B5c6dA8354219a" }, + { symbol: "ETH", vToken: "0x509e81eF638D489936FA85BC58F52Df01190d26C" }, + { symbol: "FDUSD", vToken: "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917" }, + { symbol: "USDT", vToken: "0xb7a01Ba126830692238521a1aA7E7A7509410b8e" }, + { symbol: "WBNB", vToken: "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672" }, + ], +}; + +export const OPTIMISM: PoolDef = { + label: "Optimism Core pool", + comptroller: "0x5593FF68bE84C966821eEf5F0a988C285D5B7CeC", + irmKey: "optimism", + dstChainId: LzChainId.opmainnet, + markets: [ + { symbol: "OP", vToken: "0x6b846E3418455804C1920fA4CC7a31A51C659A2D" }, + { symbol: "USDC", vToken: "0x1C9406ee95B7af55F005996947b19F91B6D55b15" }, + { symbol: "USDT", vToken: "0x37ac9731B0B02df54975cd0c7240e0977a051721" }, + { symbol: "WBTC", vToken: "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46" }, + { symbol: "WETH", vToken: "0x66d5AE25731Ce99D46770745385e662C8e0B4025" }, + ], +}; + +export const UNICHAIN: PoolDef = { + label: "Unichain Core pool", + comptroller: "0xe22af1e6b78318e1Fe1053Edbd7209b8Fc62c4Fe", + irmKey: "unichain", + dstChainId: LzChainId.unichainmainnet, + markets: [ + { symbol: "UNI", vToken: "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2" }, + { symbol: "USDC", vToken: "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95" }, + { symbol: "USD₮0", vToken: "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD" }, + { symbol: "WBTC", vToken: "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5" }, + { symbol: "weETH", vToken: "0x0170398083eb0D0387709523baFCA6426146C218" }, + { symbol: "WETH", vToken: "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374" }, + { symbol: "wstETH", vToken: "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB" }, + ], +}; + +// Ethereum is split across the two VIPs to keep each LayerZero message < 10 KB: +// - ETH_CORE → VIP-664 +// - ETH_CURVE + ETH_LIQUID_STAKED_ETH → VIP-665 +export const ETH_CORE: PoolDef = { + label: "Ethereum Core pool", + comptroller: "0x687a01ecF6d3907658f7A7c714749fAC32336D1B", + irmKey: "ethereum", + dstChainId: LzChainId.ethereum, + markets: [ + { symbol: "TUSD", vToken: "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b" }, + { symbol: "FRAX", vToken: "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", supplyCapGap: true, borrowCapGap: true }, + { symbol: "sFRAX", vToken: "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe" }, + { symbol: "EIGEN", vToken: "0x256AdDBe0a387c98f487e44b85c29eb983413c5e" }, + { symbol: "BAL", vToken: "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8" }, + { symbol: "yvUSDC-1", vToken: "0xf87c0a64dc3a8622D6c63265FA29137788163879" }, + { symbol: "yvUSDT-1", vToken: "0x475d0C68a8CD275c15D1F01F4f291804E445F677" }, + { symbol: "yvUSDS-1", vToken: "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764" }, + { symbol: "yvWETH-1", vToken: "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0" }, + ], +}; + +export const ETH_CURVE: PoolDef = { + label: "Ethereum Curve pool", + comptroller: "0x67aA3eCc5831a65A5Ba7be76BED3B5dc7DB60796", + irmKey: "ethereum", + dstChainId: LzChainId.ethereum, + markets: [ + { symbol: "CRV", vToken: "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", supplyCapGap: true, borrowCapGap: true }, + { symbol: "crvUSD", vToken: "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", supplyCapGap: true, borrowCapGap: true }, + ], +}; + +export const ETH_LIQUID_STAKED_ETH: PoolDef = { + label: "Ethereum Liquid Staked ETH pool", + comptroller: "0xF522cd0360EF8c2FF48B648d53EA1717Ec0F3Ac3", + irmKey: "ethereum", + dstChainId: LzChainId.ethereum, + markets: [ + { symbol: "ezETH", vToken: "0xA854D35664c658280fFf27B6eDC6C4195c3229B3" }, + { symbol: "pufETH", vToken: "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e" }, + { symbol: "sfrxETH", vToken: "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E" }, + { symbol: "weETH", vToken: "0xb4933AF59868986316Ed37fa865C829Eba2df0C7" }, + { symbol: "weETHs", vToken: "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9" }, + { symbol: "WETH", vToken: "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2" }, + { symbol: "wstETH", vToken: "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB" }, + ], +}; + +export const ARBITRUM_LIQUID_STAKED_ETH: PoolDef = { + label: "Arbitrum Liquid Staked ETH pool", + comptroller: "0x52bAB1aF7Ff770551BD05b9FC2329a0Bf5E23F16", + irmKey: "arbitrum", + dstChainId: LzChainId.arbitrumone, + markets: [ + { symbol: "weETH", vToken: "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88" }, + { symbol: "WETH", vToken: "0x39D6d13Ea59548637104E40e729E4aABE27FE106" }, + { symbol: "wstETH", vToken: "0x9df6B5132135f14719696bBAe3C54BAb272fDb16" }, + ], +}; + +export const BASE_CORE: PoolDef = { + label: "Base Core pool", + comptroller: "0x0C7973F9598AA62f9e03B94E92C967fD5437426C", + irmKey: "base", + dstChainId: LzChainId.basemainnet, + markets: [{ symbol: "wsuperOETHb", vToken: "0x75201D81B3B0b9D17b179118837Be37f64fc4930" }], +}; + +export const ZKSYNC_CORE: PoolDef = { + label: "zkSync Era Core pool", + comptroller: "0xddE4D098D9995B659724ae6d5E3FB9681Ac941B1", + irmKey: "zksync", + dstChainId: LzChainId.zksyncmainnet, + markets: [ + { symbol: "ZK", vToken: "0x697a70779C1A03Ba2BD28b7627a902BFf831b616" }, + { symbol: "wUSDM", vToken: "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", rfAlready100: true }, + { symbol: "wstETH", vToken: "0x03CAd66259f7F34EE075f8B62D133563D249eDa4" }, + { symbol: "zkETH", vToken: "0xCEb7Da150d16aCE58F090754feF2775C23C8b631" }, + ], +}; + +// ───────────────────────────────────────────────────────────────────────────── +// Command generator +// ───────────────────────────────────────────────────────────────────────────── + +const sig = (pool: PoolDef) => ({ + reserveFactor: pool.legacy ? "_setReserveFactor(uint256)" : "setReserveFactor(uint256)", + interestRateModel: pool.legacy ? "_setInterestRateModel(address)" : "setInterestRateModel(address)", + supplyCaps: pool.legacy ? "_setMarketSupplyCaps(address[],uint256[])" : "setMarketSupplyCaps(address[],uint256[])", + borrowCaps: pool.legacy ? "_setMarketBorrowCaps(address[],uint256[])" : "setMarketBorrowCaps(address[],uint256[])", +}); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const generatePoolCommands = (pool: PoolDef): any[] => { + const { comptroller, irmKey, markets, dstChainId } = pool; + const chain = dstChainId !== undefined ? { dstChainId } : {}; + const s = sig(pool); + const irm = PUSHOUT_IRM[irmKey]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const commands: any[] = []; + + // RF → 100% on the vToken (skip markets already at 100%). + for (const m of markets.filter(m => !m.rfAlready100)) { + commands.push({ target: m.vToken, signature: s.reserveFactor, params: [RF_FULL], ...chain }); + } + + // Repoint the IRM on the vToken (skip PLANET / stkBNB). + for (const m of markets.filter(m => !m.skipIrm)) { + commands.push({ target: m.vToken, signature: s.interestRateModel, params: [irm], ...chain }); + } + + // Close supply-cap gaps → 0, batched per pool. + const supplyGap = markets.filter(m => m.supplyCapGap); + if (supplyGap.length > 0) { + commands.push({ + target: comptroller, + signature: s.supplyCaps, + params: [supplyGap.map(m => m.vToken), supplyGap.map(() => 0)], + ...chain, + }); + } + + // Close borrow-cap gaps → 0, batched per pool. + const borrowGap = markets.filter(m => m.borrowCapGap); + if (borrowGap.length > 0) { + commands.push({ + target: comptroller, + signature: s.borrowCaps, + params: [borrowGap.map(m => m.vToken), borrowGap.map(() => 0)], + ...chain, + }); + } + + // Close CF gaps → 0 (preserving the liquidation threshold). Isolated pools only. + for (const m of markets.filter(m => m.cfGapLiqThreshold !== undefined)) { + commands.push({ + target: comptroller, + signature: "setCollateralFactor(address,uint256,uint256)", + params: [m.vToken, 0, m.cfGapLiqThreshold], + ...chain, + }); + } + + return commands; +}; From 54a67a3da807fb94dec3ce8233fb84b15e113b91 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Tue, 16 Jun 2026 19:30:41 +0530 Subject: [PATCH 2/8] feat(vip-665): add Phase-4 market deprecation Part 2 RF to 100%, push-out IRM repoint, cap closures, and the 2 collateral-factor gap closures for BNB LSBNB/LSEth/Stablecoins/Tron, Ethereum Curve+LSEth, Arbitrum, Base and zkSync. 48 governor ops. --- simulations/vip-665/arbitrumone.ts | 16 +++++++ simulations/vip-665/basemainnet.ts | 16 +++++++ simulations/vip-665/bscmainnet.ts | 23 ++++++++++ simulations/vip-665/ethereum.ts | 16 +++++++ simulations/vip-665/zksyncmainnet.ts | 16 +++++++ vips/vip-665/bscmainnet.ts | 63 ++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 simulations/vip-665/arbitrumone.ts create mode 100644 simulations/vip-665/basemainnet.ts create mode 100644 simulations/vip-665/bscmainnet.ts create mode 100644 simulations/vip-665/ethereum.ts create mode 100644 simulations/vip-665/zksyncmainnet.ts create mode 100644 vips/vip-665/bscmainnet.ts diff --git a/simulations/vip-665/arbitrumone.ts b/simulations/vip-665/arbitrumone.ts new file mode 100644 index 000000000..a61212887 --- /dev/null +++ b/simulations/vip-665/arbitrumone.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { ARBITRUM_LIQUID_STAKED_ETH } from "../../vips/vip-664/phase4Markets"; +import vip665 from "../../vips/vip-665/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; + +// Arbitrum One block (after the Arbitrum push-out IRM was deployed). +const FORK_BLOCK = 474085204; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([ARBITRUM_LIQUID_STAKED_ETH]); + + testForkedNetworkVipCommands("VIP-665 Arbitrum", await vip665()); + + checkPhase4PostVip([ARBITRUM_LIQUID_STAKED_ETH]); +}); diff --git a/simulations/vip-665/basemainnet.ts b/simulations/vip-665/basemainnet.ts new file mode 100644 index 000000000..bdef592ad --- /dev/null +++ b/simulations/vip-665/basemainnet.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { BASE_CORE } from "../../vips/vip-664/phase4Markets"; +import vip665 from "../../vips/vip-665/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; + +// Base mainnet block (after the Base push-out IRM was deployed). +const FORK_BLOCK = 47410957; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([BASE_CORE]); + + testForkedNetworkVipCommands("VIP-665 Base", await vip665()); + + checkPhase4PostVip([BASE_CORE]); +}); diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts new file mode 100644 index 000000000..635a115b8 --- /dev/null +++ b/simulations/vip-665/bscmainnet.ts @@ -0,0 +1,23 @@ +import { forking, testVip } from "src/vip-framework"; + +import { + BNB_LIQUID_STAKED_BNB, + BNB_LIQUID_STAKED_ETH, + BNB_STABLECOINS, + BNB_TRON, +} from "../../vips/vip-664/phase4Markets"; +import vip665 from "../../vips/vip-665/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; + +// BSC mainnet block (after the BNB push-out IRM was deployed). +const FORK_BLOCK = 104562598; + +const BNB_POOLS = [BNB_LIQUID_STAKED_BNB, BNB_LIQUID_STAKED_ETH, BNB_STABLECOINS, BNB_TRON]; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip(BNB_POOLS); + + testVip("VIP-665 Market Deprecation Phase 4 (Part 2) — BNB Chain", await vip665()); + + checkPhase4PostVip(BNB_POOLS); +}); diff --git a/simulations/vip-665/ethereum.ts b/simulations/vip-665/ethereum.ts new file mode 100644 index 000000000..9f815f99e --- /dev/null +++ b/simulations/vip-665/ethereum.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { ETH_CURVE, ETH_LIQUID_STAKED_ETH } from "../../vips/vip-664/phase4Markets"; +import vip665 from "../../vips/vip-665/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; + +// Ethereum mainnet block (after the Ethereum push-out IRM was deployed). +const FORK_BLOCK = 25329944; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([ETH_CURVE, ETH_LIQUID_STAKED_ETH]); + + testForkedNetworkVipCommands("VIP-665 Ethereum Curve + Liquid Staked ETH", await vip665()); + + checkPhase4PostVip([ETH_CURVE, ETH_LIQUID_STAKED_ETH]); +}); diff --git a/simulations/vip-665/zksyncmainnet.ts b/simulations/vip-665/zksyncmainnet.ts new file mode 100644 index 000000000..9719fc8d8 --- /dev/null +++ b/simulations/vip-665/zksyncmainnet.ts @@ -0,0 +1,16 @@ +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { ZKSYNC_CORE } from "../../vips/vip-664/phase4Markets"; +import vip665 from "../../vips/vip-665/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; + +// zkSync Era mainnet block (after the zkSync push-out IRM was deployed). +const FORK_BLOCK = 70814289; + +forking(FORK_BLOCK, async () => { + checkPhase4PreVip([ZKSYNC_CORE]); + + testForkedNetworkVipCommands("VIP-665 zkSync Era", await vip665()); + + checkPhase4PostVip([ZKSYNC_CORE]); +}); diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts new file mode 100644 index 000000000..aeb847742 --- /dev/null +++ b/vips/vip-665/bscmainnet.ts @@ -0,0 +1,63 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { + ARBITRUM_LIQUID_STAKED_ETH, + BASE_CORE, + BNB_LIQUID_STAKED_BNB, + BNB_LIQUID_STAKED_ETH, + BNB_STABLECOINS, + BNB_TRON, + ETH_CURVE, + ETH_LIQUID_STAKED_ETH, + ZKSYNC_CORE, + generatePoolCommands, +} from "../vip-664/phase4Markets"; + +const meta = { + version: "v2", + title: "VIP-665 Market Deprecation Phase 4 (Part 2 of 2)", + description: `#### Summary + +This proposal is the second of two VIPs implementing Phase 4 of the market deprecation outlined in the Venus community forum ([Deprecate Venus Core on opBNB / Optimism / Unichain + Isolated Pools](https://community.venus.io/t/deprecate-venus-core-on-opbnb-optimism-unichain-isolated-pools/5760) and [May 2026 Risk Parameter Update & Asset Off-boarding](https://community.venus.io/t/may-2026-risk-parameter-update-asset-off-boarding/5785)). + +The work is split across two VIPs to respect the governor's 100-operation limit and the LayerZero 10 KB per-message cap. Part 2 covers the BNB Liquid Staked BNB / Liquid Staked ETH / Stablecoins / Tron isolated pools, the Ethereum Curve and Ethereum Liquid Staked ETH pools, and the Arbitrum, Base and zkSync Era deployments. + +#### Description + +For each deprecated market this VIP: + +1. Sets the reserve factor to 100% (markets already at 100% are skipped). +2. Repoints the interest rate model to the chain's push-out deprecation curve (base 300% / slope1 0% / jump 363.64% / kink 0.45 — flat 300% below the kink, ramping to a 500% maximum at full utilization). +3. Closes the leftover Phase-1 gaps by setting outstanding supply / borrow caps to 0, and sets the collateral factor to 0 for the two BNB Liquid Staked ETH markets (weETH, wstETH) that still carry a 5% collateral factor. Liquidation thresholds are unchanged, so no healthy position is liquidated. + +#### Security and additional considerations + +- **VIP execution simulation**: validated in a fork environment that each market ends with the 100% reserve factor, the push-out IRM, zeroed caps, and (for the two flagged markets) a 0% collateral factor. +- **Cross-chain payload size**: each LayerZero message is verified below the 10 KB Relayer cap at build time.`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", +}; + +export const vip665 = () => + makeProposal( + [ + // ── BNB isolated pools ── + ...generatePoolCommands(BNB_LIQUID_STAKED_BNB), + ...generatePoolCommands(BNB_LIQUID_STAKED_ETH), + ...generatePoolCommands(BNB_STABLECOINS), + ...generatePoolCommands(BNB_TRON), + + // ── Remote chains (Ethereum Curve + Liquid Staked ETH merge into one LZ message) ── + ...generatePoolCommands(ETH_CURVE), + ...generatePoolCommands(ETH_LIQUID_STAKED_ETH), + ...generatePoolCommands(ARBITRUM_LIQUID_STAKED_ETH), + ...generatePoolCommands(BASE_CORE), + ...generatePoolCommands(ZKSYNC_CORE), + ], + meta, + ProposalType.REGULAR, + ); + +export default vip665; From 2cd7188c24a5403ea1d8d8dfa9cf2cd09986e7aa Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 17 Jun 2026 15:39:17 +0530 Subject: [PATCH 3/8] feat(vip-664): repoint PLANET/stkBNB IRM, zero DOT e-mode CF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skipIrm carve-out on PLANET/stkBNB was based on the doc's USD value, but PLANET has 6.45M tokens borrowed at ~4%; remove it so every deprecated market lands on the push-out curve uniformly (stkBNB included for consistency). Add the DOT BNB Core e-mode collateral factor (pool 14) to the gap closure — 55% to 0, liquidation threshold preserved — verified the only such e-mode gap. Simulation checks extended to assert the e-mode CF pre/post state. --- simulations/vip-664/utils/checkPhase4.ts | 27 ++++++++++++++++++++++ vips/vip-664/phase4Markets.ts | 29 ++++++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/simulations/vip-664/utils/checkPhase4.ts b/simulations/vip-664/utils/checkPhase4.ts index 8c3c43f42..b97a87210 100644 --- a/simulations/vip-664/utils/checkPhase4.ts +++ b/simulations/vip-664/utils/checkPhase4.ts @@ -17,6 +17,7 @@ const COMPTROLLER_ABI = [ "function supplyCaps(address) view returns (uint256)", "function borrowCaps(address) view returns (uint256)", "function markets(address) view returns (bool isListed, uint256 collateralFactorMantissa, uint256 liquidationThresholdMantissa)", + "function poolMarkets(uint96, address) view returns (bool isListed, uint256 collateralFactorMantissa, uint256 unused, uint256 liquidationThresholdMantissa, bool isBorrowAllowed)", ]; // Asserts the pre-VIP state for the given pools, proving the VIP is not a no-op. @@ -40,6 +41,7 @@ export const checkPhase4PreVip = (pools: PoolDef[]) => { const supplyGap = pool.markets.filter(m => m.supplyCapGap); const borrowGap = pool.markets.filter(m => m.borrowCapGap); const cfGap = pool.markets.filter(m => m.cfGapLiqThreshold !== undefined); + const emodeCfGap = pool.markets.filter(m => m.emodeCfGap !== undefined); if (rfMarkets.length > 0) { it("reserve factor below 100% on markets being raised", async () => { @@ -85,6 +87,18 @@ export const checkPhase4PreVip = (pools: PoolDef[]) => { } }); } + + if (emodeCfGap.length > 0) { + it("e-mode collateral-factor gaps still open (> 0, liquidation threshold matches)", async () => { + for (const m of emodeCfGap) { + const g = m.emodeCfGap; + if (!g) continue; + const data = await comptroller.poolMarkets(g.poolId, m.vToken); + expect(data.collateralFactorMantissa.gt(0), m.symbol).to.be.true; + expect(data.liquidationThresholdMantissa.toString(), m.symbol).to.equal(g.liquidationThreshold); + } + }); + } }); } }); @@ -109,6 +123,7 @@ export const checkPhase4PostVip = (pools: PoolDef[]) => { const supplyGap = pool.markets.filter(m => m.supplyCapGap); const borrowGap = pool.markets.filter(m => m.borrowCapGap); const cfGap = pool.markets.filter(m => m.cfGapLiqThreshold !== undefined); + const emodeCfGap = pool.markets.filter(m => m.emodeCfGap !== undefined); if (rfMarkets.length > 0) { it("reserve factor raised to 100%", async () => { @@ -154,6 +169,18 @@ export const checkPhase4PostVip = (pools: PoolDef[]) => { } }); } + + if (emodeCfGap.length > 0) { + it("e-mode collateral factors closed to 0 (liquidation threshold preserved)", async () => { + for (const m of emodeCfGap) { + const g = m.emodeCfGap; + if (!g) continue; + const data = await comptroller.poolMarkets(g.poolId, m.vToken); + expect(data.collateralFactorMantissa.toString(), m.symbol).to.equal("0"); + expect(data.liquidationThresholdMantissa.toString(), m.symbol).to.equal(g.liquidationThreshold); + } + }); + } }); } }); diff --git a/vips/vip-664/phase4Markets.ts b/vips/vip-664/phase4Markets.ts index 6e434676c..1baf14bf9 100644 --- a/vips/vip-664/phase4Markets.ts +++ b/vips/vip-664/phase4Markets.ts @@ -46,13 +46,16 @@ export interface Mkt { vToken: string; // true when RF is already 100% on-chain (RF command is a no-op and is skipped). rfAlready100?: boolean; - // true for markets where the IRM repoint is omitted (PLANET, stkBNB — ~$0 borrows). + // true for markets where the IRM repoint is intentionally omitted. skipIrm?: boolean; // leftover Phase-1 gaps to close → 0. supplyCapGap?: boolean; borrowCapGap?: boolean; // CF gap → 0, preserving the existing liquidation threshold. cfGapLiqThreshold?: string; + // BNB Core e-mode CF gap → 0 via the diamond setCollateralFactor(uint96,address,uint256,uint256), + // preserving the existing liquidation threshold. + emodeCfGap?: { poolId: number; liquidationThreshold: string }; } export interface PoolDef { @@ -88,7 +91,7 @@ export const BNB_DEFI: PoolDef = { { symbol: "ANKR", vToken: "0x19CE11C8817a1828D1d357DFBF62dCf5b0B2A362" }, { symbol: "ankrBNB", vToken: "0x53728FD51060a85ac41974C6C3Eb1DaE42776723" }, { symbol: "BSW", vToken: "0x8f657dFD3a1354DEB4545765fE6840cc54AFd379" }, - { symbol: "PLANET", vToken: "0xFf1112ba7f88a53D4D23ED4e14A117A2aE17C6be", rfAlready100: true, skipIrm: true }, + { symbol: "PLANET", vToken: "0xFf1112ba7f88a53D4D23ED4e14A117A2aE17C6be", rfAlready100: true }, { symbol: "TWT", vToken: "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F" }, { symbol: "USDD", vToken: "0xA615467caE6B9E0bb98BC04B4411d9296fd1dFa0" }, { symbol: "USDT", vToken: "0x1D8bBDE12B6b34140604E18e9f9c6e14deC16854" }, @@ -117,7 +120,7 @@ export const BNB_LIQUID_STAKED_BNB: PoolDef = { { symbol: "BNBx", vToken: "0x5E21bF67a6af41c74C1773E4b473ca5ce8fd3791" }, { symbol: "PT-clisBNB-24APR2025", vToken: "0xA537ACf381b12Bbb91C58398b66D1D220f1C77c8" }, { symbol: "slisBNB", vToken: "0xd3CC9d8f3689B83c91b7B59cAB4946B063EB894A" }, - { symbol: "stkBNB", vToken: "0xcc5D9e502574cda17215E70bC0B4546663785227", rfAlready100: true, skipIrm: true }, + { symbol: "stkBNB", vToken: "0xcc5D9e502574cda17215E70bC0B4546663785227", rfAlready100: true }, { symbol: "WBNB", vToken: "0xe10E80B7FD3a29fE46E16C30CC8F4dd938B742e2" }, ], }; @@ -193,7 +196,13 @@ export const BNB_CORE: PoolDef = { irmKey: "bscCore", legacy: true, markets: [ - { symbol: "DOT", vToken: "0x1610bc33319e9398de5f57B33a5b184c806aD217", supplyCapGap: true, borrowCapGap: true }, + { + symbol: "DOT", + vToken: "0x1610bc33319e9398de5f57B33a5b184c806aD217", + supplyCapGap: true, + borrowCapGap: true, + emodeCfGap: { poolId: 14, liquidationThreshold: parseUnits("0.65", 18).toString() }, + }, { symbol: "FIL", vToken: "0xf91d58b5aE142DAcC749f58A49FCBac340Cb0343" }, { symbol: "TUSDOLD", vToken: "0x08CEB3F4a7ed3500cA0982bcd0FC7816688084c3", rfAlready100: true }, { symbol: "THE", vToken: "0x86e06EAfa6A1eA631Eab51DE500E3D474933739f" }, @@ -397,5 +406,17 @@ export const generatePoolCommands = (pool: PoolDef): any[] => { }); } + // Close BNB Core e-mode CF gaps → 0 (preserving the liquidation threshold). + for (const m of markets) { + const g = m.emodeCfGap; + if (!g) continue; + commands.push({ + target: comptroller, + signature: "setCollateralFactor(uint96,address,uint256,uint256)", + params: [g.poolId, m.vToken, 0, g.liquidationThreshold], + ...chain, + }); + } + return commands; }; From 22f8d0d67a3ee1bdf84fae2e697b082d86ae6682 Mon Sep 17 00:00:00 2001 From: fred-venus Date: Wed, 17 Jun 2026 18:48:55 +0800 Subject: [PATCH 4/8] chore: prepare VIP-634 and VIP-635 for proposal --- simulations/{vip-664 => vip-634}/bscmainnet.ts | 6 +++--- simulations/{vip-664 => vip-634}/ethereum.ts | 6 +++--- simulations/{vip-664 => vip-634}/opbnbmainnet.ts | 6 +++--- simulations/{vip-664 => vip-634}/opmainnet.ts | 6 +++--- simulations/{vip-664 => vip-634}/unichainmainnet.ts | 6 +++--- .../{vip-664 => vip-634}/utils/checkPhase4.ts | 2 +- simulations/{vip-665 => vip-635}/arbitrumone.ts | 8 ++++---- simulations/{vip-665 => vip-635}/basemainnet.ts | 8 ++++---- simulations/{vip-665 => vip-635}/bscmainnet.ts | 8 ++++---- simulations/{vip-665 => vip-635}/ethereum.ts | 8 ++++---- simulations/{vip-665 => vip-635}/zksyncmainnet.ts | 8 ++++---- vips/{vip-664 => vip-634}/bscmainnet.ts | 10 ++++++---- vips/{vip-664 => vip-634}/phase4Markets.ts | 4 ++-- vips/{vip-665 => vip-635}/bscmainnet.ts | 12 +++++++----- 14 files changed, 51 insertions(+), 47 deletions(-) rename simulations/{vip-664 => vip-634}/bscmainnet.ts (72%) rename simulations/{vip-664 => vip-634}/ethereum.ts (66%) rename simulations/{vip-664 => vip-634}/opbnbmainnet.ts (67%) rename simulations/{vip-664 => vip-634}/opmainnet.ts (67%) rename simulations/{vip-664 => vip-634}/unichainmainnet.ts (67%) rename simulations/{vip-664 => vip-634}/utils/checkPhase4.ts (99%) rename simulations/{vip-665 => vip-635}/arbitrumone.ts (59%) rename simulations/{vip-665 => vip-635}/basemainnet.ts (55%) rename simulations/{vip-665 => vip-635}/bscmainnet.ts (65%) rename simulations/{vip-665 => vip-635}/ethereum.ts (64%) rename simulations/{vip-665 => vip-635}/zksyncmainnet.ts (56%) rename vips/{vip-664 => vip-634}/bscmainnet.ts (81%) rename vips/{vip-664 => vip-634}/phase4Markets.ts (99%) rename vips/{vip-665 => vip-635}/bscmainnet.ts (80%) diff --git a/simulations/vip-664/bscmainnet.ts b/simulations/vip-634/bscmainnet.ts similarity index 72% rename from simulations/vip-664/bscmainnet.ts rename to simulations/vip-634/bscmainnet.ts index 9d9f476d2..6e9bb04e6 100644 --- a/simulations/vip-664/bscmainnet.ts +++ b/simulations/vip-634/bscmainnet.ts @@ -1,7 +1,7 @@ import { forking, testVip } from "src/vip-framework"; -import vip664 from "../../vips/vip-664/bscmainnet"; -import { BNB_BTC, BNB_CORE, BNB_DEFI, BNB_GAMEFI, BNB_MEME } from "../../vips/vip-664/phase4Markets"; +import vip634 from "../../vips/vip-634/bscmainnet"; +import { BNB_BTC, BNB_CORE, BNB_DEFI, BNB_GAMEFI, BNB_MEME } from "../../vips/vip-634/phase4Markets"; import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; // BSC mainnet block (after the BNB push-out IRMs were deployed). @@ -12,7 +12,7 @@ const BNB_POOLS = [BNB_CORE, BNB_BTC, BNB_DEFI, BNB_GAMEFI, BNB_MEME]; forking(FORK_BLOCK, async () => { checkPhase4PreVip(BNB_POOLS); - testVip("VIP-664 Market Deprecation Phase 4 (Part 1) — BNB Chain", await vip664()); + testVip("VIP-634 Market Deprecation Phase 4 (Part 1) — BNB Chain", await vip634()); checkPhase4PostVip(BNB_POOLS); }); diff --git a/simulations/vip-664/ethereum.ts b/simulations/vip-634/ethereum.ts similarity index 66% rename from simulations/vip-664/ethereum.ts rename to simulations/vip-634/ethereum.ts index 5d57b4aed..914cc3485 100644 --- a/simulations/vip-664/ethereum.ts +++ b/simulations/vip-634/ethereum.ts @@ -1,7 +1,7 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip664 from "../../vips/vip-664/bscmainnet"; -import { ETH_CORE } from "../../vips/vip-664/phase4Markets"; +import vip634 from "../../vips/vip-634/bscmainnet"; +import { ETH_CORE } from "../../vips/vip-634/phase4Markets"; import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; // Ethereum mainnet block (after the Ethereum push-out IRM was deployed). @@ -10,7 +10,7 @@ const FORK_BLOCK = 25329944; forking(FORK_BLOCK, async () => { checkPhase4PreVip([ETH_CORE]); - testForkedNetworkVipCommands("VIP-664 Ethereum Core", await vip664()); + testForkedNetworkVipCommands("VIP-634 Ethereum Core", await vip634()); checkPhase4PostVip([ETH_CORE]); }); diff --git a/simulations/vip-664/opbnbmainnet.ts b/simulations/vip-634/opbnbmainnet.ts similarity index 67% rename from simulations/vip-664/opbnbmainnet.ts rename to simulations/vip-634/opbnbmainnet.ts index 7b76f68a7..72d69678d 100644 --- a/simulations/vip-664/opbnbmainnet.ts +++ b/simulations/vip-634/opbnbmainnet.ts @@ -1,7 +1,7 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip664 from "../../vips/vip-664/bscmainnet"; -import { OPBNB } from "../../vips/vip-664/phase4Markets"; +import vip634 from "../../vips/vip-634/bscmainnet"; +import { OPBNB } from "../../vips/vip-634/phase4Markets"; import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; // opBNB mainnet block (after the opBNB push-out IRM was deployed). @@ -10,7 +10,7 @@ const FORK_BLOCK = 153977309; forking(FORK_BLOCK, async () => { checkPhase4PreVip([OPBNB]); - testForkedNetworkVipCommands("VIP-664 opBNB", await vip664()); + testForkedNetworkVipCommands("VIP-634 opBNB", await vip634()); checkPhase4PostVip([OPBNB]); }); diff --git a/simulations/vip-664/opmainnet.ts b/simulations/vip-634/opmainnet.ts similarity index 67% rename from simulations/vip-664/opmainnet.ts rename to simulations/vip-634/opmainnet.ts index b19cb54c0..183c5b085 100644 --- a/simulations/vip-664/opmainnet.ts +++ b/simulations/vip-634/opmainnet.ts @@ -1,7 +1,7 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip664 from "../../vips/vip-664/bscmainnet"; -import { OPTIMISM } from "../../vips/vip-664/phase4Markets"; +import vip634 from "../../vips/vip-634/bscmainnet"; +import { OPTIMISM } from "../../vips/vip-634/phase4Markets"; import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; // Optimism mainnet block (after the Optimism push-out IRM was deployed). @@ -10,7 +10,7 @@ const FORK_BLOCK = 153006241; forking(FORK_BLOCK, async () => { checkPhase4PreVip([OPTIMISM]); - testForkedNetworkVipCommands("VIP-664 Optimism", await vip664()); + testForkedNetworkVipCommands("VIP-634 Optimism", await vip634()); checkPhase4PostVip([OPTIMISM]); }); diff --git a/simulations/vip-664/unichainmainnet.ts b/simulations/vip-634/unichainmainnet.ts similarity index 67% rename from simulations/vip-664/unichainmainnet.ts rename to simulations/vip-634/unichainmainnet.ts index 8ae67a7a3..07386b354 100644 --- a/simulations/vip-664/unichainmainnet.ts +++ b/simulations/vip-634/unichainmainnet.ts @@ -1,7 +1,7 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip664 from "../../vips/vip-664/bscmainnet"; -import { UNICHAIN } from "../../vips/vip-664/phase4Markets"; +import vip634 from "../../vips/vip-634/bscmainnet"; +import { UNICHAIN } from "../../vips/vip-634/phase4Markets"; import { checkPhase4PostVip, checkPhase4PreVip } from "./utils/checkPhase4"; // Unichain mainnet block (after the Unichain push-out IRM was deployed). @@ -10,7 +10,7 @@ const FORK_BLOCK = 50862900; forking(FORK_BLOCK, async () => { checkPhase4PreVip([UNICHAIN]); - testForkedNetworkVipCommands("VIP-664 Unichain", await vip664()); + testForkedNetworkVipCommands("VIP-634 Unichain", await vip634()); checkPhase4PostVip([UNICHAIN]); }); diff --git a/simulations/vip-664/utils/checkPhase4.ts b/simulations/vip-634/utils/checkPhase4.ts similarity index 99% rename from simulations/vip-664/utils/checkPhase4.ts rename to simulations/vip-634/utils/checkPhase4.ts index b97a87210..b8f9710b4 100644 --- a/simulations/vip-664/utils/checkPhase4.ts +++ b/simulations/vip-634/utils/checkPhase4.ts @@ -3,7 +3,7 @@ import { Contract } from "ethers"; import { parseUnits } from "ethers/lib/utils"; import { ethers } from "hardhat"; -import { PUSHOUT_IRM, PoolDef, RF_FULL } from "../../../vips/vip-664/phase4Markets"; +import { PUSHOUT_IRM, PoolDef, RF_FULL } from "../../../vips/vip-634/phase4Markets"; // Documented pre-VIP collateral factor on the two BNB Liquid Staked ETH markets (5%). const CF_GAP = parseUnits("0.05", 18); diff --git a/simulations/vip-665/arbitrumone.ts b/simulations/vip-635/arbitrumone.ts similarity index 59% rename from simulations/vip-665/arbitrumone.ts rename to simulations/vip-635/arbitrumone.ts index a61212887..2aef2bd62 100644 --- a/simulations/vip-665/arbitrumone.ts +++ b/simulations/vip-635/arbitrumone.ts @@ -1,8 +1,8 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import { ARBITRUM_LIQUID_STAKED_ETH } from "../../vips/vip-664/phase4Markets"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; +import { ARBITRUM_LIQUID_STAKED_ETH } from "../../vips/vip-634/phase4Markets"; +import vip635 from "../../vips/vip-635/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-634/utils/checkPhase4"; // Arbitrum One block (after the Arbitrum push-out IRM was deployed). const FORK_BLOCK = 474085204; @@ -10,7 +10,7 @@ const FORK_BLOCK = 474085204; forking(FORK_BLOCK, async () => { checkPhase4PreVip([ARBITRUM_LIQUID_STAKED_ETH]); - testForkedNetworkVipCommands("VIP-665 Arbitrum", await vip665()); + testForkedNetworkVipCommands("VIP-635 Arbitrum", await vip635()); checkPhase4PostVip([ARBITRUM_LIQUID_STAKED_ETH]); }); diff --git a/simulations/vip-665/basemainnet.ts b/simulations/vip-635/basemainnet.ts similarity index 55% rename from simulations/vip-665/basemainnet.ts rename to simulations/vip-635/basemainnet.ts index bdef592ad..3af01013c 100644 --- a/simulations/vip-665/basemainnet.ts +++ b/simulations/vip-635/basemainnet.ts @@ -1,8 +1,8 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import { BASE_CORE } from "../../vips/vip-664/phase4Markets"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; +import { BASE_CORE } from "../../vips/vip-634/phase4Markets"; +import vip635 from "../../vips/vip-635/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-634/utils/checkPhase4"; // Base mainnet block (after the Base push-out IRM was deployed). const FORK_BLOCK = 47410957; @@ -10,7 +10,7 @@ const FORK_BLOCK = 47410957; forking(FORK_BLOCK, async () => { checkPhase4PreVip([BASE_CORE]); - testForkedNetworkVipCommands("VIP-665 Base", await vip665()); + testForkedNetworkVipCommands("VIP-635 Base", await vip635()); checkPhase4PostVip([BASE_CORE]); }); diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-635/bscmainnet.ts similarity index 65% rename from simulations/vip-665/bscmainnet.ts rename to simulations/vip-635/bscmainnet.ts index 635a115b8..fb23f27c9 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-635/bscmainnet.ts @@ -5,9 +5,9 @@ import { BNB_LIQUID_STAKED_ETH, BNB_STABLECOINS, BNB_TRON, -} from "../../vips/vip-664/phase4Markets"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; +} from "../../vips/vip-634/phase4Markets"; +import vip635 from "../../vips/vip-635/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-634/utils/checkPhase4"; // BSC mainnet block (after the BNB push-out IRM was deployed). const FORK_BLOCK = 104562598; @@ -17,7 +17,7 @@ const BNB_POOLS = [BNB_LIQUID_STAKED_BNB, BNB_LIQUID_STAKED_ETH, BNB_STABLECOINS forking(FORK_BLOCK, async () => { checkPhase4PreVip(BNB_POOLS); - testVip("VIP-665 Market Deprecation Phase 4 (Part 2) — BNB Chain", await vip665()); + testVip("VIP-635 Market Deprecation Phase 4 (Part 2) — BNB Chain", await vip635()); checkPhase4PostVip(BNB_POOLS); }); diff --git a/simulations/vip-665/ethereum.ts b/simulations/vip-635/ethereum.ts similarity index 64% rename from simulations/vip-665/ethereum.ts rename to simulations/vip-635/ethereum.ts index 9f815f99e..a52953806 100644 --- a/simulations/vip-665/ethereum.ts +++ b/simulations/vip-635/ethereum.ts @@ -1,8 +1,8 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import { ETH_CURVE, ETH_LIQUID_STAKED_ETH } from "../../vips/vip-664/phase4Markets"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; +import { ETH_CURVE, ETH_LIQUID_STAKED_ETH } from "../../vips/vip-634/phase4Markets"; +import vip635 from "../../vips/vip-635/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-634/utils/checkPhase4"; // Ethereum mainnet block (after the Ethereum push-out IRM was deployed). const FORK_BLOCK = 25329944; @@ -10,7 +10,7 @@ const FORK_BLOCK = 25329944; forking(FORK_BLOCK, async () => { checkPhase4PreVip([ETH_CURVE, ETH_LIQUID_STAKED_ETH]); - testForkedNetworkVipCommands("VIP-665 Ethereum Curve + Liquid Staked ETH", await vip665()); + testForkedNetworkVipCommands("VIP-635 Ethereum Curve + Liquid Staked ETH", await vip635()); checkPhase4PostVip([ETH_CURVE, ETH_LIQUID_STAKED_ETH]); }); diff --git a/simulations/vip-665/zksyncmainnet.ts b/simulations/vip-635/zksyncmainnet.ts similarity index 56% rename from simulations/vip-665/zksyncmainnet.ts rename to simulations/vip-635/zksyncmainnet.ts index 9719fc8d8..f8bb179c9 100644 --- a/simulations/vip-665/zksyncmainnet.ts +++ b/simulations/vip-635/zksyncmainnet.ts @@ -1,8 +1,8 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import { ZKSYNC_CORE } from "../../vips/vip-664/phase4Markets"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-664/utils/checkPhase4"; +import { ZKSYNC_CORE } from "../../vips/vip-634/phase4Markets"; +import vip635 from "../../vips/vip-635/bscmainnet"; +import { checkPhase4PostVip, checkPhase4PreVip } from "../vip-634/utils/checkPhase4"; // zkSync Era mainnet block (after the zkSync push-out IRM was deployed). const FORK_BLOCK = 70814289; @@ -10,7 +10,7 @@ const FORK_BLOCK = 70814289; forking(FORK_BLOCK, async () => { checkPhase4PreVip([ZKSYNC_CORE]); - testForkedNetworkVipCommands("VIP-665 zkSync Era", await vip665()); + testForkedNetworkVipCommands("VIP-635 zkSync Era", await vip635()); checkPhase4PostVip([ZKSYNC_CORE]); }); diff --git a/vips/vip-664/bscmainnet.ts b/vips/vip-634/bscmainnet.ts similarity index 81% rename from vips/vip-664/bscmainnet.ts rename to vips/vip-634/bscmainnet.ts index a52b14615..614775eb6 100644 --- a/vips/vip-664/bscmainnet.ts +++ b/vips/vip-634/bscmainnet.ts @@ -16,7 +16,7 @@ import { const meta = { version: "v2", - title: "VIP-664 Market Deprecation Phase 4 (Part 1 of 2)", + title: "VIP-634 Market Deprecation Phase 4 (Part 1 of 2)", description: `#### Summary This proposal is the first of two VIPs implementing Phase 4 of the market deprecation outlined in the Venus community forum ([Deprecate Venus Core on opBNB / Optimism / Unichain + Isolated Pools](https://community.venus.io/t/deprecate-venus-core-on-opbnb-optimism-unichain-isolated-pools/5760) and [May 2026 Risk Parameter Update & Asset Off-boarding](https://community.venus.io/t/may-2026-risk-parameter-update-asset-off-boarding/5785)). @@ -25,7 +25,7 @@ The work is split across two VIPs to respect the governor's 100-operation limit #### Description -For each deprecated market this VIP: +These markets already had their collateral factors reduced to zero through prior off-boarding actions, but their reserve factors, interest rate models, and certain residual supply / borrow caps remain misaligned with a wound-down state. For each deprecated market this VIP: 1. Sets the reserve factor to 100% (markets already at 100% are skipped). 2. Repoints the interest rate model to the chain's push-out deprecation curve (base 300% / slope1 0% / jump 363.64% / kink 0.45 — flat 300% below the kink, ramping to a 500% maximum at full utilization). PLANET and stkBNB are excluded (~$0 borrows, IRM moot). @@ -33,6 +33,8 @@ For each deprecated market this VIP: Liquidation thresholds are unchanged; no action reduces collateral factors of healthy positions in this part. +This parameter update is the first of a two-step wind-down. A follow-up VIP, expected approximately two weeks later, will set the liquidation thresholds and remaining collateral factors of these markets to zero, completing the wind-down. + #### Security and additional considerations - **VIP execution simulation**: validated in a fork environment that each market ends with the 100% reserve factor, the push-out IRM, and zeroed caps. @@ -42,7 +44,7 @@ Liquidation thresholds are unchanged; no action reduces collateral factors of he abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", }; -export const vip664 = () => +export const vip634 = () => makeProposal( [ // ── BNB Core (legacy) ── @@ -64,4 +66,4 @@ export const vip664 = () => ProposalType.REGULAR, ); -export default vip664; +export default vip634; diff --git a/vips/vip-664/phase4Markets.ts b/vips/vip-634/phase4Markets.ts similarity index 99% rename from vips/vip-664/phase4Markets.ts rename to vips/vip-634/phase4Markets.ts index 1baf14bf9..c64b72b48 100644 --- a/vips/vip-664/phase4Markets.ts +++ b/vips/vip-634/phase4Markets.ts @@ -264,8 +264,8 @@ export const UNICHAIN: PoolDef = { }; // Ethereum is split across the two VIPs to keep each LayerZero message < 10 KB: -// - ETH_CORE → VIP-664 -// - ETH_CURVE + ETH_LIQUID_STAKED_ETH → VIP-665 +// - ETH_CORE → VIP-634 +// - ETH_CURVE + ETH_LIQUID_STAKED_ETH → VIP-635 export const ETH_CORE: PoolDef = { label: "Ethereum Core pool", comptroller: "0x687a01ecF6d3907658f7A7c714749fAC32336D1B", diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-635/bscmainnet.ts similarity index 80% rename from vips/vip-665/bscmainnet.ts rename to vips/vip-635/bscmainnet.ts index aeb847742..70a3be63d 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-635/bscmainnet.ts @@ -12,11 +12,11 @@ import { ETH_LIQUID_STAKED_ETH, ZKSYNC_CORE, generatePoolCommands, -} from "../vip-664/phase4Markets"; +} from "../vip-634/phase4Markets"; const meta = { version: "v2", - title: "VIP-665 Market Deprecation Phase 4 (Part 2 of 2)", + title: "VIP-635 Market Deprecation Phase 4 (Part 2 of 2)", description: `#### Summary This proposal is the second of two VIPs implementing Phase 4 of the market deprecation outlined in the Venus community forum ([Deprecate Venus Core on opBNB / Optimism / Unichain + Isolated Pools](https://community.venus.io/t/deprecate-venus-core-on-opbnb-optimism-unichain-isolated-pools/5760) and [May 2026 Risk Parameter Update & Asset Off-boarding](https://community.venus.io/t/may-2026-risk-parameter-update-asset-off-boarding/5785)). @@ -25,12 +25,14 @@ The work is split across two VIPs to respect the governor's 100-operation limit #### Description -For each deprecated market this VIP: +Most in-scope markets already had their collateral factors reduced to zero through prior off-boarding actions; this VIP brings the remaining parameters — reserve factors, interest rate models, residual caps, and the two BNB Liquid Staked ETH markets still carrying a 5% collateral factor — in line with a wound-down state. For each deprecated market this VIP: 1. Sets the reserve factor to 100% (markets already at 100% are skipped). 2. Repoints the interest rate model to the chain's push-out deprecation curve (base 300% / slope1 0% / jump 363.64% / kink 0.45 — flat 300% below the kink, ramping to a 500% maximum at full utilization). 3. Closes the leftover Phase-1 gaps by setting outstanding supply / borrow caps to 0, and sets the collateral factor to 0 for the two BNB Liquid Staked ETH markets (weETH, wstETH) that still carry a 5% collateral factor. Liquidation thresholds are unchanged, so no healthy position is liquidated. +This parameter update is the first of a two-step wind-down. A follow-up VIP, expected approximately two weeks later, will set the liquidation thresholds and remaining collateral factors of these markets to zero, completing the wind-down. + #### Security and additional considerations - **VIP execution simulation**: validated in a fork environment that each market ends with the 100% reserve factor, the push-out IRM, zeroed caps, and (for the two flagged markets) a 0% collateral factor. @@ -40,7 +42,7 @@ For each deprecated market this VIP: abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", }; -export const vip665 = () => +export const vip635 = () => makeProposal( [ // ── BNB isolated pools ── @@ -60,4 +62,4 @@ export const vip665 = () => ProposalType.REGULAR, ); -export default vip665; +export default vip635; From 25dbc620955c6998ed19682c9046e018b2431da9 Mon Sep 17 00:00:00 2001 From: fred-venus Date: Wed, 17 Jun 2026 20:10:06 +0800 Subject: [PATCH 5/8] vip-634: drop 4 ETH_CORE yv* markets to keep propose tx under EIP-7825 16.78M gas cap Full 55-cmd propose needs ~17.6M gas, over BSC's per-tx cap (16,777,216); removing yvUSDC/USDT/USDS/WETH-1 brings it to ~16.28M. --- vips/vip-634/phase4Markets.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vips/vip-634/phase4Markets.ts b/vips/vip-634/phase4Markets.ts index c64b72b48..14a470f2d 100644 --- a/vips/vip-634/phase4Markets.ts +++ b/vips/vip-634/phase4Markets.ts @@ -277,10 +277,10 @@ export const ETH_CORE: PoolDef = { { symbol: "sFRAX", vToken: "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe" }, { symbol: "EIGEN", vToken: "0x256AdDBe0a387c98f487e44b85c29eb983413c5e" }, { symbol: "BAL", vToken: "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8" }, - { symbol: "yvUSDC-1", vToken: "0xf87c0a64dc3a8622D6c63265FA29137788163879" }, - { symbol: "yvUSDT-1", vToken: "0x475d0C68a8CD275c15D1F01F4f291804E445F677" }, - { symbol: "yvUSDS-1", vToken: "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764" }, - { symbol: "yvWETH-1", vToken: "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0" }, + // { symbol: "yvUSDC-1", vToken: "0xf87c0a64dc3a8622D6c63265FA29137788163879" }, + // { symbol: "yvUSDT-1", vToken: "0x475d0C68a8CD275c15D1F01F4f291804E445F677" }, + // { symbol: "yvUSDS-1", vToken: "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764" }, + // { symbol: "yvWETH-1", vToken: "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0" }, ], }; From d7037b94e2794127b0b445fb803a5507ca60dc9c Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 17 Jun 2026 18:21:47 +0530 Subject: [PATCH 6/8] feat(vip-framework): enforce per-tx gas cap at propose, log gas for all governance steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A VIP is stored in a single propose() tx, so it must fit BSC's 2^24 per-tx gas cap — over it the on-chain propose reverts with an empty error and the VIP can't be created, something the sim previously never caught. Add a reportTxGas() helper that logs gasUsed (% of cap) for propose/queue/execute in one format and asserts the cap on propose (the binding, heaviest tx). --- src/vip-framework/index.ts | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/vip-framework/index.ts b/src/vip-framework/index.ts index 82c65f57b..4141e13a3 100644 --- a/src/vip-framework/index.ts +++ b/src/vip-framework/index.ts @@ -163,6 +163,31 @@ export const pretendExecutingVip = async (proposal: Proposal, sender: string = G return txResponses; }; +// Logs a single governance transaction's gas in a consistent format: +// [gas]