Skip to content

Commit b9dd926

Browse files
GeObtsclaude
andcommitted
feat(deploy): CREATE2 deterministic deploy script
Single Deploy.s.sol covering all four target chains (Arbitrum One, Arbitrum Sepolia, Base mainnet, Base Sepolia). The Manager deploys via CREATE2 through Arachnid's deterministic deployer (0x4e59...) using salt keccak256('MiTanda.v1.Manager'), giving the same Manager address on every chain — branding/UX win. Structure: - Pre-flight checks (deployer/treasury/subscription non-zero, gas lane non-zero, Arachnid present on this chain) fail loud before broadcast - Predict Manager address via pure RLP encoding helper - Deploy Tanda implementation, three NFTs (with predicted Manager address), then Manager via CREATE2 - Assert deployed Manager address matches prediction - Critical ordering: manager.acceptOwnership() runs BEFORE any owner-only setup (allowlistToken, registerCollection, setActiveCollection), structurally enforced by being inside the same function with a require(manager.owner() == deployer) gate between - 13 post-deploy invariant checks before considering deploy successful - JSON output to deployments/{chainId}.json for frontend consumption - Logged post-deploy instructions (add Manager as VRF consumer, fund subscription, verify contracts on block explorer) Chain config: - Base mainnet and Arbitrum One gas-lane keyHashes filled (best-effort from training data, marked VERIFY against Chainlink docs) - Base Sepolia and Arbitrum Sepolia gas-lane keyHashes left as bytes32(0) with TODO comments; pre-flight reverts until set - Token allowlists per chain: USDC on Base, USDC+MXNB on Arbitrum One, MXNB on Arbitrum Sepolia (no canonical Sepolia USDC), USDC on Base Sepolia .env.example documents all required environment variables including the cross-chain determinism contract (fresh deployer EOA, same starting nonce on each chain, no intervening transactions). 85 tests still pass; no contract changes in this commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5ee26b4 commit b9dd926

3 files changed

Lines changed: 565 additions & 3 deletions

File tree

.env.example

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,60 @@
11
# Mi Tanda — environment template
22
# Copy to .env and fill in. NEVER commit the real .env.
33

4-
# ===== Alchemy RPC endpoints =====
4+
# ─────────────────────────────────────────────────────────────────────
5+
# Alchemy RPC endpoints
6+
# ─────────────────────────────────────────────────────────────────────
57
ARBITRUM_MAINNET_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/<YOUR_ALCHEMY_KEY>
68
BASE_MAINNET_RPC_URL=https://base-mainnet.g.alchemy.com/v2/<YOUR_ALCHEMY_KEY>
79
ARBITRUM_SEPOLIA_RPC_URL=https://arb-sepolia.g.alchemy.com/v2/<YOUR_ALCHEMY_KEY>
810
BASE_SEPOLIA_RPC_URL=https://base-sepolia.g.alchemy.com/v2/<YOUR_ALCHEMY_KEY>
911

10-
# ===== Privy =====
12+
# ─────────────────────────────────────────────────────────────────────
13+
# Privy
14+
# ─────────────────────────────────────────────────────────────────────
1115
PRIVY_APP_ID=<your-privy-app-id>
1216
PRIVY_APP_SECRET=<your-privy-app-secret>
1317

14-
# ===== Deployment =====
18+
# ─────────────────────────────────────────────────────────────────────
19+
# Deployer
20+
#
21+
# Cross-chain determinism note: the Manager's CREATE2 address depends
22+
# on (deployer EOA, deployer nonce, salt, init code). To get the SAME
23+
# Manager address on every chain, use a FRESH deployer EOA dedicated
24+
# to Mi Tanda deploys and run the script with the same starting nonce
25+
# on each chain (ideally nonce 0 — i.e. the EOA has never sent any tx
26+
# on that chain). Do not reuse the deployer between chain runs.
27+
# ─────────────────────────────────────────────────────────────────────
1528
DEPLOYER_PRIVATE_KEY=0x<your-deployer-private-key>
29+
30+
# ─────────────────────────────────────────────────────────────────────
31+
# Block explorer API keys — for `forge verify-contract`
32+
# ─────────────────────────────────────────────────────────────────────
1633
ARBISCAN_API_KEY=<your-arbiscan-api-key>
1734
BASESCAN_API_KEY=<your-basescan-api-key>
35+
36+
# ─────────────────────────────────────────────────────────────────────
37+
# Treasury (platform fee recipient + initial royalty receiver)
38+
# Owner-configurable post-deploy via TandaManager.setTreasury(...)
39+
# ─────────────────────────────────────────────────────────────────────
40+
TREASURY_ADDRESS=0x70D3a9aA7e10070d3F528e91c9bCf5158c922C66
41+
42+
# ─────────────────────────────────────────────────────────────────────
43+
# Chainlink VRF v2.5
44+
# Create the subscription per-chain at https://vrf.chain.link
45+
# Fund it with native ETH (not LINK) — the deploy script logs the
46+
# `fundSubscriptionWithNative` cast command in its post-deploy steps.
47+
# ─────────────────────────────────────────────────────────────────────
48+
VRF_SUBSCRIPTION_ID=
49+
50+
# 2.5M gas accommodates the worst-case 50-participant shuffle plus
51+
# coordinator callback overhead with margin. Owner can adjust via
52+
# TandaManager.updateVRFConfig(...) post-deploy.
53+
CALLBACK_GAS_LIMIT=2500000
54+
55+
# ─────────────────────────────────────────────────────────────────────
56+
# Initial Receipt NFT fallback URI — used when a tanda has no
57+
# sponsored collection active. Set to your IPFS CID for a tasteful
58+
# default; owner can update later via MitandaReceiptNFT.setDefaultFallbackBaseURI.
59+
# ─────────────────────────────────────────────────────────────────────
60+
INITIAL_FALLBACK_BASE_URI=ipfs://QmReplaceWithRealCID

deployments/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

0 commit comments

Comments
 (0)