Repository navigation
feat: VIP-675/677/678 list the bStock mainstream spoke pool on BNB Chain - #787
Conversation
Lists a second Hub-Funded Spoke pool of single-stock bStocks on BNB Chain. Its execute() does not fit one or two proposals under the per-tx gas cap, so the listing is split by tier into three proposals built from one shared command builder. - VIP-674: the pool, the USDT, USDC and U markets with their Hub wiring, and the tier 1 bStocks - VIP-675: tier 2 and 3 bStocks - VIP-676: tier 4 bStocks - one fork simulation covering all three, end to end
Drop AMATB and set per-market risk values and protocol seize shares. - Drop AMATB, leaving 20 collateral markets. - Set each market's CF, LT, liquidation incentive and supply cap. - Set the protocol seize share where it differs from the 5% default, in the aggregator batch after the market's incentive. - Raise the e2e loan to 45% of the collateral value. At 40%, NVDAB's 80% LT left the loan exactly at the threshold after the price halved. - Check each part's incentive and seize share in its own test, and expect ActionPaused on a collateral borrow. - Trim comments that went stale or restated the code.
The pool's markets were redeployed under the bStock mainstream name. - Use the 23 redeployed markets, and name the pool, symbols and code after bStock mainstream. - Move the simulation fork past the deployments. VIP-673 is queued there, so the simulation applies its commands without cancelling it. - Measure feed age at the fork block, not at the latest block.
VIP-674 is already on chain for another proposal, so the three parts move up by one and the folders move to vip-675.
A third pool in the Spoke pool registry: BPNC, the BPN Credit Token, priced at a fixed $1 and suppliable only by allowlisted accounts, as collateral, and USDT, USDC and U as Hub-funded liquidity at a flat 6% borrow APY. Draft: BPNC, the comptroller, the four markets, the flat rate model and BPN's supply address are pending, and vip678() throws until they are set. The simulation deploys stand-ins for them on a bscmainnet fork. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
BPNC is a CustodyReceiptToken, the vceBTC contract, deployed with the Normal Timelock nominated as owner. VIP-678 accepts ownership and mints the first 3,333,334 BPNC to the Operator and the 10 BPNC seed. The Normal Timelock holds mint only for those two mints. The Operator gets mint and pause; the Normal Timelock and the Critical Guardian get burn and unpause. With the token steps the proposal needed 99.3% of the per-tx gas cap to be proposed through the Safe. The grants, risk setters, allowlists and Hub wiring now run as two adjacent AuxiliaryCommandsAggregator batches. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
VIP-678 now turns on the pool's liquidation allowlist with only the Liquidity Hub Operator on it, per the updated listing doc. Every seizure checks the allowlist, so no one else can liquidate BPNC through liquidateBorrow, liquidateAccount or healAccount. The two calls run in the second batch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| underlying: CRCLB, | ||
| supplyCap: cap(12340), | ||
| initialSupply: parseUnits("0.13", 18), | ||
| atlasFeed: PENDING, |
There was a problem hiding this comment.
fix: use the authorized Atlas feeds for the bStock mainstream assets
Updated CRCLB, SNDKB, MSFTB and MUB to Atlas's sheet feeds, all authorized for AtlasOracle.
| export const REGISTRY_GRANTS_MAINSTREAM: Grant[] = REGISTRY_GRANTS.map(role => ({ | ||
| role, | ||
| account: SPOKE_POOL_REGISTRY, | ||
| })); | ||
|
|
||
| /// The other 14: the Normal Timelock's six, the Critical Guardian's five, the Pause Guardian's two and | ||
| /// CollateralGateway's `enterMarketForAccount`. Nothing in VIP-675 needs them first, so they run in the aggregator | ||
| /// batch. | ||
| export const OTHER_GRANTS_MAINSTREAM: Grant[] = [ | ||
| ...NORMAL_TIMELOCK_GRANTS.map(role => ({ role, account: NORMAL_TIMELOCK })), | ||
| ...CRITICAL_GUARDIAN_GRANTS.map(role => ({ role, account: CRITICAL_GUARDIAN })), | ||
| ...PAUSE_GUARDIAN_GRANTS.map(role => ({ role, account: PAUSE_GUARDIAN })), | ||
| ...ROUTER_ROLES.map(role => ({ role, account: COLLATERAL_GATEWAY })), | ||
| ]; |
There was a problem hiding this comment.
lets apply this following rule for the acm grants, for each caller + exact function signature:
- if an on-chain wildcard already covers that caller/function, omit the redundant contract-scoped grant.
- otherwise, where the permission should apply across pools, grant the wildcard once and revoke scoped permissions on existing pools if the wildcard also covers the case
- only keep scoped permissions where access is intentionally limited to specific contracts
There was a problem hiding this comment.
this way in the future when adding more spoke pool we no gonna need acm setting
There was a problem hiding this comment.
@fred-venus Should Critical Guardian's setCloseFactor, setLiquidationIncentive, setMinLiquidatableCollateral and setForcedLiquidation be wildcards? As wildcards they also reach FRV LiquidationAdapter, where it has no access today.
Granting CollateralGateway enterMarketForAccount as a wildcard, and revoking its scoped grants on the bStock index pool and Core.
There was a problem hiding this comment.
Done: feat: grant the spoke comptroller roles as wildcards
LMK if any changes in permissions are required
| underlying: GOOGLB, | ||
| supplyCap: cap(3060), | ||
| initialSupply: parseUnits("0.032", 18), | ||
| atlasFeed: "0x2FcEafD81a4dBDa2409B6fe5ce2afFe3cD46eDbC", |
There was a problem hiding this comment.
seems not limited to google, others are different as well
There was a problem hiding this comment.
The Notion doc listed Atlas feeds that are not authorized for AtlasOracle, so all 16 new assets were affected, not only GOOGLB. They now use the authorized feeds from Atlas's sheet, and the sim checks isAuthorizedCaller
fix: use the authorized Atlas feeds for the bStock mainstream assets
@fred-venus While reviewing, I found this point too but dropped it for the reason below. We're adding it now, so sharing the reason FYI:
add it for both pools: feat: set the bStock mainstream and bStock index pool descriptions |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Final BPNC roles: mint and pause to the Operator, the Normal Timelock and the Critical Guardian; burn and unpause to the Normal Timelock and the Critical Guardian. The Normal Timelock keeps the mint it is granted for the two mints, so the revoke is gone and the batch skips that one grant. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The listed Atlas feeds for the 16 new assets never authorized the Atlas oracle, so execution would revert when the deviation-bounded oracle reads the price. - Switch every new asset to the feed from Atlas's feed list - Drop the candidate feeds and the simulation's stand-in for them - Check isAuthorizedCaller on every Atlas feed in the simulation - Fork at 130,450,000 and propose from an account with no live proposal
…feat/bpn-loan-spoke-pool
Drop the comptroller grants the bStock mainstream pool's address(0) wildcards cover, keeping the Critical Guardian's setCloseFactor scoped. The sim now applies that VIP's part 1 with pretendExecutingVip at a recent block.
Only BPN's supplier is still pending. The sim drops its stand-ins and runs against the live deployments.
Every command now sits in makeProposal in execution order, run by the Normal Timelock, since without the wildcard-covered grants it proposes at 75% of the gas cap. BPN's supplier is a placeholder, and the sim impersonates it.
Add updatePoolMetadata after addPool, as the bStock mainstream pool does. The addresses folder becomes config.ts, with network addresses from NETWORK_ADDRESSES and the rest written out instead of re-exported through earlier VIPs.
…revoke the gateway's Core grant - Grant all 20 spoke comptroller roles against address(0), including the Critical Guardian's setCloseFactor, so a later spoke pool needs no ACM grant. As a wildcard it also reaches FRV's LiquidationAdapter, the only Critical Guardian role FRV checks. - Revoke CollateralGateway's scoped enterMarketForAccount grant on Core, which its wildcard covers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The VTreasury now holds every seed and VIP-673 has executed, so the simulation no longer has to fake either. - Move FORK_BLOCK to 130640000 - Remove the VIP-673 apply, the treasury top-up and the explicit proposer - Assert that the VTreasury holds every seed - Remove comments that are stale or point to docs outside the repo
Pin part 1's aggregator batches at their seeded indices 5 and 6, fork the simulation after the seeding, and drop the inline backticks the governance UI hides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n's setCloseFactor The base branch now grants setCloseFactor against address(0), so the scoped grant goes.
…eeding The base pool's batches are now pinned, so fork past their seeding; the dependency it applied has executed by then.
The Operator keeps pause, so it can still stop BPNC transfers, but no longer gets mint. Minting, burning and unpausing BPNC are left to the Normal Timelock and the Critical Guardian. The simulation mints its test BPNC from the Normal Timelock and checks that the Operator cannot mint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each Spoke yield group now withdraws from bStock mainstream, then bStock index, and only then from its BPN Loan market, so the Hub pulls liquidity from the loan last. The deposit queues are unchanged, with the BPN Loan market last. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@multica-review please review this VIP before we take it forward. Main things to check:
|
…IP-676 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d LT For each of the 20 collateral markets, after VIP-678: - borrowing power equals CF x collateral value, and account liquidity LT x value - a loan of the full borrowing power succeeds, and 1 wei more reverts InsufficientLiquidity - 0.01% above the price where LT covers the loan, liquidation reverts InsufficientShortfall; 0.01% below, it succeeds - the loan is then repaid in full Runs after the end-to-end flow, whose exact seed vToken count its liquidations would shift. Values collateral at the market's exchange rate, as the comptroller does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: VIP-676 [BNB Chain] list the BPN Loan Hub-Funded Spoke pool






Summary
Lists the bStock mainstream Hub-Funded Spoke pool on BNB Chain, in the same SpokePoolRegistry as the bStock index pool.
Listing doc: bStock mainstream spoke pool listing
Proposals
vips/vip-675/bscmainnet.tsvips/vip-675/bscmainnet-part-2.tsvips/vip-675/bscmainnet-part-3.tsVIP-677 and VIP-678 need VIP-675 executed first. They do not depend on each other.
Each collateral market gets its own CF, LT, liquidation incentive and supply cap from the listing doc. Where the doc sets a protocol seize share other than the 5% default, the aggregator batch sets it after the market's incentive, since
setProtocolSeizeShareis bounded by that incentive.Permissions
VIP-675 grants all 20 Spoke comptroller roles as wildcards, so later Spoke pools need no ACM grants. It then revokes the scoped grants those wildcards replace: the 20 on the bStock index pool's comptroller and CollateralGateway's
enterMarketForAccounton Core.Deployments
isolated-pools#575:
Comptroller_bStockMainstreamand its 23 markets (vX_bStockMainstream). Every market has the Normal Timelock as owner and shortfall.Before proposing
The risk owner signs off the risk values and supply caps.
Seed the aggregator batches:
Pin the printed indices as
seededIndicesonPART_1,PART_2andPART_3.Move
FORK_BLOCKpast the seeding and re-run the simulation.Status: All three VIPs are seeded and pinned: VIP-675 at indices 5 and 6, VIP-677 at index 7 (seeding transaction), and VIP-678 at index 8 (seeding transaction). Both new batches were read back and matched byte-for-byte against the proposal builders.
Simulation
npx hardhat test simulations/vip-675/bscmainnet.ts --fork bscmainnet: 168 passing at block 131,366,432. All three proposals use their seeded on-chain batches: 5 and 6 for VIP-675, 7 for VIP-677, and 8 for VIP-678. The simulation uses a separate proposer and sufficient supporters because VIP-675 is active at this fork block.It runs all three VIPs, then an end-to-end flow:
At this block the VTreasury holds every seed, all 16 new Atlas feeds authorize AtlasOracle and VIP-673 has executed, so the simulation does not stand in for any of them. It pins direct prices to survive the governance warp, so it checks the feed authorization with
isAuthorizedCallerrather than through a live read.Note