|
| 1 | +-include .env |
| 2 | +export |
| 3 | + |
| 4 | +.PHONY: help deploy-base-sepolia deploy-base-mainnet verify bridge-l1-to-base-sepolia bridge-l1-to-base-mainnet withdraw-base-to-l1-sepolia withdraw-base-to-l1-mainnet prove-withdrawal-sepolia prove-withdrawal-mainnet finalize-withdrawal-sepolia finalize-withdrawal-mainnet |
| 5 | + |
| 6 | +help: ## Show help |
| 7 | + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' |
| 8 | + |
| 9 | +# OptimismMintableERC20Factory |
| 10 | +# Mainnet uses Base-specific factory to avoid address conflicts with Optimism. |
| 11 | +# Source: https://docs.base.org/chain/base-contracts |
| 12 | +FACTORY_SEPOLIA=0x4200000000000000000000000000000000000012 |
| 13 | +FACTORY_MAINNET=0xF10122D428B4bc8A9d050D06a2037259b4c4B83B |
| 14 | + |
| 15 | +# --- Deployment --- |
| 16 | + |
| 17 | +deploy-base-sepolia: ## Deploy ALIGN on BaseSepolia |
| 18 | + @L2_TOKEN=$$(cast send $(FACTORY_SEPOLIA) \ |
| 19 | + "createOptimismMintableERC20(address,string,string)" \ |
| 20 | + $(L1_TOKEN_SEPOLIA) "Aligned Token" "ALIGN" \ |
| 21 | + --private-key $(DEPLOYER_PRIVATE_KEY) \ |
| 22 | + --rpc-url $(BASE_SEPOLIA_RPC_URL) \ |
| 23 | + --json | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address) && \ |
| 24 | + echo "L2 Token deployed at: $$L2_TOKEN" |
| 25 | + |
| 26 | +deploy-base-mainnet: ## Deploy ALIGN on BaseMainnet |
| 27 | + @L2_TOKEN=$$(cast send $(FACTORY_MAINNET) \ |
| 28 | + "createOptimismMintableERC20(address,string,string)" \ |
| 29 | + $(L1_TOKEN_MAINNET) "Aligned Token" "ALIGN" \ |
| 30 | + --interactive \ |
| 31 | + --rpc-url $(BASE_MAINNET_RPC_URL) \ |
| 32 | + --json | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address) && \ |
| 33 | + echo "L2 Token deployed at: $$L2_TOKEN" |
| 34 | + |
| 35 | +# --- Verification --- |
| 36 | + |
| 37 | +verify: ## Verify L2 token (requires L2_TOKEN, RPC_URL) |
| 38 | + @cast call $(L2_TOKEN) "name()(string)" --rpc-url $(RPC_URL) |
| 39 | + @cast call $(L2_TOKEN) "symbol()(string)" --rpc-url $(RPC_URL) |
| 40 | + @cast call $(L2_TOKEN) "decimals()(uint8)" --rpc-url $(RPC_URL) |
| 41 | + @cast call $(L2_TOKEN) "REMOTE_TOKEN()(address)" --rpc-url $(RPC_URL) |
| 42 | + @cast call $(L2_TOKEN) "BRIDGE()(address)" --rpc-url $(RPC_URL) |
| 43 | + @cast call $(L2_TOKEN) "totalSupply()(uint256)" --rpc-url $(RPC_URL) |
| 44 | + |
| 45 | +# --- Bridging L1 -> Base --- |
| 46 | + |
| 47 | +bridge-l1-to-base-sepolia: ## Bridge ALIGN from Sepolia to BaseSepolia (requires AMOUNT) |
| 48 | + cast send $(L1_TOKEN_SEPOLIA) "approve(address,uint256)" $(L1_BRIDGE_SEPOLIA) $(AMOUNT) \ |
| 49 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 50 | + cast send $(L1_BRIDGE_SEPOLIA) "depositERC20(address,address,uint256,uint32,bytes)" \ |
| 51 | + $(L1_TOKEN_SEPOLIA) $(L2_TOKEN_SEPOLIA) $(AMOUNT) 200000 0x \ |
| 52 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 53 | + |
| 54 | +bridge-l1-to-base-mainnet: ## Bridge ALIGN from Ethereum to Base (requires AMOUNT) |
| 55 | + cast send $(L1_TOKEN_MAINNET) "approve(address,uint256)" $(L1_BRIDGE_MAINNET) $(AMOUNT) \ |
| 56 | + --interactive --rpc-url $(L1_MAINNET_RPC_URL) |
| 57 | + cast send $(L1_BRIDGE_MAINNET) "depositERC20(address,address,uint256,uint32,bytes)" \ |
| 58 | + $(L1_TOKEN_MAINNET) $(L2_TOKEN_MAINNET) $(AMOUNT) 200000 0x \ |
| 59 | + --interactive --rpc-url $(L1_MAINNET_RPC_URL) |
| 60 | + |
| 61 | +bridge-l1-to-base-sepolia-to: ## Bridge ALIGN from Sepolia to BaseSepolia to a different address (requires AMOUNT, TO) |
| 62 | + cast send $(L1_TOKEN_SEPOLIA) "approve(address,uint256)" $(L1_BRIDGE_SEPOLIA) $(AMOUNT) \ |
| 63 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 64 | + cast send $(L1_BRIDGE_SEPOLIA) "depositERC20To(address,address,address,uint256,uint32,bytes)" \ |
| 65 | + $(L1_TOKEN_SEPOLIA) $(L2_TOKEN_SEPOLIA) $(TO) $(AMOUNT) 200000 0x \ |
| 66 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(L1_SEPOLIA_RPC_URL) |
| 67 | + |
| 68 | +bridge-l1-to-base-mainnet-to: ## Bridge ALIGN from Ethereum to Base to a different address (requires AMOUNT, TO) |
| 69 | + cast send $(L1_TOKEN_MAINNET) "approve(address,uint256)" $(L1_BRIDGE_MAINNET) $(AMOUNT) \ |
| 70 | + --interactive --rpc-url $(L1_MAINNET_RPC_URL) |
| 71 | + cast send $(L1_BRIDGE_MAINNET) "depositERC20To(address,address,address,uint256,uint32,bytes)" \ |
| 72 | + $(L1_TOKEN_MAINNET) $(L2_TOKEN_MAINNET) $(TO) $(AMOUNT) 200000 0x \ |
| 73 | + --interactive --rpc-url $(L1_MAINNET_RPC_URL) |
| 74 | + |
| 75 | +# --- Bridging Base -> L1 (withdrawal) --- |
| 76 | +# This initiates the withdrawal on L2. After this, you must: |
| 77 | +# 1. Wait ~1 hour for the L2 output to be proposed |
| 78 | +# 2. Prove the withdrawal on L1 (requires Optimism SDK or Base Bridge UI) |
| 79 | +# 3. Wait 7 days (challenge period) |
| 80 | +# 4. Finalize the withdrawal on L1 |
| 81 | +# L2StandardBridge predeploy: 0x4200000000000000000000000000000000000010 |
| 82 | + |
| 83 | +withdraw-base-to-l1-sepolia: ## Initiate ALIGN withdrawal from BaseSepolia to Sepolia (requires AMOUNT) |
| 84 | + cast send 0x4200000000000000000000000000000000000010 \ |
| 85 | + "withdraw(address,uint256,uint32,bytes)" \ |
| 86 | + $(L2_TOKEN_SEPOLIA) $(AMOUNT) 200000 0x \ |
| 87 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 88 | + |
| 89 | +withdraw-base-to-l1-mainnet: ## Initiate ALIGN withdrawal from Base to Ethereum (requires AMOUNT) |
| 90 | + cast send 0x4200000000000000000000000000000000000010 \ |
| 91 | + "withdraw(address,uint256,uint32,bytes)" \ |
| 92 | + $(L2_TOKEN_MAINNET) $(AMOUNT) 200000 0x \ |
| 93 | + --interactive --rpc-url $(BASE_MAINNET_RPC_URL) |
| 94 | + |
| 95 | +withdraw-base-to-l1-sepolia-to: ## Initiate ALIGN withdrawal from BaseSepolia to a different address on Sepolia (requires AMOUNT, TO) |
| 96 | + cast send 0x4200000000000000000000000000000000000010 \ |
| 97 | + "withdrawTo(address,address,uint256,uint32,bytes)" \ |
| 98 | + $(L2_TOKEN_SEPOLIA) $(TO) $(AMOUNT) 200000 0x \ |
| 99 | + --private-key $(USER_PRIVATE_KEY) --rpc-url $(BASE_SEPOLIA_RPC_URL) |
| 100 | + |
| 101 | +withdraw-base-to-l1-mainnet-to: ## Initiate ALIGN withdrawal from Base to a different address on Ethereum (requires AMOUNT, TO) |
| 102 | + cast send 0x4200000000000000000000000000000000000010 \ |
| 103 | + "withdrawTo(address,address,uint256,uint32,bytes)" \ |
| 104 | + $(L2_TOKEN_MAINNET) $(TO) $(AMOUNT) 200000 0x \ |
| 105 | + --interactive --rpc-url $(BASE_MAINNET_RPC_URL) |
| 106 | + |
| 107 | +# --- Prove & Finalize (requires npm install) --- |
| 108 | + |
| 109 | +prove-withdrawal-sepolia: ## Prove withdrawal on L1 Sepolia (requires TX_HASH) |
| 110 | + npx tsx scripts/withdraw.ts prove --tx-hash $(TX_HASH) --network sepolia |
| 111 | + |
| 112 | +prove-withdrawal-mainnet: ## Prove withdrawal on L1 Mainnet (requires TX_HASH) |
| 113 | + npx tsx scripts/withdraw.ts prove --tx-hash $(TX_HASH) --network mainnet |
| 114 | + |
| 115 | +finalize-withdrawal-sepolia: ## Finalize withdrawal on L1 Sepolia (requires TX_HASH) |
| 116 | + npx tsx scripts/withdraw.ts finalize --tx-hash $(TX_HASH) --network sepolia |
| 117 | + |
| 118 | +finalize-withdrawal-mainnet: ## Finalize withdrawal on L1 Mainnet (requires TX_HASH) |
| 119 | + npx tsx scripts/withdraw.ts finalize --tx-hash $(TX_HASH) --network mainnet |
0 commit comments