Skip to content

Stop RevNet v5 fund routing, interim 100% beneficiary split + v6 upgrade path #4

Description

@pglavin2

Stop RevNet v5 fund routing — interim 100% beneficiary split + v6 upgrade path

Background

The Markee RevNet on Juicebox v5 has a known vulnerability. This issue covers the full migration: stop routing funds to the v5 terminal immediately, route 100% to each Markee's configured beneficiary address in the interim, and restructure contracts + frontend so switching to v6 requires only admin config calls — no code changes, no redeployment.

This is also an opportunity to standardize all contracts on the v1.0 architecture (direct RPC, no subgraph dependency) and fully deprecate the subgraph once migrations are complete.


Current architecture

All three active strategy contracts (TopDawgStrategy, TopDawgPartnerStrategy, FixedPriceStrategy) route funds to the v5 RevNet terminal (0x2dB6d704058E552DeFE415753465df8dF0361846) via IJBMultiTerminal.pay().

Contract Current behavior Indexing
TopDawgPartnerStrategy 62% to partner beneficiary, 38% to RevNet. beneficiaryAddress and percentToBeneficiary are mutable. Subgraph
TopDawgStrategy 100% to RevNet. No beneficiary split. revNetTerminal / revNetProjectId are immutable. Subgraph
FixedPriceStrategy 100% to RevNet. No beneficiary address. revNetTerminal / revNetProjectId are immutable. Subgraph
v1.0 Leaderboard.sol 62/38 split, immutable RevNet config. percentToBeneficiary is mutable (admin access confirmed). Direct RPC

Goals

  1. Immediate: Stop all ETH flowing to 0x2dB6d704058E552DeFE415753465df8dF0361846 from every Markee contract
  2. Interim: Route 100% of funds to the beneficiaryAddress configured on each Markee
  3. Standardize: All redeployed contracts use v1.0 architecture — direct RPC, no subgraph dependency
  4. Preserve history: New deployments seed historical state (total funds, message count, last owner/message) from legacy contracts via a one-time initializeHistory() admin function
  5. Forward-compatible: The v6 upgrade is a targeted admin config update — no code changes, no redeployment

Immediate stopgap (no redeployment required)

Legacy strategy contracts (TopDawgPartnerStrategy instances)

TopDawgPartnerStrategy already has an if (revNetAmount > 0) guard that skips the RevNet call when the amount is zero, and a mutable percentToBeneficiary with an admin setter.

Action: Call setPercentToBeneficiary(10000) on each deployed TopDawgPartnerStrategy instance today. Routes 100% to the existing partner beneficiary address; RevNet call is skipped cleanly.

v1.0 contracts (Leaderboard.sol instances)

Admin access confirmed and percentToBeneficiary is mutable on v1.0.

Action: Call the equivalent percent setter on each deployed v1.0 Leaderboard instance to route 100% to the configured beneficiary. No redeployment needed. These contracts stay in place and are not replaced as part of this migration.

TopDawgStrategy and FixedPriceStrategy have immutable RevNet config — they require new deployments (see below).


Contract changes

Shared: history preservation via initializeHistory()

All new contract deployments must include a one-time admin function to seed historical state from the legacy contract being replaced:

function initializeHistory(
    uint256 _totalFundsRaised,
    uint256 _totalMessagesBought,
    address _lastMessageOwner,
    string calldata _lastMessage
) external onlyAdmin {
    require(!historyInitialized, "Already initialized");
    totalFundsRaised = _totalFundsRaised;
    totalMessagesBought = _totalMessagesBought;
    lastMessageOwner = _lastMessageOwner;
    lastMessage = _lastMessage;
    historyInitialized = true;
}
  • Call immediately after deployment, before going live
  • Values are read from the legacy contract (or subgraph) at migration time
  • historyInitialized flag makes this a one-time operation — cannot be overwritten
  • This same pattern carries forward to v6: initializeHistory() seeds the v6 contract from the v1.0 deployment's final state

TopDawgStrategy.sol — new deployment required

Current: routes 100% to RevNet, no beneficiary split, revNetTerminal/revNetProjectId are immutable. Indexed via subgraph.

Changes:

  • Rewrite as v1.0-style contract (direct RPC, no subgraph)
  • Change revNetTerminal and revNetProjectId from immutable to mutable storage variables
  • Add admin setters: setRevNetTerminal(address) and setRevNetProjectId(uint256)
  • Add address public beneficiaryAddress (set to Markee Cooperative multisig 0xAf4401E765dFf079aB6021BBb8d46E53E27613DB at deployment) + setBeneficiaryAddress(address) setter
  • Add uint256 public percentToBeneficiary (basis points) + setPercentToBeneficiary(uint256) setter
  • Add bool public revNetEnabled (default false) + setRevNetEnabled(bool) setter
  • Add initializeHistory() (see above)
  • Update _splitAndDistributeFunds():
    • When revNetEnabled == false: send 100% to beneficiaryAddress, skip RevNet call
    • When revNetEnabled == true: apply percentToBeneficiary split, call RevNet with remainder (same if (revNetAmount > 0) guard as partner strategy)
  • Deploy new instances; seed history; migrate all existing Markees via changePricingStrategy() on Markee.sol

TopDawgPartnerStrategy.sol — new deployment required for v6 readiness

Stopgap available now: Call setPercentToBeneficiary(10000) on each deployed instance.

For proper fix (needed for v6 switchover):

  • Rewrite as v1.0-style contract (direct RPC, no subgraph)
  • Change revNetTerminal and revNetProjectId from immutable to mutable storage variables
  • Add admin setters: setRevNetTerminal(address) and setRevNetProjectId(uint256)
  • Add bool public revNetEnabled (default false) + setRevNetEnabled(bool) setter
  • Add initializeHistory() (see above)
  • Update _splitAndDistributeFunds() to explicitly skip RevNet call when revNetEnabled == false
  • Deploy new instances; seed history; migrate

FixedPriceStrategy.sol — new deployment required

Current: routes 100% to RevNet, no beneficiary address. Indexed via subgraph.

Changes:

  • Rewrite as v1.0-style contract (direct RPC, no subgraph)
  • Same mutable revNetTerminal / revNetProjectId + setters
  • Add address public beneficiaryAddress + setter
  • Add bool public revNetEnabled (default false) + setter
  • Add initializeHistory() (see above)
  • Update changeMessage() payment logic: when revNetEnabled == false, send full msg.value to beneficiaryAddress; when revNetEnabled == true, call RevNet with full amount (or apply split ratio if added later)
  • Deploy new instances; seed history; update CONTRACTS config in frontend

v1.0 contracts (Markee.sol, Leaderboard.sol, LeaderboardFactory.sol)

Admin access confirmed. percentToBeneficiary is mutable — using Option B stopgap, no redeployment needed.

Action: Call the percent setter on each deployed Leaderboard instance to route 100% to the configured beneficiary. These contracts stay in place and are not replaced as part of this migration.


Migration sequence per contract

For each legacy strategy contract being redeployed:

  1. Read current state from legacy contract: totalFundsRaised, totalMessagesBought, lastMessageOwner, lastMessage
  2. Deploy new contract
  3. Call initializeHistory() with values from step 1
  4. Call setPercentToBeneficiary(10000) (interim — 100% to beneficiary)
  5. Call setBeneficiaryAddress(...) to configure the correct address
  6. Confirm revNetEnabled is false (should be default)
  7. Migrate Markee instances to the new strategy via changePricingStrategy()
  8. Update CONTRACTS config in frontend
  9. Verify no funds reach 0x2dB6d704058E552DeFE415753465df8dF0361846

Frontend changes

frontend/lib/contracts/addresses.ts

  • Remove the REVNET_CONFIG block (project IDs 119/63/62/56 per chain, JB_TERMINAL address)
  • Add a REVNET_V6_CONFIG block (commented out / empty) as a placeholder — v6 cutover becomes a one-line fill-in
  • Update strategy contract addresses in CONTRACTS once new contracts are deployed

frontend/components/modals/BuyMessageModal.tsx

  • Remove the PHASES array (token emission rate schedule, lines 79–99) and calculateMarkeeTokens() function
  • Remove "You'll receive X MARKEE tokens" display from the modal UI
  • Update revenue split display: "62% [beneficiary] / 38% Markee Cooperative""100% [beneficiary]"
  • Remove useReadContract call for beneficiaryAddress if no longer needed for token calc

frontend/components/modals/TopDawgModal.tsx

  • Remove calculateMarkeeTokens() and all token emission phase logic (lines 92–104)
  • Remove "MARKEE tokens" display from bid confirmation UI
  • Update split display copy to reflect 100% to beneficiary

frontend/lib/contracts/usePartnerMarkees.ts

  • Update fundingSplit strings: "62% to [Partner] / 38% to Markee Cooperative""100% to [Partner]"
  • Remove or set percentToBeneficiary to 10000 in partner config objects

frontend/app/how-it-works/page.tsx

  • Remove or replace "View token terms on Revnets" link (line 391, revnet.app/v5:base:119/terms)
  • Remove or replace "See project on Revnets" link (line 403)
  • Update the RevNet FAQ section (lines 398–406): explain that MARKEE token issuance is temporarily paused while RevNet v5 is replaced with v6; link to announcement once available
  • Remove any copy describing the 62/38 split as permanent or immutable

frontend/app/owners/page.tsx

  • Remove RevNet v5 links (lines 81 and 129, both pointing to revnet.app/v5:base:119)
  • Replace with a placeholder note: "v6 RevNet coming soon"

frontend/components/wallet/TokenBalance.tsx

  • Keep this component — users still hold pre-pause tokens
  • Remove or update the broken ops link (line 64, app.revnet.eth.sucks/v5:base:119/ops)
  • Replace link with static text or a "v6 coming soon" note

frontend/app/api/openinternet/leaderboards/route.ts

  • Update percentToBeneficiary values in server-side leaderboard config to 10000 where applicable
  • Remove any RevNet-specific config fields

Subgraph deprecation

All redeployed contracts use v1.0 architecture and are indexed via direct RPC — no subgraph dependency. Once all legacy strategy contract instances are migrated:

  1. Confirm no active Markees still point to subgraph-indexed contracts
  2. Remove subgraph queries from frontend (Apollo Client calls, useQuery hooks referencing subgraph data)
  3. Archive the subgraph — do not redeploy or update
  4. Remove subgraph-related env vars and config from the frontend once confirmed clean

The subgraph does not need schema updates as part of this migration — it will simply stop receiving new events once legacy contracts are migrated off.


V6 upgrade path

Once v6 RevNet is deployed, the full cutover is admin calls only — no code changes, no redeployment:

  1. Call setRevNetTerminal(v6TerminalAddress) on each strategy contract
  2. Call setRevNetProjectId(v6ProjectId) on each strategy contract
  3. Call setPercentToBeneficiary(splitRatio) to restore the desired split (e.g. 6200 for 62/38)
  4. Call setRevNetEnabled(true) on each strategy contract
  5. Populate REVNET_V6_CONFIG in addresses.ts with new project IDs
  6. Re-add MARKEE token issuance display in modal components
  7. For any v1.0 Leaderboard contracts still active at v6 time: read their current state, deploy v6-ready replacement, call initializeHistory() with current values, migrate

Out of scope

  • Actual v6 RevNet deployment or configuration
  • Changes to the MARKEE token address or supply schedule
  • Changes to the ecosystem / Superfluid / GitHub integration APIs

Acceptance criteria

  • No ETH flows to 0x2dB6d704058E552DeFE415753465df8dF0361846 (v5 terminal) from any Markee contract
  • 100% of funds reach the configured beneficiaryAddress for each Markee
  • Non-partner Markees route to Markee Cooperative multisig 0xAf4401E765dFf079aB6021BBb8d46E53E27613DB
  • All frontend UI correctly shows 100% to beneficiary (no "38% Markee Cooperative" split display)
  • No broken RevNet v5 links in the UI
  • MARKEE token issuance UI is cleanly removed or replaced with an interim message
  • TokenBalance.tsx kept; broken ops link removed or replaced
  • New contracts have mutable revNetTerminal / revNetProjectId + revNetEnabled flag
  • New contracts include initializeHistory(); history is seeded before going live
  • historyInitialized flag prevents re-seeding
  • All redeployed contracts use v1.0 architecture (direct RPC, no subgraph)
  • Subgraph decommissioned once all legacy instances are migrated
  • V6 upgrade is achievable via admin calls only — no code changes, no redeployment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions