💎 PAY_DIAMOND Deploy Tool — REAL PRODUCTION FACETS ⚠️ MAINNET

Tool v1.0.0

⚠️ REAL DEPLOY — real HolgerPayment production logic, real gas, real consequence. This is NOT the toy tool. Every facet deployed here is real Payment logic (views, admin approval gating, refunds, campaigns, plans, memberships, and the money-moving PaymentCoreFacet). Go through the steps below IN ORDER, at your own pace — every step is independent: you can stop after any step and resume later, nothing is lost (progress auto-saves to this browser). If a contract is already deployed and you know its address, paste it into that step's override field instead of redeploying.
Progress backup
Every resolved address auto-saves to this browser (localStorage key 'payDiamondDeployV1'). Export/Import move progress across devices/browsers; Reset clears everything (asks to confirm).

Step 1 — Connect wallet, verify OWNER + network

Strict OWNER gate, same as every other tool in this project — if the connected wallet isn't exactly OWNER, every deploy/write button stays disabled.

Step 2 — Deploy DiamondCutFacet

Standard EIP-2535 diamondCut facet. No constructor args.

Step 3 — Deploy DiamondLoupeFacet

Standard EIP-2535 loupe facet (facets()/facetAddress()/etc). No constructor args.

Step 4 — Deploy OwnershipFacet

Standard EIP-2535 ownership facet (owner()/transferOwnership()). No constructor args.

Step 5 — Deploy Diamond (needs Step 2's DiamondCutFacet address)

Constructor: (OWNER, DiamondCutFacet address) — DiamondCutFacet's own selector is wired in automatically inside the constructor, per Diamond.sol. This is the address you'll call everything through from here on.

Step 6 — diamondCut: register DiamondLoupeFacet + OwnershipFacet

Calls diamondCut on the Diamond from Step 5 to register Loupe's 4 selectors + Ownership's 2 selectors. Needs Steps 3, 4, 5 done first.

Step 7 — Deploy PaymentViewFacet

Pure reads — isActiveMember()/totalPaid()/etc. Zero state-mutation risk. Real production Payment logic, no constructor args.

Step 8 — Deploy PaymentAdminFacet

Admin wallet/config setters, plus the 3 registration-approval functions folded in per T107: setPlanRequiresApproval/approveMembership/rejectMembership. No constructor args.

Step 9 — Deploy RefundFacet

Refund handling. No constructor args.

Step 10 — Deploy CampaignFacet

Campaign/slot/coupon logic (compiled with viaIR — Stack too deep otherwise). No constructor args.

Step 11 — Deploy PlanFacet

Plan configuration. No constructor args.

Step 12 — Deploy MembershipFacet

Membership state transitions. No constructor args.

Step 13 — Deploy PaymentCoreFacet

⚠️ THE MONEY-MOVING FACET — payForService and friends. Deploy LAST, only once every simpler facet on this Diamond is proven working, per the migration plan's explicit ordering. No constructor args.

Step 14 — diamondCut: register all 7 Payment facets (77 selectors)

Calls diamondCut once with all 7 Payment facets' real function selectors, derived LIVE from each facet's real compiled ABI via ethers.Interface.getFunction(name).selector — never hardcoded/guessed. Verified in advance (T110 compile/verification pass) that all 77 selectors across the 7 facets are distinct — no collisions. Needs Step 5 (Diamond) and all 7 facet addresses (Steps 7–13) done first.

Step 15 — Bootstrap Owner Wallet (REQUIRED — do this before any other admin-gated step)

⚠️ Critical one-time step. PaymentAdminFacet's business-logic ownerWallet field (distinct from the Diamond's own EIP-173 technical owner set in Step 5's constructor) starts at address(0) — every onlyOwner-gated function reverts until this is set. This bootstrapOwnerWallet(address) call is gated by the Diamond's REAL technical owner (LibDiamond.contractOwner()), not by the broken business-field check, and reverts if ownerWallet is already non-zero — so it can only ever run once. Needs Step 5 (Diamond) + Step 8 (PaymentAdminFacet) + Step 14 (diamondCut wiring) done first.

Step 16 — Verify: read facets() through the Diamond

Calls facets() via DiamondLoupeFacet, routed through the Diamond's fallback — displays every registered facet address and how many selectors it owns, so the wiring can be visually confirmed.

Step 17 — Optional: set auto-refund-on-reject (admin setter, T111)

Calls PaymentAdminFacet.setAutoRefundOnReject(bool) through the Diamond. Default on-chain state after deploy is false — this step is entirely optional and can be skipped; the Diamond behaves exactly like a plain deploy until this is explicitly called. When enabled, every future rejectMembership call auto-attempts a refund from the Diamond's own USDC balance regardless of the per-call refund argument. Needs Step 5 (Diamond) + Step 8 (PaymentAdminFacet) + Step 14 (diamondCut wiring) done first. Safe to call again later to flip the toggle either direction — not a one-time setup step.