Skip to content

Support V6 revnets; launch new revnets on V6 - #136

Open
mejango wants to merge 21 commits into
mainfrom
feat/v6
Open

Support V6 revnets; launch new revnets on V6#136
mejango wants to merge 21 commits into
mainfrom
feat/v6

Conversation

@mejango

@mejango mejango commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Juicebox V6 support end-to-end and makes V6 the only version new revnets launch on. Existing V4/V5 revnets remain fully viewable and manageable.

Depends on Bananapus/juice-sdk-v4#25 — this PR pins juice-sdk-core@^3.0.0 / juice-sdk-react@^6.0.0, which publish when that PR merges (changesets). Run yarn install to refresh yarn.lock once they're on npm.

Create flow → V6 only

  • parseDeployData builds the v6 REVDeployer.deployFor args (4-arg overload — the v6 deployer bakes in the multi terminal, router terminal registry, buyback hook, and REVLoans, and deploys a default 721 hook internally). REVConfig uses operator + scopeCashOutsToLocalBalances.
  • Reads JBProjects.creationFee() per chain and sends it as the tx value — v6 requires the exact fee; the ERC-2771 forward request and Relayr bundle carry it (SDK support added in the SDK PR).
  • Sucker configs come from parseSuckerDeployerConfig(..., { version: 6 }) — v6 per-remote-chain CCIP deployers, bytes32 peer/remoteToken shape.
  • Post-deploy redirect and homepage links use /v6:; there was no version picker to remove — the create flow's implicit version flips to 6.

View/manage flows stay multi-version

  • Where v6 renamed or reshaped functions, calls branch on the context version using the SDK's new version-suffixed ABIs: currentSurplusOf (3 surplus hooks), currentReclaimableSurplusOf (same selector-trap noted inline: empty arrays encode identically but the selector differs), borrowFrom, reallocateCollateralFromLoan, borrowableAmountFrom (v6 returns (borrowableNow, borrowableCapacity) — normalized by a new useBorrowableAmountFrom hook), auto-issuance (moved to the new REVOwner contract in v6), and the fixed loan fee (REVLoans.MIN_PREPAID_FEE_PERCENT replaces REVDeployer.FEE).
  • Paying with non-accounting tokens routes through the v6 JBRouterTerminalRegistry (replaces the swap-terminal registries).
  • Bridging: prepare uses the v6 signature (bytes32 beneficiary, opaque metadata) via a minimal vendored v6 sucker ABI. toRemote is unchanged. Manual claim UI for v6 still uses the juicerkle service, which doesn't serve v6 leaf shapes yet (bytes32 beneficiary + metadata) — the keeper auto-processes v6 claims in the meantime.
  • Homepage top-projects query widened to version_in: [5, 6] with per-row version links; $REV links point at the v6 revnet (/v6:eth:3).
  • graphql.schema.json / src/generated/* are regenerated output (yarn generate:gql against the live bendystraw schema).

Verification

  • tsc --noEmit and next build pass against the locally built SDK from the SDK PR.
  • Live Sepolia simulations of the exact args produced by parseDeployData + parseSuckerDeployerConfig({version: 6}) against the deployed v6 REVDeployer, with value = creationFee (1e14 wei): a multichain ETH revnet (Sepolia ↔ OP-Sepolia CCIP sucker, 2 stages, auto-issuance, splits) and a single-chain USDC-reserve revnet both returned a valid (revnetId, hook).

🤖 Generated with Claude Code

- Create flow deploys via the v6 REVDeployer.deployFor (4-arg overload; terminals,
  buyback hook, and loans are baked into the deployer) with the exact JBProjects
  creation fee as msg.value, v6 CCIP sucker deployers, and the v6 ERC-2771
  forwarder for Relayr. New revnets launch on V6 only.
- View/manage flows stay version-aware for existing v4/v5 revnets: version-suffixed
  ABIs where interfaces drifted (currentSurplusOf, currentReclaimableSurplusOf,
  borrowFrom, reallocateCollateralFromLoan, borrowableAmountFrom via a normalizing
  hook, autoIssueFor via REVOwner on v6, REVLoans MIN_PREPAID_FEE_PERCENT in place
  of the removed REVDeployer.FEE).
- Payments in non-accounting tokens route through the v6 JBRouterTerminalRegistry
  (replaces the swap terminal registries).
- Bridge send (sucker prepare) uses the v6 bytes32-beneficiary signature; manual
  v6 claim UI awaits juicerkle v6 support (the keeper auto-processes v6 claims).
- Homepage top projects include v5 and v6 groups and link per-row by version;
  $REV links point at the v6 revnet.
- Requires juice-sdk-core ^3.0.0 and juice-sdk-react ^6.0.0
  (Bananapus/juice-sdk-v4#25); run yarn install once those are published.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
revnet-app Ready Ready Preview Jul 21, 2026 10:24pm

Request Review

The juice-sdk-core/juice-sdk-react npm names aren't publishable by the team;
the SDK now ships under the @Bananapus scope at 1.0.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mejango

mejango commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Update: the SDK is being republished as @bananapus/nana-sdk-core@1.0.0 / @bananapus/nana-sdk-react@1.0.0 (Bananapus/juice-sdk-v4#27) since the old npm names aren't publishable. This PR now imports from the scoped names and pins ^1.0.0. Once #27 merges and the Release workflow publishes, run yarn install here to refresh the lockfile and Vercel should go green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Migrate the app's hand-rolled V6 protocol logic onto the SDK's
framework-agnostic action layer (nana-sdk-core 1.1.x, nana-sdk-react 2.0.0):

- BridgeDialog: build the v6 sucker `prepare` request with
  buildBridgePrepareTx (handles bytes32 beneficiary padding + zeroHash
  metadata); delete the local jbSuckerV6Abi copy in favor of the SDK's.
- create/page: read the project creation fee via getProjectCreationFee and
  drive encodeFunctionData / gas estimate / Relayr from the request returned
  by parseDeployData.
- parseDeployData: build stages with buildRevnetStageConfig, the reserve
  asset context with buildAccountingContext (token-keyed currency computed
  by the builder), and return a buildDeployRevnetTx request. Split-group
  percents now run through fillSplitPercents, fixing a latent revert when
  per-row rounding drifted the group away from an exact 1e9 total.
- useBorrowDialog: v6 borrowFrom / reallocateCollateralFromLoan writes go
  through buildBorrowTx / buildReallocateCollateralTx.
- AutoIssuance: v6 branch uses buildAutoIssueTx.
- paymentTerminal: v6 resolution goes through resolvePaymentTerminal
  (router-registry fallback); v4/v5 logic untouched.
- tsconfig: moduleResolution "node" -> "bundler" so the package's /v6
  subpath export resolves (webpack already resolved it; tsc now does too).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mejango

mejango commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up commit c43e79b migrates the app's hand-rolled v6 protocol logic onto the SDK's new @bananapus/nana-sdk-core/v6 action layer (deps bumped to core ^1.1.0 / react ^2.0.0): sucker bridge prepare, creation-fee read, the whole revnet deploy encode (buildDeployRevnetTx/buildRevnetStageConfig), borrow/reallocate writes, auto-issuance, and v6 terminal resolution. A differential test showed byte-identical deployFor calldata vs the old implementation — except split groups, which previously could sum to 999,999,999 (on-chain revert) and now sum to exactly 1e9 via fillSplitPercents. Requests now carry chainId, so wagmi enforces the target chain on writes.

Bump @bananapus/nana-sdk-core to ^1.3.0 and @bananapus/nana-sdk-react to
^4.0.0 (v6 action-layer review fixes, native-bridge sucker option, 721 shop
helpers).

Pays on v6 now support any-token payments (USDC alongside ETH):
- resolveBestV6PayRoute previews both the multi terminal and the router
  terminal registry via previewPayFor and keeps whichever mints the most
  project tokens, so a surviving route always carries a live quote
  (verified against Sepolia: ETH ties resolve to the direct multi terminal;
  USDC pays to native-context projects route through the registry).
- Pay-time v6 flow re-resolves the route and encodes minReturnedTokens from
  the fresh preview (1% slippage floor that never rounds a positive quote
  to zero); legacy multi-terminal non-native pays keep a 5% floor while
  swap-terminal pays stay at 0.
- v4/v5 issuance quotes now replicate JBTerminalStore.recordPaymentFrom
  exactly: 1:1 when the payment currency matches the ruleset base currency,
  else the live JBPrices.pricePerUnitOf feed, replacing the hard-coded
  ETH/USD heuristics.
- useProjectBaseToken is memoized, carries the accounting-context currency
  id, and pins USDC reserve assets to 6 decimals; PayForm keeps the selected
  pay token referentially stable (fixes a setState loop), clears stale
  quotes, and hands the raw quoted bigint to the pay dialog instead of a
  format(3) round-trip.
- Cross-token USDC is only offered as a pay option on v6; USDC-base v5
  projects still pay in their own base token.
- Fix ERC-20 pay metadata: "0x0" is odd-length hex and viem rejects it.

Ports and hardens the v6 USDC payment work from d2things/revnet-fork
(v6-integration).

Co-authored-by: cryorepository <cryorepository@protonmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mejango

mejango commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Commit 20eb433 brings the branch to ship-readiness: SDK bumped to core 1.3.0 / react 4.0.0 (action-layer review fixes, native-bridge sucker option, 721 shop helpers), and v6 pays now support USDC/any-token: resolveBestV6PayRoute previews both the multi terminal and the router terminal registry and keeps the route minting the most project tokens, with minReturnedTokens encoded from a fresh on-chain preview at pay time. v4/v5 issuance quotes now replicate JBTerminalStore.recordPaymentFrom math via live JBPrices feeds instead of hard-coded ETH/USD heuristics. Verified against live Sepolia: ETH pays tie-break to the direct multi terminal; USDC pays to native-context projects route through the registry.

This ports and hardens the v6 USDC work from d2things/revnet-forkv6-integration (thanks @d2things). Not taken from the fork (regressions): reverting v6 prepare to the v5 signature, hand-rolled borrow/reallocate args, a v6 REVDeployer.FEE read (moved to REVLoans.MIN_PREPAID_FEE_PERCENT in v6), dropping the v5 terminal-store ABI (different selector), and [NATIVE_TOKEN] in the reclaim quote (v6 treats an empty token list as all tokens).

mejango and others added 3 commits July 21, 2026 11:08
v6 projects get the full tab set (Overview | Terms | Owners | Shop | Extras |
Operator); Ops folds into Owners for v6 and redirects. Earlier versions keep
their existing pages untouched.

Foundation pieces:
- src/lib/v6/suckerProofs.ts: juicerkle-free bridge-claim support ported from
  website/ — outbox reconstruction from InsertToOutboxTree logs, depth-32
  MerkleLib tree rebuild, per-leaf status from live outbox/inbox/executed-leaf
  reads, locally VERIFIED proofs (throws rather than surfacing an unverified
  claim), unmapped-token recovery, and toRemote fee discovery (native = exact
  registry fee; CCIP = simulated budget ladder with on-chain refund).
- src/lib/v6/componentSpecs.ts: website/'s COMPONENT_SPECS registry ported
  verbatim (incl. the 8 hardened overrides) for the [copy build prompt] system.
- BuildPromptFooter: the [copy build prompt] affordance for every v6 card.

Merkle port verified against the canonical depth-32 empty root (0x27ae5ba0…)
and proof/root self-consistency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v6 projects get website/'s complete revnet surface; v4/v5 pages are untouched
(menu, routes, pay card, and permission ids all branch on version).

Pay card (v6): Pay / Add-to-balance modes, chain selector, accepted tokens
resolved from on-chain accounting contexts plus router-probed ETH/USDC,
debounced live previews, fail-closed 99% minReturnedTokens from a fresh
pay-time preview, ERC-20 approvals against the resolved terminal, simulate-
first sends, a confirm dialog with decoded args + raw calldata, and a 721
shop strip sharing one cart with the Shop tab (credits, METADATA_ID_TARGET-
keyed metadata, credit-only checkout).

Tabs: Overview (about + per-chain ids/operator panel); Terms (issuance card
with cut countdown, stepped SVG schedule, stages table incl. auto-issuance
totals and cash-out tax); Owners with Accounts | Market | Settlement |
Splits | Auto issuance | Loans subtabs — You card (per-chain balances,
cash-out values, max loan, cash-out-delay locks) with cash out / borrow /
move / claim-credits actions, holders pie+table, all-loans + your-loans,
market AMM card (buyback pool resolved through the ruleset data hook, exact
composition from replayed liquidity deltas) and LP split-hook card (collect
fees / deploy pool); Settlement with across-chains composition, bridges,
gossip freshness + simulate-first sync, and queued movements with LOCAL
merkle-proof claims (no juicerkle) and fee-discovered toRemote execution;
Shop (inventory grid, tier detail, operator add-items with per-tier reserve
beneficiaries, customers/purchases feeds on the SDK 1.3 shop helpers);
Extras (payer-address deploys + indexed payer list); Operator (account card
with Safe/EOA detection + operator transfer via REVOwner, edits card,
buyback & router card with the three registry writes, permissions card on
the v6 id numbering).

Cross-cutting fix: useUserPermissions resolved permission ids from the v5
map for every version — v6 renumbered them (SET_PROJECT_URI 6→7,
SET_SPLIT_GROUPS 17→19, ADJUST_721_TIERS 20→24), so v6 operators saw
edit affordances hidden or wrongly shown. Now version-aware via the SDK's
JBPermissionIdsV6.

Every card carries website/'s [copy build prompt] affordance backed by the
verbatim-ported COMPONENT_SPECS registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mejango and others added 2 commits July 21, 2026 12:00
… build prompts

- ProjectProviders: with no API key in NEXT_PUBLIC_BENDYSTRAW_URL the SDK
  posted client-side queries to the bare bendystraw origin, which 404s —
  every client query (activity, owners, splits) spun forever. Pass
  "graphql" as the path so keyless setups land on the public endpoint on
  both networks.
- v6 renders the issuance/cash-out price chart inside the Overview tab
  (website/ parity); v4/v5 keep it in the layout.
- Remove the [copy build prompt] system from the site.
- Settlement: single-chain projects now explain why there are no bridges/
  gossip/movements instead of silently hiding the sections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Pay card: restore the legacy PayForm block-stack design (mode dropdown in
  the old label slot, You-get block, splits strip, memo + teal Pay button)
  while keeping all v6 functionality; chain selection and connect/switch
  prompts move back into the confirm dialog — fixes the spurious
  "Switch to Base" in the card (ButtonWithWallet compares against wagmi's
  default-chain fallback when disconnected). Confirm re-prepares from a
  fresh route + preview after in-dialog connect/chain-switch.
- Activity feed: v6 renders all indexed event types (add-to-balance, mints/
  auto-issue with same-tx dedupe, ERC-20 deploy, ruleset queues, transfers,
  permissions, buyback pool) with amounts in the accounting token's own
  decimals; v4/v5 output unchanged. Verified against live indexer data.
- Terms: the issuance unit no longer renders "/ undefined" for accounting-
  context currencies — v6 resolves the unit from the on-chain accounting
  context (USDC et al); charts de-chunked to the site's existing chart
  chrome (true 2px strokes, dashed gridlines, quiet range pills, hover-only
  marker).
- Owners You card: cash-out and max-loan quotes now pass the accounting
  context's own currency id + decimals (USDC-base projects previously
  reverted with 18/ETH args and rendered "—"); proven against live Base
  reads for Artizen.
- Revert the "graphql" apiKey fallback: the SDK appends /graphql itself,
  so the keyless empty-string extraction was already correct — the
  fallback produced /graphql/graphql 401s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The public bendystraw endpoints answer browsers with a fixed CORS
allowlist, so the SDK's client-side queries (activity, owners, splits,
operator panels) were silently blocked from any non-allowlisted origin —
localhost included — while server-side fetches worked, which is why the
pages half-rendered. juicebox-money-v6 never hits this because it queries
bendystraw from the server.

Client queries now go through /api/bendystraw/<net>/<key>/graphql, a
same-origin route that forwards server-side (mainnet/testnet chosen from
the project's chain; "public" stands in for a missing API key since the
SDK splices the key into the URL path). The URL is anchored to
window.location.origin because graphql-request rejects relative URLs.

Verified headless against Banny Network (v6:eth:4): activity feed renders
(343 events), owners table lists holders (154 participants), and the
Other-info operator column resolves team.banny.eth per chain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Banny-class resolvers return metadata whose image is an SVG data-URI that
merely wraps an external <image href="…ipfs…"> — browsers refuse external
loads inside an <img> data URI, so those tiers rendered broken (pay strip)
or as a Media badge (shop tab, which classified the extension-less gateway
URL as non-image). One shared resolution chain now serves both surfaces:
unwrap wrapper SVGs to their underlying asset, default image-field URLs to
images, and re-route any ipfs:// or foreign-gateway URL through the app.

New /api/ipfs/[...path] route fronts the gateway: tier grids request dozens
of cold assets at once and the upstream throttles parallel browser fetches;
CID content is immutable so responses cache forever (browser, Next data
cache, CDN). Tier thumbs stay lazy-loaded.

Verified live against Banny Network (v6:eth:4): 68/68 tiers resolve by
script, 72/72 rendered images load in the browser after scroll.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Splits subtab rebuilt: every chain's split table inline for the selected
  stage (jbm-v6 presentation) instead of one chain behind a dropdown. The
  "Operator is currently" line now resolves the real revnet operator from
  the indexer — it previously showed the FIRST split's beneficiary, which
  is the zero address whenever the split routes to a hook. Split rows
  render the hook address (tagged "(hook)") when a split routes to one —
  Banny's reserved split pays the LP split hook, not a beneficiary — and
  tag the 0xdead burn sentinel. Per-chain pending balances + Distribute.
- Auto issuance rebuilt as one table across the whole group (Chain | Stage
  | Account | Amount | Unlock date | Distribute) — it previously showed
  only the connected chain's rows. Stage numbers and unlock dates map each
  row's stageId against that CHAIN'S own ruleset list; Distribute targets
  the row's chain. Verified on Banny: 16 rows across 4 chains.
- Operator tab: buyback/router card collapses identical per-chain values to
  one value + "Same on all chains"; "reserved splits" copy is now "splits".

Permissions card slowness was the bendystraw CORS block, fixed by the
same-origin proxy in 24a98b8 — the query answers immediately now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The card is one bordered container: the 721 shop strip sits inside it,
  flush at the edges, on the same zinc-100 gray as the pay block; inner
  blocks keep only bottom dividers and the memo row joins the card.
- "Pay ▾ on <chain> ▾" header (website/ parity): the chain dropdown moves
  into the card header next to the mode select (static label when the
  project is single-chain); the confirm dialog's selector stays in sync
  through the same selected-sucker context.
- Shop tiles show media + price only (names live in the Shop tab).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Thumbs go edge-to-edge (square, no padding) with only the price below,
and tier media fits by containment so tall art scales to the largest
un-cropped size.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mejango and others added 2 commits July 21, 2026 13:30
- Supply next to the stepper names the chain ("10,000 left on Ethereum")
  instead of the ambiguous "left here".
- Category shows its name when the metadata carries one (General /
  Category N fallback), not the raw id.
- The current discount joins the facts list alongside the price badge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Voting power stays in the tier detail modal; the grid card keeps just the
reserve-mint note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Art sits on white; the info areas (card footer, detail facts pane) take
the light gray.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The scroller escapes the section padding (full bleed under the card
edges) while resting tiles keep the default inset, and extra bottom
padding keeps the overlay scrollbar off the tiles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tab row carries a full-width rule (jbm-style); the active tab's
2px teal border sits on it via -mb-px, matching the subtab underline
height. Applies to v4/v5 and v6 rows alike.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant