💎 AFF_DIAMOND Deploy Tool — REAL PRODUCTION FACETS ⚠️ MAINNET

⚠️ REAL DEPLOY — real HolgerAffiliate production logic, real gas, real consequence. This is NOT the toy tool. Every facet deployed here is real Affiliate logic (views, admin config, payout release, and the core commission-accrual/tier logic). 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 'affDiamondDeployV1'). 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 AffiliateViewFacet

Pure reads — getAffiliateData()/getRate()/etc. Zero state-mutation risk. Real production Affiliate logic, no constructor args.

Step 8 — Deploy AffiliateAdminFacet

Admin wallet/config setters, tier-rate config, plus setPaymentContract — the cross-Diamond wiring setter that points this Diamond back at PAY_DIAMOND (confirmed present T113). No constructor args.

Step 9 — Deploy AffiliatePayoutFacet

Commission release/payout handling. No constructor args.

Step 10 — Deploy AffiliateCoreFacet

⚠️ THE MONEY-MOVING FACET — commission accrual entry points, called from PAY_DIAMOND once cross-wired. Deploy LAST, only once every simpler facet on this Diamond is proven working, per the migration plan's explicit ordering. No constructor args.

Step 11 — diamondCut: register all 4 Affiliate facets (30 selectors)

Calls diamondCut once with all 4 Affiliate 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 (T114 compile/verification pass) that all 30 selectors across the 4 facets are distinct — no collisions. Needs Step 5 (Diamond) and all 4 facet addresses (Steps 7–10) done first.

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

⚠️ Critical one-time step. AffiliateAdminFacet'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 (AffiliateAdminFacet) + Step 11 (diamondCut wiring) done first.

Step 13 — 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.