⬆️ PAY_DIAMOND Upgrade Tool — REAL PRODUCTION UPGRADE ⚠️ MAINNET

Tool v1.5.2 · Facet bundle v8.14.0

⚠️ REAL UPGRADE — targets the ALREADY-LIVE PAY_DIAMOND, real member data, real gas, real consequence. This is NOT the fresh-deploy tool (pay-diamond-deploy.html) — that tool only ever ADDS facets to a brand-new Diamond. This tool REPLACES facets on a Diamond that is already serving real traffic. Go through the steps below IN ORDER, at your own pace — every step is independent and resumable (progress auto-saves to this browser). Step 10 (the actual diamondCut) is the one irreversible on-chain wiring change — review the Replace/Add/Remove counts on that step carefully before confirming in your wallet.
Progress backup
Every resolved address auto-saves to this browser (localStorage key 'payDiamondUpgradeV1'). 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 — Set the ALREADY-LIVE PAY_DIAMOND address

Pre-filled with the real T119 mainnet address from 2026-07-19_Diamond_Contract_Reference_MAINNET_v1.md. Edit only if PAY_DIAMOND is ever redeployed and this address changes.

Steps 3-9 — Deploy the 7 NEW v8.12.0 Payment facets

Each is a fresh, standalone deploy of the updated facet source (T181 PlanTierHierarchy batch — tierRank, linkedAnnualPlanId, on-chain descriptionPoints — redeployed on top of the currently-live v8.10.0 Diamond) — no constructor args. Same manual-override/resumable pattern as pay-diamond-deploy.html: paste a known address to skip redeploying.
Step 3 — PaymentViewFacet (new: getMaintenanceMode, getMemberLockedPlanPrice, getMemberLockSnapshotInfo, getRegistrationPlanId (T173) — 5,724 → 5,789 deployed bytes)
Step 4 — PaymentAdminFacet (new T190 MigrationGapSetters: setMemberReferralId(address,uint256), setCreditExpiry(address,uint256), setMemberLockedPlanPrice(address,uint8,uint256), setMemberLockSnapshotMeta(address,bool,uint256), setHasEverPurchasedPlan(address,uint8,bool) — 5 real Add selectors; ~10,312 → 11,616 deployed bytes)
Step 5 — RefundFacet (new: addCreditNoteWithExpiry, addCreditNoteWithExpiryBatch)
Step 6 — CampaignFacet (version-tag-only for v8.12.0 too — confirmed by real compile: bytecode identical to the live v8.11.0 CampaignFacet except the trailing solc metadata hash; no ABI/selector change)
Step 7 — PlanFacet (⚠️ createPlan/updatePlan signatures CHANGED AGAIN — new trailing tierRank/linkedAnnualPlanId params (T181) mean NEW selectors vs the currently-live v8.10.0 PlanFacet, old ones removed; also gains the brand-new setPlanDescription(uint8,string[]) function — see Step 10)
Step 8 — MembershipFacet (new: deactivateMember(Batch), reactivateMember(Batch), resetMember(Batch) — T189)
Step 9 — PaymentCoreFacet (proration engine, partial-payment rate-capping, price-lock snapshot integration, now also carries the new first-vs-repeat-purchase renewalDurationSeconds branch via inlined PaymentStorage.updateMemberOnPayment — no ABI change, largest facet, 15,597/24,576 bytes)

Step 10 — diamondCut UPGRADE (Replace + Add + Remove)

New at T189d, fixed at T190 (tool v1.4.1): categorization no longer trusts a hand-typed snapshot for the one question that matters most — "does this selector already exist on the live Diamond right now?" Click "REFRESH LIVE SELECTORS FROM CHAIN" first — a free, read-only facets() call straight to the real PAY_DIAMOND — to pull the actual current selector set directly from chain state. COMPUTE CUT now builds Replace/Add AND Remove against THAT live data, not the static OLD_SELECTOR_SET array (which is used only to label selectors with their function name/facet for display, and for the T188b same-name drift check — never to decide existence or removal). This is the direct fix for the failure class that caused both T188's revert ("Add" for a selector the chain already had) and T190's revert ("Remove" for a selector the chain no longer had, because the Remove list was still built from the stale static snapshot until this fix).

Step 11 — Verify

Calls facets() through the live Diamond and shows every registered facet address + selector count, so the upgrade can be visually confirmed.