Skip to content

Index DTF v6: Folio 6.0.0 support against the deployed contracts (0.7.0) - #45

Open
lcamargof wants to merge 26 commits into
mainfrom
feat/index-dtf-v6-support
Open

lcamargof wants to merge 26 commits into
mainfrom
feat/index-dtf-v6-support

Conversation

@lcamargof

@lcamargof lcamargof commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Folio 6.0.0 support for @reserve-protocol/sdk and react-sdk 0.7.0 and dtf-catalog 0.2.0, matched to the deployed 6.0.0 contracts (index-protocol 7d97c80, explorer-verified ABIs committed as fixtures).

  • v6 reads, rebalance and auction builders, settings, upgrade proposals and version registry; v6 deploys default to the production 6.0.0 deployers.
  • endRebalance takes the rebalance nonce on 6.0.0.
  • Subgraph 1.11 fields: v6 fee tables, self fee (selfRevenue), trade allowlist; revenue split accounts for immutable recipients and the self fee.
  • Fixes: CJS entry exported ABIs and the catalog as { default }; deploy-address extraction now only trusts the deployer's own logs; v6 basket proposals reject tokens outside an enabled allowlist.
  • Real-bytecode fork suite on mainnet, Base and BSC: deploy, governed deploy, rebalance, bids at start/mid/end, community auction, close and end.

Breaking: prepareIndexDtfDeployAssetApproval(s) require version; extractIndexDtfDeployedAddress takes the deploy target.

Publish only after the index subgraph prod tag serves 1.11.x — the new queries fail against 1.10.2, and release:ci checks the prod endpoints.

…ion state for v6

Folio 6.0 support across the rebalance surface: generated v6 ABIs, six-argument
startRebalance with nonce and deadline, openAuction with the trailing auction
length, v6 settings setters and deploy/registry ABIs.

Version contract: prepareIndexDtfOpenAuctionArgs, prepareIndexDtfOpenAuction,
buildStartRebalanceArgs and the write-ABI selector require "5.0.0" | "6.0.0"
and reject anything else with a typed error; buildIndexDtfStartRebalance reads
the proxy version when none is passed. v4 stays Register-local by decision.

Auction state: getLatestAuction/getActiveAuction resolve one block and pin
every read to it, compare the auction nonce with the current rebalance nonce,
and use the inclusive bid window Folio enforces. Open-auction inputs reject
non-positive or non-finite prices before the rebalance library runs.
…l rebalance reads in open-auction input

Adds getIndexDtfMaxAuctionLength (namespace, ref, React hook and query key) so
launchers can pass the protocol's required v6 auction length once, and relaxes
prepareIndexDtfOpenAuctionArgs to accept a rebalance read without bidsEnabled,
which the auction math never uses.
@coderabbitai

coderabbitai Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4decedb9-1647-4456-9013-34368c20bc44
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ose the rebalance nonce read

bid, closeAuction, endRebalance, openAuctionUnrestricted and distributeFees take version and
select their ABI through index-dtf/write-version.ts; calldata stays byte-identical across
5.0.0 and 6.0.0 and 4.0.0 is rejected. getIndexDtfRebalanceNonce reads Folio 6.0's
getRebalanceNonce with namespace, ref, query options and hook.
…istry, deployer, settings and revenue proposals, upgrade proposal

Folio 6.0 reads (self fee, immutable fee recipients, trade allowlist, max auction length,
rebalance nonce) and FolioVersionRegistry reads with react-sdk hooks; version-discriminated
deploy builders with an explicit v6 deployer; fee tables validated to FolioLib's rules at build
time and revenue proposals that keep the immutable table; settings proposals for self fee and
the allowlist; the 5.0.0 -> 6.0.0 spell proposal reproduced byte for byte from the sandbox; a
fork smoke that executes the SDK-built v6 deploy, settings and upgrade on the sandbox Anvil.
…al and check auction liveness per block

The sandbox skips the native-v6 authority proposal when the roles are already granted and records
id 0; the fixture parser and the fork smoke treat that as no proposal. The v5 control auction's
liveness is checked against the on-chain window at every fixture block instead of assuming the
window is still open at the pinned state.
Reserve deployed the production 6.0.0 FolioDeployer on mainnet, Base and BSC
before registering it. INDEX_DTF_V6_DEPLOYER_ADDRESS pins them, the v6 deploy
target's deployer becomes an optional override for forks and sandboxes, and
standalone deploy approvals take `version` so their default spender follows
it: a 6.0.0 deploy never approves the 5.0.0 deployer by default.
…nnet, Base and BSC

Opt-in suite (test:smoke:index:fork-real-v6) on disposable, unindexed forks:
ungoverned and governed deploys through the SDK's default v6 deployer, v6
reads, startRebalance -> openAuction -> a bid priced at the auction's end with
exact settled amounts, and registry registration by the role-registry owner.
Sends pin a gas limit: Anvil estimates at one timestamp and can mine the next,
and Folio's unconditional lastFolioFeePoke write then starves the RebalancingLib
delegatecall.
IndexDtf gains version, rebalance.maxAuctionLength, rebalance.tradeAllowlist, fees.immutableRecipients
and fees.selfFee from the index subgraph 1.11.0 schema, and the revenue view folds the immutable table
and the holders' share into the effective distribution. Types were generated from the fork subgraph;
the prod codegen check stays red until the subgraph is deployed.
Rolldown's unbundled CJS output re-exported the module namespace for every ABI module that had both a named and a
default export, so require('@reserve-protocol/sdk').folioV6Abi (and ten other ABIs) was { default: abi } and viem
encoding failed. The ABI modules now only export by name, the v6 alias module is gone, and check:package packs the
tarball and loads it through import and require in CI, the gate and release:ci.
The real 6.0.0 Folio (explorer-verified on mainnet, Base and BSC) is reserve-index-dtf 7d97c80, which binds
endRebalance to a rebalance nonce (Pashov L-05). The ABIs were generated from 18706fb, so the SDK encoded
endRebalance() and every 6.0.0 end-rebalance call reverted. Re-sync the v6 ABIs from 7d97c80, require
rebalanceNonce for 6.0.0 end-rebalance calls (5.0.0 unchanged), replace the test that enshrined v5 bytes for v6,
and compare the generated Folio and FolioDeployer ABIs item for item with the Base Blockscout verified ABIs.
…oyer

extractIndexDtfDeployedAddress took the first FolioDeployed/GovernedFolioDeployed from any emitter, so a basket
token could emit a lookalike during transferFrom (before the deployer's own event) and hand back an attacker-chosen
Folio. Both extractors now take the deploy target, keep only logs from the resolved deployer (the version's deployer
or the v6 override; the chain's governance deployer for staking tokens), and reject receipts where that deployer
names more than one address.
…e allowlist

Folio 6.0 startRebalance reverts Folio__TokenNotAllowlisted for every rebalance token off an enabled allowlist. The
v6 basket builder already reads the Folio for the rebalance nonce; it now also reads the allowlist and fails at
build time instead of producing a proposal that passes the vote and reverts on execution.
…nd map selfRevenue

S7 was generated from the 1.11.0 fork schema, where tradeTokenAllowlist and the legacy governance lists were still
non-null. Regenerate against the 1.11.1 candidate (nullable lists, selfRevenue), map financials.selfRevenue null-safe
(totalRevenue now includes it), and pin the v6 split with the DAO 50% / self 25% / 60-40 example. The index codegen
schema is switchable through INDEX_DTF_SUBGRAPH_SCHEMA; the default stays prod, so graphql:codegen:check fails until
prod serves 1.11.1, and the check no longer rewrites the checked-in types when it fails.
test:smoke:index:fork ran fork-smoke-v6.test.ts, which snapshots, reverts and warps 400 days on the shared sandbox
Anvil (8545); the stack lane runs it while a fork Graph Node indexes that chain, and rewinding under the indexer
killed it. The script keeps its name and now runs only read-only cases (v6 reads pinned to the fixture's state block,
since the lane appends rebalances after recording). The writing cases move to fork-smoke-v6-mutating.test.ts with its
own script, which requires INDEX_DTF_FORK_DISPOSABLE_RPC_URL and refuses port 8545 and the manifest's RPC through the
guard the real-v6 suite already used, now shared from the fixture module.
…ecode of mainnet, Base and BSC

The real-v6 fork suite stopped at one bid at an auction's end. Per chain it now checks the implementation's runtime
code against the explorer-verified 6.0.0, eth_calls every function of the SDK v6 Folio ABI on it (an unknown
selector, like the old endRebalance(), reverts with empty data; every function must return or revert with a decoded
error), and runs startRebalance, a launcher auction with bids at start, mid and end, a no-op close after the end,
openAuctionUnrestricted from a roleless account (rejected before restrictedUntil), an all-available bid, a mid-auction
close and endRebalance(nonce) after a stale nonce is rejected. Prices and bid sizes are recomputed from contract reads
and the final basket must sit within the spot limits. The fixed gas limit now applies only to the sync-modifier
Folio calls the estimation flake affects.
fail() exited the process from inside the try block, so a failing check left its unpacked tarball under
node_modules/.cache, where docs:links then scanned the packed README. fail() now throws so the finally block runs, and
the doc-link walk skips node_modules directories.
…from the CommonJS entry

Comparing export values (not only kinds) between the packed ESM and CJS entries found another interop bug:
require('@reserve-protocol/sdk').dtfCatalog was the catalog module namespace, because the CJS interop for a
re-exported default from an external package hands out module.exports. The catalog now exports the combined catalog by
name and the SDK re-exports that; check:package compares a digest of every non-function export.
…rod subgraph before release

Review follow-ups on the v6 subgraph fields: the effective split now requires the full v6 fee shape and gives the
recipients' pool to the DAO when both tables are empty (distributeFees does); an enabled allowlist without an indexed
token list is left out instead of reading as nothing tradable; revenue fields are documented as raw share amounts.
check:subgraph-endpoints (in release:ci) validates the shipped GraphQL documents against every configured endpoint,
since codegen only checks Base prod and mainnet or BSC could lag the 1.11.1 promotion. The changeset lists the
breaking type and signature changes and the rollout blocker for all three endpoints.
Read the trade allowlist after building the rebalance instead of racing it with the nonce read; document that
endRebalance should carry the nonce of the rebalance being acted on, not a fresh read, and that the lower-level
startRebalance args builder does not check the allowlist; list the React SDK in the extractor changeset (it re-exports
the SDK). The real-v6 suite also pins the Base deployer's verified runtime hash and checks that auction prices bracket
the fixture price; the mutating smoke refuses a fork that reports another chain.
Domain and project pages describe the nonce-bound v6 endRebalance, emitter-checked deploy extraction, the trade
allowlist check, the 1.11.1 subgraph fields and switchable codegen source, the named-export rule for ABIs and the
disposable-fork rule for writing suites. Progress gains the release-fix row, S7 points at it, and the any-emitter
backlog item is closed.
The codegen check restores the checked-in types on every path, including a codegen run that fails after writing one
output. The revenue split documents that it uses the DAO's nominal share (the fee floor can raise it on-chain; floor-
aware math is backlogged). The real-v6 suite pins the startRebalance spot amounts to independently computed 20/80
targets and bounds the final native share within two points, so a wrong target no longer passes.
@lcamargof lcamargof changed the title Index DTF v6: explicit version contract, protocol-accurate auction state, v6 open auction Index DTF v6: Folio 6.0.0 support against the deployed contracts (0.7.0) Oct 1, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants