|
| 1 | +-include .env |
| 2 | + |
| 3 | +.PHONY: help deploy-base-sepolia deploy-base-mainnet verify-base-sepolia verify-base-mainnet bridge-l1-to-base-sepolia bridge-l1-to-base-mainnet |
| 4 | + |
| 5 | +help: ## Show help for each of the Makefile recipes |
| 6 | + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' |
| 7 | + |
| 8 | +# OptimismMintableERC20Factory predeploy address (same on all OP Stack chains) |
| 9 | +FACTORY=0x4200000000000000000000000000000000000012 |
| 10 | +TOKEN_NAME="Aligned Token" |
| 11 | +TOKEN_SYMBOL="ALIGN" |
| 12 | + |
| 13 | +# Default values |
| 14 | +DEPLOYER_PRIVATE_KEY?= |
| 15 | +BASE_SEPOLIA_RPC_URL?=https://sepolia.base.org |
| 16 | +BASE_MAINNET_RPC_URL?=https://mainnet.base.org |
| 17 | + |
| 18 | +# L1 token addresses (set these or pass via env/CLI) |
| 19 | +L1_TOKEN_SEPOLIA?=0xd2Fd114f098b355321cB3424400f3CC6a0d75C9A |
| 20 | +L1_TOKEN_MAINNET?=0x0000000000000000000000000000000000000000 |
| 21 | + |
| 22 | +# L2 token addresses |
| 23 | +L2_TOKEN_SEPOLIA?=0x4AAcFbc2C31598a560b285dB20966E00B73F9F81 |
| 24 | +L2_TOKEN_MAINNET?=0x0000000000000000000000000000000000000000 |
| 25 | + |
| 26 | +# L1 Standard Bridge addresses |
| 27 | +L1_BRIDGE_SEPOLIA=0xfd0Bf71F60660E2f608ed56e1659C450eB113120 |
| 28 | +L1_BRIDGE_MAINNET=0x3154Cf16ccdb4C6d922629664174b904d80F2C35 |
| 29 | + |
| 30 | +# L1 RPC URLs |
| 31 | +L1_SEPOLIA_RPC_URL?=https://ethereum-sepolia-rpc.publicnode.com |
| 32 | +L1_MAINNET_RPC_URL?=https://ethereum-rpc.publicnode.com |
| 33 | + |
| 34 | +# Deployments |
| 35 | +# Following: https://docs.optimism.io/app-developers/tutorials/bridging/standard-bridge-standard-token#create-an-l2-erc-20-token |
| 36 | +# The deployed L2 token address is extracted from the OptimismMintableERC20Created event logs. |
| 37 | + |
| 38 | +deploy-base-sepolia: ## Deploy ALIGN token on BaseSepolia via OptimismMintableERC20Factory |
| 39 | + @echo "Deploying ALIGN on BaseSepolia..." |
| 40 | + @echo "L1 Remote Token: $(L1_TOKEN_SEPOLIA)" |
| 41 | + @echo "Factory: $(FACTORY)" |
| 42 | + @L2_TOKEN=$$(cast send $(FACTORY) \ |
| 43 | + "createOptimismMintableERC20(address,string,string)" \ |
| 44 | + $(L1_TOKEN_SEPOLIA) $(TOKEN_NAME) $(TOKEN_SYMBOL) \ |
| 45 | + --private-key $(DEPLOYER_PRIVATE_KEY) \ |
| 46 | + --rpc-url $(BASE_SEPOLIA_RPC_URL) \ |
| 47 | + --json | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address) && \ |
| 48 | + echo "---------------------------------------------" && \ |
| 49 | + echo "ALIGN L2 Token deployed at: $$L2_TOKEN" && \ |
| 50 | + echo "---------------------------------------------" |
| 51 | + |
| 52 | +deploy-base-mainnet: ## Deploy ALIGN token on BaseMainnet via OptimismMintableERC20Factory |
| 53 | + @echo "Deploying ALIGN on BaseMainnet..." |
| 54 | + @echo "L1 Remote Token: $(L1_TOKEN_MAINNET)" |
| 55 | + @echo "Factory: $(FACTORY)" |
| 56 | + @L2_TOKEN=$$(cast send $(FACTORY) \ |
| 57 | + "createOptimismMintableERC20(address,string,string)" \ |
| 58 | + $(L1_TOKEN_MAINNET) $(TOKEN_NAME) $(TOKEN_SYMBOL) \ |
| 59 | + --private-key $(DEPLOYER_PRIVATE_KEY) \ |
| 60 | + --rpc-url $(BASE_MAINNET_RPC_URL) \ |
| 61 | + --json | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address) && \ |
| 62 | + echo "---------------------------------------------" && \ |
| 63 | + echo "ALIGN L2 Token deployed at: $$L2_TOKEN" && \ |
| 64 | + echo "---------------------------------------------" |
| 65 | + |
| 66 | +# Verification |
| 67 | + |
| 68 | +verify-base-sepolia: ## Verify the deployed L2 token on BaseSepolia (requires L2_TOKEN) |
| 69 | + @echo "Verifying L2 token deployment on BaseSepolia..." |
| 70 | + @echo "--- Token metadata ---" |
| 71 | + cast call $(L2_TOKEN) "name()(string)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 72 | + cast call $(L2_TOKEN) "symbol()(string)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 73 | + cast call $(L2_TOKEN) "decimals()(uint8)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 74 | + @echo "--- Bridge configuration ---" |
| 75 | + cast call $(L2_TOKEN) "REMOTE_TOKEN()(address)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 76 | + cast call $(L2_TOKEN) "BRIDGE()(address)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 77 | + @echo "--- Total supply (should be 0 before any bridging) ---" |
| 78 | + cast call $(L2_TOKEN) "totalSupply()(uint256)" --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 79 | + |
| 80 | +verify-base-mainnet: ## Verify the deployed L2 token on BaseMainnet (requires L2_TOKEN) |
| 81 | + @echo "Verifying L2 token deployment on BaseMainnet..." |
| 82 | + @echo "--- Token metadata ---" |
| 83 | + cast call $(L2_TOKEN) "name()(string)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 84 | + cast call $(L2_TOKEN) "symbol()(string)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 85 | + cast call $(L2_TOKEN) "decimals()(uint8)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 86 | + @echo "--- Bridge configuration ---" |
| 87 | + cast call $(L2_TOKEN) "REMOTE_TOKEN()(address)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 88 | + cast call $(L2_TOKEN) "BRIDGE()(address)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 89 | + @echo "--- Total supply (should be 0 before any bridging) ---" |
| 90 | + cast call $(L2_TOKEN) "totalSupply()(uint256)" --rpc-url $(BASE_MAINNET_RPC_URL) |
| 91 | + |
| 92 | +# Bridging L1 -> L2 |
| 93 | +# Step 1: Approve the L1StandardBridge to spend ALIGN tokens |
| 94 | +# Step 2: Deposit tokens via the bridge (tokens appear on Base after ~20 min) |
| 95 | +# Requires: AMOUNT (in wei), USER_PRIVATE_KEY |
| 96 | +AMOUNT?=1000000000000000000 # Default to 1 ALIGN (18 decimals) |
| 97 | +USER_PRIVATE_KEY?= |
| 98 | + |
| 99 | +bridge-l1-to-base-sepolia: ## Bridge ALIGN tokens from Sepolia L1 to BaseSepolia (requires AMOUNT) |
| 100 | + @echo "Step 1: Approving L1StandardBridge to spend $(AMOUNT) ALIGN on Sepolia..." |
| 101 | + cast send $(L1_TOKEN_SEPOLIA) \ |
| 102 | + "approve(address,uint256)" \ |
| 103 | + $(L1_BRIDGE_SEPOLIA) $(AMOUNT) \ |
| 104 | + --private-key $(USER_PRIVATE_KEY) \ |
| 105 | + --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 106 | + @echo "Step 2: Depositing $(AMOUNT) ALIGN to BaseSepolia..." |
| 107 | + cast send $(L1_BRIDGE_SEPOLIA) \ |
| 108 | + "depositERC20(address,address,uint256,uint32,bytes)" \ |
| 109 | + $(L1_TOKEN_SEPOLIA) $(L2_TOKEN_SEPOLIA) $(AMOUNT) 200000 0x \ |
| 110 | + --private-key $(USER_PRIVATE_KEY) \ |
| 111 | + --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 112 | + @echo "---------------------------------------------" |
| 113 | + @echo "Bridge initiated. Tokens will appear on BaseSepolia in ~20 minutes." |
| 114 | + @echo "---------------------------------------------" |
| 115 | + |
| 116 | +bridge-l1-to-base-mainnet: ## Bridge ALIGN tokens from Ethereum L1 to Base (requires AMOUNT) |
| 117 | + @echo "Step 1: Approving L1StandardBridge to spend $(AMOUNT) ALIGN on Mainnet..." |
| 118 | + cast send $(L1_TOKEN_MAINNET) \ |
| 119 | + "approve(address,uint256)" \ |
| 120 | + $(L1_BRIDGE_MAINNET) $(AMOUNT) \ |
| 121 | + --private-key $(USER_PRIVATE_KEY) \ |
| 122 | + --rpc-url $(L1_MAINNET_RPC_URL) |
| 123 | + @echo "Step 2: Depositing $(AMOUNT) ALIGN to Base..." |
| 124 | + cast send $(L1_BRIDGE_MAINNET) \ |
| 125 | + "depositERC20(address,address,uint256,uint32,bytes)" \ |
| 126 | + $(L1_TOKEN_MAINNET) $(L2_TOKEN_MAINNET) $(AMOUNT) 200000 0x \ |
| 127 | + --private-key $(USER_PRIVATE_KEY) \ |
| 128 | + --rpc-url $(L1_MAINNET_RPC_URL) |
| 129 | + @echo "---------------------------------------------" |
| 130 | + @echo "Bridge initiated. Tokens will appear on Base in ~20 minutes." |
| 131 | + @echo "---------------------------------------------" |
0 commit comments