Steps 4–5 · Relay Distribution
The bundle must not be traceable to one funding transaction. Wallet 0 splits the budget across every bundle wallet through relay.link, on your schedule.
Step 4 — Choose the window
Enter the total duration in hours (e.g. 0.5 = 30 min) and click Build plan. The app reads wallet 0's live balance on the source chain and generates a plan:
- Amounts — randomized around the average share, within ±30%
- Timing — Poisson-spaced intervals rescaled to fill your window, with a randomized gap between every transfer
- Routing — each entry is a relay.link cross-chain transfer into a different bundle wallet
The plan is persisted in localStorage (jb:fundplan) — inspectable, resumable, and it survives a closed tab.
Step 5 — Execute
Click Execute. The vault must be unlocked (the app asks for the password if needed). A one-time platform fee of $20 gates the first execution: pay it in USDC, USDT or USDG on Ethereum, Base or Robinhood to the fee address shown in the app. You can send it straight from wallet 0 (USDC/USDT on Ethereum or Base) or pay from any external wallet and paste the tx hash; the app verifies the transfer on-chain (token symbol, decimals, amount and recipient all checked against the receipt) and remembers the payment per vault (`jb:fee:
- Each transfer goes
pending → sending → confirmed(orerror) - Every send re-quotes relay.link just before broadcasting — the plan-time quote is hours old by then
- Failed entries are retried on the next run — the per-entry journal makes the whole job crash-safe
- The Setup step flips
runningwhile it works anddoneonly when every entry is confirmed
fromBalance mode means the plan always matches wallet 0's real balance — an empty funder refuses at plan time, not mid-execution.
Keep the tab open while the window runs. If you close it anyway, the next open detects the interrupted plan (JBFund.wasInterrupted()) and JBFund.resume() re-spreads the overdue sends over the remaining window — ambiguous entries go back to pending, so check the explorer before resuming if a transaction may have gone out.
In the browser
| Call | Notes |
|---|---|
JBFund.buildPlan({hours, fromBalance, srcChain, sourceIndex}) | srcChain accepts 8453, 1, or 42161 |
JBFund.execute({dryRun}) | requires unlocked vault and a verified fee payment; dryRun: true quotes everything, signs nothing |
JBFee.pay({chainId, symbol}) / JBFee.verifyTx(txHash, chainId) | the $20 platform fee: in-app payment from wallet 0, or on-chain verification of an external payment |
JBFund.planStatus() | {total, byStatus, etaSeconds} — step-5 completion is derived from this, never from a flag you could fake |
Until this is done
Launch remains locked: the pipeline gate counts confirmed plan entries, and the launch wizard stays closed while any entry is unconfirmed.