Uh oh!
There was an error while loading. Please reload this page.
VDB-54: draft: VIP-664 list vhUSDT, vhUSDC, vhU in the Venus Core Pool - #754
Open
trumpgpt-bot wants to merge 12 commits into
Open
VDB-54: draft: VIP-664 list vhUSDT, vhUSDC, vhU in the Venus Core Pool#754trumpgpt-bot wants to merge 12 commits into
trumpgpt-bot wants to merge 12 commits into
Conversation
Non-borrowable collateral markets backed by Venus Hub receipt tokens (24-dec ERC4626), with a capped ERC4626Oracle and E-brake (DBO) per market. Confirmed risk params + recommended defaults for the two open knobs baked in; deploy-dependent addresses and the fork simulation remain pending (see PR).
trumpgpt-bot
marked this pull request as ready for review
August 19, 2026 05:53
…view Addresses PR #754 review (Debugger022): the reviewer confirmed the underlying addresses are correct and the vToken/oracle placeholders are legitimately deploy-gated. Remaining points were to make three deliberate choices explicit in the VIP text so reviewers do not read them as contradictions: - IRM is wired only to satisfy the vToken constructor and is inert while borrowing is paused (consistent with the template's "IRM not needed"). - CF == LT on all three markets is intentional per the approved template (tightly-pegged, growth-capped, E-brake-protected collaterals). - reserveFactor / vTokenReceiver / bootstrap amount follow the standard Core-pool convention where the template was silent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
…CF split, seize share) Address the 'flags to close before this becomes a VIP' from the approved listing-template source doc: - state the 10M supply cap is denominated in underlying vhToken amount (24 dec), not USD (~$10M at the ~$1 vault price) - record the 82.5/80/75 collateral-factor split as approved per-asset risk-manager values ordered by peg maturity/depth (USDC > USDT > USD1/U), not a blanket ACK - note protocol seize share is a global Comptroller parameter, unchanged by this VIP Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
snapshotInterval = MaxUint256 never re-snapshots, so the 5%/yr cap would grow unbounded from the deploy seed. Both live BNB Chain capped oracles (asBNB and slisBNB) run 5%/yr over a 30-day interval since VIP-605. Also records what was read from chain: all three vhToken addresses, names, 24 decimals and ERC4626 assets check out, U trades at ~$1, and the VTreasury holds none of the three vhTokens the bootstrap withdraws.
Deploy-gated: the oracle, vToken and IRM addresses are still zero, so the run fails on them. CI runs ./tests only, not ./simulations.
Debugger022force-pushed
the
bot/VDB-54-draft-vip-to-list-vhusdt-vhusdc-vhu-in-venus-core-pool
branch
from
August 19, 2026 10:45
ca89111 to
f29431fCompareThe capped ERC4626 oracles deploy with every cap parameter zeroed, the same way the asBNB oracle did, so the cap has to be armed by a VIP or the markets list with an uncapped price source. VIP-530 is the precedent. Order matters: setSnapshot must precede setGrowthRate, because updateSnapshot() on an oracle whose snapshotMaxExchangeRate is still 0 collapses the cap to snapshotGap alone. Gap of 41 bps is one snapshot interval of capped growth (5% * 30/365), the ratio VIP-530 used on every asset it armed. Seeds are the live vault rates at block 116836175. Measured growth is 1.82%/1.52%/2.29% per year, so the 5% cap keeps 2-3x headroom and will not bind. No new interest rate model: 0x1Ef3b851 already carries base 0, multiplier 9%, jump 200%, kink 50% and already backs vasBNB and vslisBNB.
Mirrors the mainnet VIP through the real capped ERC4626 oracle instead of a mocked direct price, so the growth cap is exercised before mainnet. Mock 24-decimal vault, oracle and vToken addresses stay zeroed until the testnet deploy lands.
DeviationBoundedOracle.setTokenConfig seeds minPrice and maxPrice from RESILIENT_ORACLE.getPrice(asset), so it reverts unless the capped oracle is registered first. The command was already last in each market block but nothing recorded why, and nothing checked the seeding.
Diffing the command list against every recent core-pool listing turned up two commands other listings issue that this one relied on defaults for. _setMarketBorrowCaps: a fresh market already defaults to 0, but the borrow cap is a stated risk parameter and the simulation was asserting a default rather than a decision. VIP-554 and VIP-581 set it. _setInterestRateModel: the model was trusted from the vToken constructor. Since this reuses an already deployed model rather than deploying one per market, the VIP now sets it so it does not depend on what the deploy passes. VIP-581 does the same. Also corrects the protocol seize share note: the legacy Core vToken exposes no protocolSeizeShare getter or setter at all, so there is nothing to configure.
Hub_USDT is the only Venus Hub vault deployed on testnet, so there is no vhUSDC or vhU to list. Its share token is vSHARE with 12 decimals, not mainnet's 24, because testnet USDT is 6 decimals and the Hub adds a 6 decimal offset. Every amount is redenominated accordingly.
The VTreasury holds USDT but no vSHARE, so withdrawing the share token reverted. Pull USDT instead and mint the shares from Hub_USDT, which removes the pre-funding step entirely. Uses mint(shares, receiver) rather than deposit(assets, receiver) so the share count is pinned and the hardcoded amounts cannot drift with the vault rate.
Both contracts are live and verified on BscScan testnet. The fork block moves past them, and the ChainlinkOracle stale period has to be relaxed because a pinned fork block goes stale against the feed's 24h window and every getPrice call reverts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft VIP-664 listing three non-borrowable collateral markets in the BNB Core pool, backed by Venus Hub receipt tokens (24-decimal ERC4626): vvhUSDT / vvhUSDC / vvhU. Mainnet and testnet VIPs plus both fork simulations.
tsc0 errors,eslintandprettierclean. The mainnet proposal builds to 66 commands, 22 per market. The testnet proposal lists one market and builds to 25.Companion deploy branch:
VenusProtocol/oracle@feat/vh-capped-oracles.Confirmed on chain
0x18AfDACF30F8671021dec4b78297E39d2FE872260x9D2D9592cF8DFbf59107fAab703d08494BE146170x0e5AA174d4F31b757a237eb1999DE151596788B0asset()0x55d3…79550x8AC7…580d0xcE24…6666CorrelatedTokenOracle._calculatePricedivides by10 ** correlatedToken.decimals(), so a 24-decimal share returns a price scaled to10**12— exactly Venus's10**(36-decimals)convention.DeviationBoundedOracleenforcesMIN_THRESHOLD = 5e16,MAX_THRESHOLD = 50e16, reset below trigger, cooldown non-zero. 5% is the contract minimum. VIP-633's 16.67% is an equity setting and is not reused.Two defects found and fixed
1. The cap was never going to be armed. The capped ERC4626 oracles deploy with every cap parameter zeroed — the same way the asBNB oracle was deployed — and
getPriceskips capping entirely whilesnapshotMaxExchangeRateis 0. The earlier draft assumed the deploy would arm it, so the markets would have listed with an uncapped price source and nothing would have flagged it. VIP-530 is the precedent for arming, and this VIP now does it per market:setSnapshot, thensetGrowthRate, thensetSnapshotGap. Permissions already sit with the Normal, Fast-Track and Critical timelocks from VIP-517, so no new ACM grants are needed.The order is load-bearing.
updateSnapshot()on an oracle whose snapshot is still 0 computesmin(rate, 0) + gapand collapses the cap to the gap alone — about 0.4% of the true rate.setSnapshotmust come first.2.
snapshotInterval = MaxUint256was wrong. The first draft called it a "frozen snapshot", but with that valueupdateSnapshot()can never fire and the cap grows unbounded from the seed forever. Both live BNB Chain capped oracles use a 30-day interval.The 41 bps gap is one snapshot interval of capped growth (5% × 30/365 = 0.41%) — the ratio VIP-530 applied to every asset it armed: BNBx 7.53%/yr → 63 bps, ankrBNB 6.12%/yr → 51 bps, sUSDe 28.27%/yr → 236 bps, slisBNB 4.12%/yr → 34 bps. Seeds were read at block 116836175 (
2026-08-19T10:57:40Z), which is also the snapshot timestamp.Also in this branch
0x1Ef3b851…already carries base 0 / multiplier 9% / jump 200% / kink 50% and already backs vasBNB and vslisBNB. Testnet has the mirror at0x8734dBD8…. Three deploys avoided.checkRiskParametersskips both whenisLegacyPoolis true, so a core-pool listing that sets them otherwise gets no coverage.Price protection, and E-mode
Two independent layers, both configured here:
DeviationBoundedOraclebounds the price with a 5% deviation trigger, 2% reset and 1h cooldown. ItssetTokenConfigseedsminPriceandmaxPricefromRESILIENT_ORACLE.getPrice(asset), so it is the last command in each market block: it reverts if the capped oracle is not registered first. That self-seeding is also why no separate bounds command is needed.E-mode is out of scope, per the listing checklist. The Core Comptroller's pool-scoped overloads —
setCollateralFactor(uint96,…),setLiquidationIncentive(uint96,…),addPoolMarkets,setIsBorrowAllowed— are not called; the built proposal contains zerouint96commands, so all three markets land in the base pool. Non-borrowable is therefore enforced withsetActionsPaused(BORROW), becausesetIsBorrowAllowedexists only in the pool-scoped form.addMarket completeness
The command list was diffed against every recent Core-pool listing (VIP-554, 581, 584, 596, 633, 643). Two commands those listings issue were being left to defaults and are now explicit:
_setMarketBorrowCaps— a fresh market defaults to 0, but the borrow cap is a stated risk parameter, and the simulation was asserting a default rather than a decision._setInterestRateModel— the model was trusted from the vToken constructor. Since this reuses an already deployed model instead of deploying one per market, the VIP now sets it.Deliberately absent, each checked rather than assumed:
protocolSeizeSharegetter or setter; it is a constant in the implementation. No Core-pool listing sets it._acceptAdmin— not needed if the vTokens are constructed withadmin= NormalTimelock, which is how VIP-643's market was deployed. Tracked in the todo.setValidateConfig(BoundValidator) — only meaningful with a pivot oracle. These markets use a single main source, as asBNB does.setTokenConfig((address,address,uint256))— a Chainlink/Atlas-style feed config. The capped ERC4626Oracle derives its price from the vault and needs no feed.setConversionConfigs— token-converter routing for reserves. Tracked in the todo as a follow-up.bsctestnet
Testnet lists one market, not three.
Hub_USDTis the only Venus Hub vault deployed there, there is no Hub for USDC or U, and noUtoken exists on testnet at all. Its share token is namedVault Share/vSHAREand has 12 decimals rather than mainnet's 24, because testnet USDT is 6 decimals and the Hub adds a 6 decimal offset. Every amount in the testnet VIP is redenominated accordingly, and the exchange rate is1e22rather than1e34.Both contracts are deployed and verified:
vSHARE_ERC4626Oracle0xB5A17EB6A135A61057bc2F4f102c633899256BFavvSHAREvToken0xb846eEbaC8b014296709dc660Bfcb6ea182718e8The vToken reuses
VBep20Delegate0x73fF7509…, the implementation behind the live vasBNB and vslisBNB markets, and itsadminis set to the NormalTimelock in the constructor, so no_acceptAdminis needed. Risk parameters match mainnet's vhUSDT market: CF and LT 80%, supply cap 10M, borrow cap 0, reserve factor 10%, liquidation incentive 10%, cap 5%/yr over 30 days with a 41 bps gap, E-brake 5% / 2% / 1h.The bootstrap no longer needs the Treasury pre-funded. The VTreasury holds testnet USDT but no vSHARE, so
withdrawTreasuryBEP20(vSHARE, …)would revert. The testnet VIP now withdraws USDT, mints exactly 100 vSHARE fromHub_USDT, and supplies those to the new market. It calls the vault'smint(shares, receiver)rather thandeposit(assets, receiver), which pins the share count so the amounts hardcoded in the VIP cannot drift with the vault rate. The timelock keeps neither the asset nor the shares, and both approvals are cleared.Simulation: 75 passing, 0 failing, all 25 commands executing, at fork block 126331000. The ChainlinkOracle stale period is relaxed in
before(), since a pinned fork block goes stale against the feed's 24h window and everygetPricecall would revert.Proposed, queued and executed on bsctestnet as proposal 713.
0x81b3cb16…0x2f0b8297…0x28fc694d…Every gas figure matches the local simulation exactly, and
state(713)reads 7 (Executed). Reads against the live market after execution:markets(vvSHARE)listed with CF 0.80; supply cap 10,000,000 vSHARE; borrow cap 0 with the BORROW action paused; reserve factor 10%; interest rate model0x8734dBD8…vvSHARE.totalSupplyis 100, of which 10 sit at the zero address and 90 at the vTokenReceiver;exchangeRateStoredis 1e22ResilientOracle.getPrice(vSHARE)returns5e23($0.50), with the main oracle set to0xB5A17EB6…and flags true / false / falsesnapshotMaxExchangeRate1004100, which is the 1,000,000 seed plus the 41 bps gap, atsnapshotTimestamp1787137060Todo
Blocked on deploys and funding:
VHUSDT/VHUSDC/VHU_ORACLE. The testnet one is deployed and its artifact is committed on that PR.admin= NormalTimelock → fillVVHUSDT/VVHUSDC/VVHU. The testnet vToken is deployed and filled in.FORK_BLOCKand run its simulation green. Testnet is done: 75 passing at block 126331000.Decisions needed:
totalSupplyis 10.000000040 shares and 10 of those sit at0x000000000000000000000000000000000000dEaD, so the vault is effectively empty and unused.totalAssetsis 10.0065 U.Outside this repo:
setConversionConfigs) for the three vhTokensNot blocking: CI runs
./testsonly, so the deploy-gated simulations don't affect it. The testnet simulation now passes end to end; the mainnet one forks and runs, with every remaining failure tracing to the zero addresses plus the unfunded Treasury.