diff --git a/contracts/evm-gateway/.env.example b/contracts/evm-gateway/.env.example index d9693ff..79a95ce 100644 --- a/contracts/evm-gateway/.env.example +++ b/contracts/evm-gateway/.env.example @@ -1,7 +1,19 @@ -# Sepolia Testnet Configuration -SEPOLIA_RPC_URL=YOUR_RPC_RUL -ETH_MAINNET_RPC_URL=YOUR_RPC_RUL -POLYGON_RPC_URL=YOUR_RPC_RUL +# RPC URLs +SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY +BASE_SEPOLIA_RPC_URL=https://sepolia.base.org +ARB_SEPOLIA_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc +BSC_TESTNET_RPC_URL=https://data-seed-prebsc-1-s1.binance.org:8545 +PUSH_CHAIN_RPC_URL=https://evm.rpc-testnet-donut-node1.push.org/ -# Optional: Etherscan API Key for verification -ETHERSCAN_API_KEY=your_etherscan_api_key_here +# Private Keys (must have 0x prefix) +PRIVATE_KEY_sepolia=0x... +PRIVATE_KEY_base_sepolia=0x... +PRIVATE_KEY_arb_sepolia=0x... +PRIVATE_KEY_bsc_testnet=0x... +PRIVATE_KEY_push_chain=0x... + +# Etherscan API Keys +ETHERSCAN_API_KEY=... +BASESCAN_API_KEY=... +ARBISCAN_API_KEY=... +BSCSCAN_API_KEY=... diff --git a/contracts/evm-gateway/Makefile b/contracts/evm-gateway/Makefile new file mode 100644 index 0000000..f7e9422 --- /dev/null +++ b/contracts/evm-gateway/Makefile @@ -0,0 +1,219 @@ +.PHONY: help deploy-gateway deploy-gateway-v0 deploy-gateway-pc verify-gateway verify-gateway-v0 verify-gateway-pc upgrade-gateway upgrade-gateway-v0 upgrade-vault upgrade-gateway-pc upgrade-vault-pc + +# Default network +network ?= sepolia + +# Map network names to foundry chain names +ifeq ($(network),sepolia) + CHAIN = sepolia +else ifeq ($(network),base_sepolia) + CHAIN = base_sepolia +else ifeq ($(network),arb_sepolia) + CHAIN = arb_sepolia +else ifeq ($(network),bsc_testnet) + CHAIN = bsc_testnet +else ifeq ($(network),push_chain) + CHAIN = push_chain +else + $(error Unknown network: $(network). Supported: sepolia, base_sepolia, arb_sepolia, bsc_testnet, push_chain) +endif + +help: + @echo "════════════════════════════════════════════════════════════════" + @echo " DEPLOYMENT COMMANDS" + @echo "════════════════════════════════════════════════════════════════" + @echo "" + @echo " make deploy-gateway network=" + @echo " Deploy UniversalGateway + Vault (new, no USDT)" + @echo "" + @echo " make deploy-gateway-v0 network=" + @echo " Deploy UniversalGatewayV0 (legacy with USDT)" + @echo "" + @echo " make deploy-gateway-pc network=" + @echo " Deploy UniversalGatewayPC + VaultPC (Push Chain)" + @echo "" + @echo "════════════════════════════════════════════════════════════════" + @echo " VERIFICATION COMMANDS" + @echo "════════════════════════════════════════════════════════════════" + @echo "" + @echo " make verify-gateway network=" + @echo " make verify-gateway-v0 network=" + @echo " make verify-gateway-pc network=" + @echo "" + @echo "════════════════════════════════════════════════════════════════" + @echo " UPGRADE COMMANDS" + @echo "════════════════════════════════════════════════════════════════" + @echo "" + @echo " make upgrade-gateway network= PROXY_ADDRESS=0x... PROXY_ADMIN_ADDRESS=0x..." + @echo " Upgrade UniversalGateway" + @echo "" + @echo " make upgrade-gateway-v0 network= PROXY_ADDRESS=0x... PROXY_ADMIN_ADDRESS=0x..." + @echo " Upgrade UniversalGatewayV0" + @echo "" + @echo " make upgrade-vault network= PROXY_ADDRESS=0x... PROXY_ADMIN_ADDRESS=0x..." + @echo " Upgrade Vault" + @echo "" + @echo " make upgrade-gateway-pc network= PROXY_ADDRESS=0x... PROXY_ADMIN_ADDRESS=0x..." + @echo " Upgrade UniversalGatewayPC" + @echo "" + @echo " make upgrade-vault-pc network= PROXY_ADDRESS=0x... PROXY_ADMIN_ADDRESS=0x..." + @echo " Upgrade VaultPC" + @echo "" + @echo "════════════════════════════════════════════════════════════════" + @echo " NETWORKS: sepolia, base_sepolia, arb_sepolia, bsc_testnet, push_chain" + @echo "════════════════════════════════════════════════════════════════" + +# ═══════════════════════════════════════════════════════════════════════ +# DEPLOYMENT +# ═══════════════════════════════════════════════════════════════════════ + +deploy-gateway: + @echo "Deploying UniversalGateway + Vault to $(network)..." + @NETWORK=$(network) forge script script/deployment/DeployUniversalGateway.sol:DeployUniversalGateway \ + --rpc-url $(CHAIN) \ + --broadcast \ + --via-ir + @echo "✅ Deployment complete! Run 'make verify-gateway network=$(network)' to verify contracts." + +deploy-gateway-v0: + @echo "Deploying UniversalGatewayV0 to $(network)..." + @NETWORK=$(network) forge script script/deployment/DeployUniversalGatewayV0.sol:DeployUniversalGatewayV0 \ + --rpc-url $(CHAIN) \ + --broadcast \ + --via-ir + @echo "✅ Deployment complete! Run 'make verify-gateway-v0 network=$(network)' to verify contracts." + +deploy-gateway-pc: + @echo "Deploying UniversalGatewayPC + VaultPC to $(network)..." + @NETWORK=$(network) forge script script/deployment/DeployUniversalGatewayPC.sol:DeployUniversalGatewayPC \ + --rpc-url $(CHAIN) \ + --broadcast \ + --slow \ + --via-ir + @echo "✅ Deployment complete! Verify manually if needed." + +# ═══════════════════════════════════════════════════════════════════════ +# VERIFICATION +# ═══════════════════════════════════════════════════════════════════════ + +verify-gateway: + @echo "Use broadcast receipts to verify contracts manually:" + @echo "Check: broadcast/DeployUniversalGateway.sol/*/run-latest.json" + @echo "" + @echo "Example: forge verify-contract src/UniversalGateway.sol:UniversalGateway --chain $(CHAIN)" + +verify-gateway-v0: + @echo "Use broadcast receipts to verify contracts manually:" + @echo "Check: broadcast/DeployUniversalGatewayV0.sol/*/run-latest.json" + @echo "" + @echo "Example: forge verify-contract src/UniversalGatewayV0.sol:UniversalGatewayV0 --chain $(CHAIN)" + +verify-gateway-pc: + @echo "Use broadcast receipts to verify contracts manually:" + @echo "Check: broadcast/DeployUniversalGatewayPC.sol/*/run-latest.json" + @echo "" + @echo "Example: forge verify-contract src/UniversalGatewayPC.sol:UniversalGatewayPC --chain $(CHAIN)" + +# ═══════════════════════════════════════════════════════════════════════ +# UPGRADE +# ═══════════════════════════════════════════════════════════════════════ + +upgrade-gateway: + @echo "Upgrading UniversalGateway on $(network)..." + @if [ -z "$(PROXY_ADDRESS)" ]; then \ + echo "Auto-detecting proxy from broadcast folder..."; \ + SCRIPT_DIR="broadcast/DeployUniversalGateway.sol"; \ + LATEST=$$(find $$SCRIPT_DIR -name "run-latest.json" ! -path "*/dry-run/*" -type f -exec ls -t {} + 2>/dev/null | head -1); \ + if [ -z "$$LATEST" ]; then echo "❌ No deployment found. Deploy first or provide PROXY_ADDRESS=0x..."; exit 1; fi; \ + if command -v jq >/dev/null 2>&1; then \ + PROXY=$$(jq -r '.transactions[] | select(.contractName == "TransparentUpgradeableProxy" and (.transaction.to == null or .transaction.to == "")) | .contractAddress' $$LATEST 2>/dev/null | head -1); \ + else \ + PROXY=$$(cat $$LATEST | grep -B2 -A5 '"contractName": "TransparentUpgradeableProxy"' | grep -B3 '"to": null' | grep '"contractAddress"' | tail -1 | cut -d'"' -f4); \ + fi; \ + if [ -z "$$PROXY" ] || [ "$$PROXY" = "null" ]; then echo "❌ Could not find Gateway proxy address in deployment"; exit 1; fi; \ + echo "Found Gateway Proxy: $$PROXY (ProxyAdmin auto-detected from storage slot)"; \ + NETWORK=$(network) PROXY_ADDRESS=$$PROXY forge script script/upgrade/UpgradeUniversalGateway.sol:UpgradeUniversalGateway --rpc-url $(CHAIN) --broadcast --via-ir; \ + else \ + echo "Using provided PROXY_ADDRESS: $(PROXY_ADDRESS)"; \ + NETWORK=$(network) PROXY_ADDRESS=$(PROXY_ADDRESS) forge script script/upgrade/UpgradeUniversalGateway.sol:UpgradeUniversalGateway --rpc-url $(CHAIN) --broadcast --via-ir; \ + fi + +upgrade-gateway-v0: + @echo "Upgrading UniversalGatewayV0 on $(network)..." + @if [ -z "$(PROXY_ADDRESS)" ]; then \ + echo "Auto-detecting proxy from broadcast folder..."; \ + SCRIPT_DIR="broadcast/DeployUniversalGatewayV0.sol"; \ + LATEST=$$(find $$SCRIPT_DIR -name "run-latest.json" ! -path "*/dry-run/*" -type f -exec ls -t {} + 2>/dev/null | head -1); \ + if [ -z "$$LATEST" ]; then echo "❌ No deployment found. Deploy first or provide PROXY_ADDRESS=0x..."; exit 1; fi; \ + if command -v jq >/dev/null 2>&1; then \ + PROXY=$$(jq -r '.transactions[] | select(.contractName == "TransparentUpgradeableProxy" and (.transaction.to == null or .transaction.to == "")) | .contractAddress' $$LATEST 2>/dev/null | head -1); \ + else \ + PROXY=$$(cat $$LATEST | grep -B2 -A5 '"contractName": "TransparentUpgradeableProxy"' | grep -B3 '"to": null' | grep '"contractAddress"' | tail -1 | cut -d'"' -f4); \ + fi; \ + if [ -z "$$PROXY" ] || [ "$$PROXY" = "null" ]; then echo "❌ Could not find proxy address in deployment"; exit 1; fi; \ + echo "Found Gateway Proxy: $$PROXY (ProxyAdmin auto-detected from storage slot)"; \ + NETWORK=$(network) PROXY_ADDRESS=$$PROXY forge script script/upgrade/UpgradeUniversalGatewayV0.sol:UpgradeUniversalGatewayV0 --rpc-url $(CHAIN) --broadcast --via-ir; \ + else \ + echo "Using provided PROXY_ADDRESS: $(PROXY_ADDRESS)"; \ + NETWORK=$(network) PROXY_ADDRESS=$(PROXY_ADDRESS) forge script script/upgrade/UpgradeUniversalGatewayV0.sol:UpgradeUniversalGatewayV0 --rpc-url $(CHAIN) --broadcast --via-ir; \ + fi + +upgrade-vault: + @echo "Upgrading Vault on $(network)..." + @if [ -z "$(PROXY_ADDRESS)" ]; then \ + echo "Auto-detecting proxy from broadcast folder..."; \ + SCRIPT_DIR="broadcast/DeployUniversalGateway.sol"; \ + LATEST=$$(find $$SCRIPT_DIR -name "run-latest.json" ! -path "*/dry-run/*" -type f -exec ls -t {} + 2>/dev/null | head -1); \ + if [ -z "$$LATEST" ]; then echo "❌ No deployment found. Deploy first or provide PROXY_ADDRESS=0x..."; exit 1; fi; \ + if command -v jq >/dev/null 2>&1; then \ + PROXY=$$(jq -r '.transactions[] | select((.contractName == "Vault" or (.contractName == "TransparentUpgradeableProxy" and (.transaction.to == null or .transaction.to == ""))) and .contractAddress != null) | .contractAddress' $$LATEST 2>/dev/null | grep -v "^$$" | tail -1); \ + else \ + PROXY=$$(cat $$LATEST | grep -B5 '"contractName": "Vault"' | grep '"contractAddress"' | tail -1 | cut -d'"' -f4); \ + fi; \ + if [ -z "$$PROXY" ] || [ "$$PROXY" = "null" ]; then echo "❌ Could not find Vault proxy address in deployment"; exit 1; fi; \ + echo "Found Vault Proxy: $$PROXY (ProxyAdmin auto-detected from storage slot)"; \ + NETWORK=$(network) PROXY_ADDRESS=$$PROXY forge script script/upgrade/UpgradeVault.sol:UpgradeVault --rpc-url $(CHAIN) --broadcast --via-ir; \ + else \ + echo "Using provided PROXY_ADDRESS: $(PROXY_ADDRESS)"; \ + NETWORK=$(network) PROXY_ADDRESS=$(PROXY_ADDRESS) forge script script/upgrade/UpgradeVault.sol:UpgradeVault --rpc-url $(CHAIN) --broadcast --via-ir; \ + fi + +upgrade-gateway-pc: + @echo "Upgrading UniversalGatewayPC on $(network)..." + @if [ -z "$(PROXY_ADDRESS)" ]; then \ + echo "Auto-detecting proxy from broadcast folder..."; \ + SCRIPT_DIR="broadcast/DeployUniversalGatewayPC.sol"; \ + LATEST=$$(find $$SCRIPT_DIR -name "run-latest.json" ! -path "*/dry-run/*" -type f -exec ls -t {} + 2>/dev/null | head -1); \ + if [ -z "$$LATEST" ]; then echo "❌ No deployment found. Deploy first or provide PROXY_ADDRESS=0x..."; exit 1; fi; \ + if command -v jq >/dev/null 2>&1; then \ + PROXY=$$(jq -r '.transactions[] | select(.contractName == "TransparentUpgradeableProxy" and (.transaction.to == null or .transaction.to == "")) | .contractAddress' $$LATEST 2>/dev/null | tail -1); \ + else \ + PROXY=$$(cat $$LATEST | grep -B2 -A5 '"contractName": "TransparentUpgradeableProxy"' | grep -B3 '"to": null' | grep '"contractAddress"' | tail -1 | cut -d'"' -f4); \ + fi; \ + if [ -z "$$PROXY" ] || [ "$$PROXY" = "null" ]; then echo "❌ Could not find GatewayPC proxy address in deployment"; exit 1; fi; \ + echo "Found Gateway Proxy: $$PROXY (ProxyAdmin auto-detected from storage slot)"; \ + NETWORK=$(network) PROXY_ADDRESS=$$PROXY forge script script/upgrade/UpgradeUniversalGatewayPC.sol:UpgradeUniversalGatewayPC --rpc-url $(CHAIN) --broadcast --slow --via-ir; \ + else \ + echo "Using provided PROXY_ADDRESS: $(PROXY_ADDRESS)"; \ + NETWORK=$(network) PROXY_ADDRESS=$(PROXY_ADDRESS) forge script script/upgrade/UpgradeUniversalGatewayPC.sol:UpgradeUniversalGatewayPC --rpc-url $(CHAIN) --broadcast --slow --via-ir; \ + fi + +upgrade-vault-pc: + @echo "Upgrading VaultPC on $(network)..." + @if [ -z "$(PROXY_ADDRESS)" ]; then \ + echo "Auto-detecting proxy from broadcast folder..."; \ + SCRIPT_DIR="broadcast/DeployUniversalGatewayPC.sol"; \ + LATEST=$$(find $$SCRIPT_DIR -name "run-latest.json" ! -path "*/dry-run/*" -type f -exec ls -t {} + 2>/dev/null | head -1); \ + if [ -z "$$LATEST" ]; then echo "❌ No deployment found. Deploy first or provide PROXY_ADDRESS=0x..."; exit 1; fi; \ + if command -v jq >/dev/null 2>&1; then \ + PROXY=$$(jq -r '.transactions[] | select(.contractName == "TransparentUpgradeableProxy" and (.transaction.to == null or .transaction.to == "")) | .contractAddress' $$LATEST 2>/dev/null | head -1); \ + else \ + PROXY=$$(cat $$LATEST | grep -B2 -A5 '"contractName": "TransparentUpgradeableProxy"' | grep -B3 '"to": null' | grep '"contractAddress"' | head -1 | cut -d'"' -f4); \ + fi; \ + if [ -z "$$PROXY" ] || [ "$$PROXY" = "null" ]; then echo "❌ Could not find VaultPC proxy address in deployment"; exit 1; fi; \ + echo "Found VaultPC Proxy: $$PROXY (ProxyAdmin auto-detected from storage slot)"; \ + NETWORK=$(network) PROXY_ADDRESS=$$PROXY forge script script/upgrade/UpgradeVaultPC.sol:UpgradeVaultPC --rpc-url $(CHAIN) --broadcast --slow --via-ir; \ + else \ + echo "Using provided PROXY_ADDRESS: $(PROXY_ADDRESS)"; \ + NETWORK=$(network) PROXY_ADDRESS=$(PROXY_ADDRESS) forge script script/upgrade/UpgradeVaultPC.sol:UpgradeVaultPC --rpc-url $(CHAIN) --broadcast --slow --via-ir; \ + fi diff --git a/contracts/evm-gateway/README.md b/contracts/evm-gateway/README.md index d8d3cd9..236eafc 100644 --- a/contracts/evm-gateway/README.md +++ b/contracts/evm-gateway/README.md @@ -214,21 +214,28 @@ forge coverage --ir-minimum ## Deployment and Verification -See `script/` and `script/DeployCommands.md` for example commands. Example (Sepolia): +**Deploy:** +```bash +make deploy-gateway network=sepolia +make deploy-gateway-v0 network=sepolia +make deploy-gateway-pc network=push_chain +``` -Deploy (proxy + implementation + admin via script): +**Upgrade (auto-detects proxy address if not provided):** ```bash -forge script script/1_DeployGatewayWithProxy.sol:DeployGatewayWithProxy \ - --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast +make upgrade-gateway network=sepolia +make upgrade-gateway-v0 network=sepolia +make upgrade-vault network=sepolia +make upgrade-gateway-pc network=push_chain +make upgrade-vault-pc network=push_chain ``` -Upgrade: +**Manual override:** ```bash -forge script script/3_UpgradeGatewayNewImpl.sol:UpgradeGatewayNewImpl \ - --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast +make upgrade-gateway-v0 network=sepolia PROXY_ADDRESS=0x... ``` -Verification examples are listed in `script/DeployCommands.md`. +**Networks:** `sepolia`, `base_sepolia`, `arb_sepolia`, `bsc_testnet`, `push_chain` ## Security Notes diff --git a/contracts/evm-gateway/config/chainConfig.json b/contracts/evm-gateway/config/chainConfig.json new file mode 100644 index 0000000..eb017da --- /dev/null +++ b/contracts/evm-gateway/config/chainConfig.json @@ -0,0 +1,42 @@ +{ + "sepolia": { + "chainId": 11155111, + "weth": "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "uniswapV3Factory": "0x0227628f3F023bb0B980b67D528571c95c6DaC1c", + "uniswapV3Router": "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E", + "ethUsdFeed": "0x694AA1769357215DE4FAC081bf1f309aDC325306", + "usdt": "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06", + "usdtUsdFeed": "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E" + }, + "base_sepolia": { + "chainId": 84532, + "weth": "0x4200000000000000000000000000000000000006", + "uniswapV3Factory": "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24", + "uniswapV3Router": "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4", + "ethUsdFeed": "0xE7fab834B68dA8016239845D08F0B8a82fa446f0", + "usdt": "0x9FF5a186f53F6E6964B00320Da1D2024DE11E0cB", + "usdtUsdFeed": "0x3ec8593F930EA45ea58c968260e6e9FF53FC934f" + }, + "arb_sepolia": { + "chainId": 421614, + "weth": "0x980B62Da83eFf3D4576C647993b0c1D7faf17c73", + "uniswapV3Factory": "0x248AB79Bbb9bC29bB72f7Cd42F17e054Fc40188e", + "uniswapV3Router": "0x101F443B4d1b059569D643917553c771E1b9663E", + "ethUsdFeed": "0xd30e2101a97dcbAeBCBC04F14C3f624E67A35165", + "usdt": "0x1419d7C74D234fA6B73E06A2ce7822C1d37922f0", + "usdtUsdFeed": "0x80EDee6f667eCc9f63a0a6f55578F870651f06A4" + }, + "bsc_testnet": { + "chainId": 97, + "weth": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd", + "uniswapV3Factory": "0x0bEC2a9E08658eAA15935C25cfF953caB2934C85", + "uniswapV3Router": "0x2908Fa14Ef79A774c2bF0ab895948B0e768e4CB0", + "ethUsdFeed": "0x143db3CEEfbdfe5631aDD3E50f7614B6ba708BA7", + "usdt": "0xBC14F348BC9667be46b35Edc9B68653d86013DC5", + "usdtUsdFeed": "0xEca2605f0BCF2BA5966372C99837b1F182d3D620" + }, + "push_chain": { + "chainId": 31337, + "universalCore": "0x00000000000000000000000000000000000000C0" + } +} \ No newline at end of file diff --git a/contracts/evm-gateway/foundry.toml b/contracts/evm-gateway/foundry.toml index e33f653..e8e3f9c 100644 --- a/contracts/evm-gateway/foundry.toml +++ b/contracts/evm-gateway/foundry.toml @@ -33,7 +33,8 @@ fs_permissions = [ { access = "read", path = "./out" }, { access = "read", path = "./lib" }, { access = "read", path = "./src" }, - { access = "read", path = "./test" } + { access = "read", path = "./test" }, + { access = "read", path = "./config" }, ] # remappings @@ -47,9 +48,20 @@ remappings = [ "@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/", ] -# etherscan configuration +# RPC endpoints configuration +[rpc_endpoints] +sepolia = "${SEPOLIA_RPC_URL}" +base_sepolia = "${BASE_SEPOLIA_RPC_URL}" +arb_sepolia = "${ARB_SEPOLIA_RPC_URL}" +bsc_testnet = "${BSC_TESTNET_RPC_URL}" +push_chain = "${PUSH_CHAIN_RPC_URL}" + +# Etherscan API keys for verification [etherscan] -sepolia = { key = "${process.env.ETHERSCAN_API_KEY}" } +sepolia = { key = "${ETHERSCAN_API_KEY}" } +base_sepolia = { key = "${BASESCAN_API_KEY}", url = "https://api-sepolia.basescan.org/api" } +arb_sepolia = { key = "${ARBISCAN_API_KEY}", url = "https://api-sepolia.arbiscan.io/api" } +bsc_testnet = { key = "${BSCSCAN_API_KEY}", url = "https://api-testnet.bscscan.com/api" } # FUZZ TESTING CONFIGURATION fuzz testing configuration [fuzz] @@ -166,4 +178,4 @@ fork = true # Fork URL (set your RPC endpoint) # fork_url = "https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY" # Etherscan API key for verification -# etherscan_api_key = "YOUR_ETHERSCAN_API_KEY" \ No newline at end of file +# etherscan_api_key = "YOUR_ETHERSCAN_API_KEY" diff --git a/contracts/evm-gateway/script/1_DeployGatewayWithProxy.sol b/contracts/evm-gateway/script/1_DeployGatewayWithProxy.sol deleted file mode 100644 index 05b30ec..0000000 --- a/contracts/evm-gateway/script/1_DeployGatewayWithProxy.sol +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import { Script } from "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; -import { UniversalGatewayV0 } from "../src/UniversalGatewayV0.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -/** - * @title DeployGatewayWithProxy - * @notice Single deployment script for UniversalGatewayV0 on Sepolia testnet - * @dev Deploys implementation, proxy admin, and transparent upgradeable proxy - */ -contract DeployGatewayWithProxy is Script { - // Sepolia testnet constructor args - address constant SEPOLIA_WETH = 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14; - address constant SEPOLIA_UNISWAP_V3_FACTORY = 0x0227628f3F023bb0B980b67D528571c95c6DaC1c; - address constant SEPOLIA_UNISWAP_V3_ROUTER = 0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E; - address constant SEPOLIA_ETH_USD_FEED = 0x694AA1769357215DE4FAC081bf1f309aDC325306; - address constant SEPOLIA_USDT = 0x7169D38820dfd117C3FA1f22a697dBA58d90BA06; - address constant SEPOLIA_USDT_USD_FEED = 0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E; - - address constant DEPLOYER = 0xe520d4A985A2356Fa615935a822Ce4eFAcA24aB6; - bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; - - // Role addresses (to be set by deployer) - address admin; - address pauser; - address tss; - - // Gateway configuration - uint256 constant MIN_CAP_USD = 1e18; // $1 USD (1e18 = $1) - uint256 constant MAX_CAP_USD = 10e18; // $10 USD (1e18 = $1) - - // Deployed contract addresses - address public implementationAddress; - address public proxyAddress; - - function run() external { - console.log("=== DEPLOYING UNIVERSAL GATEWAY TO SEPOLIA ==="); - - // Start broadcasting transactions - vm.startBroadcast(); - - _loadDeploymentConfig(); - - // Deploy contracts - _deployImplementation(); - _deployProxy(); - _configureGateway(); - - // Verify contracts and ADMIN CONFIGS - _verifyAllAdmins(); - _verifyDeployment(); - - vm.stopBroadcast(); - - // Log deployment summary - _logDeploymentSummary(); - } - - function _loadDeploymentConfig() internal { - console.log("\n--- Loading Deployment Configuration ---"); - - // Use deployer as admin for simplicity (can be changed later) - admin = msg.sender; - pauser = msg.sender; - tss = msg.sender; - - console.log("Admin address:", admin); - console.log("Pauser address:", pauser); - console.log("TSS address:", tss); - console.log("Min USD cap: $1"); - console.log("Max USD cap: $10"); - console.log("WETH address:", SEPOLIA_WETH); - console.log("USDT address:", SEPOLIA_USDT); - console.log("Uniswap V3 Factory:", SEPOLIA_UNISWAP_V3_FACTORY); - console.log("Uniswap V3 Router:", SEPOLIA_UNISWAP_V3_ROUTER); - console.log("ETH/USD Price Feed:", SEPOLIA_ETH_USD_FEED); - console.log("USDT/USD Price Feed:", SEPOLIA_USDT_USD_FEED); - } - - function _deployImplementation() internal { - console.log("\n--- Deploying Implementation Contract ---"); - - UniversalGatewayV0 implementation = new UniversalGatewayV0(); - implementationAddress = address(implementation); - - console.log("Implementation deployed at:", implementationAddress); - } - - function _deployProxy() internal { - console.log("\n--- Deploying Transparent Upgradeable Proxy ---"); - - // Encode initialization call - bytes memory initData = abi.encodeWithSelector( - UniversalGatewayV0.initialize.selector, - admin, // admin - pauser, // pauser - tss, // tss - MIN_CAP_USD, // minCapUsd - MAX_CAP_USD, // maxCapUsd - SEPOLIA_UNISWAP_V3_FACTORY, // factory - SEPOLIA_UNISWAP_V3_ROUTER, // router - SEPOLIA_WETH, // wethAddress - SEPOLIA_USDT, // usdtAddress - SEPOLIA_USDT_USD_FEED, // usdtUsdPriceFeed - SEPOLIA_ETH_USD_FEED // ethUsdPriceFeed - ); - - // Deploy proxy with initialization - TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(implementationAddress, DEPLOYER, initData); - - proxyAddress = address(proxy); - console.log("Proxy deployed at:", proxyAddress); - } - - function _configureGateway() internal { - console.log("\n--- Configuring Gateway ---"); - - UniversalGatewayV0 gateway = UniversalGatewayV0(payable(proxyAddress)); - - // ETH/USD price feed and USDT configuration are now set in initialize() - console.log("ETH/USD feed and USDT config set during initialization"); - - // Set a reasonable staleness period for testnet (24 hours) - console.log("Setting staleness period..."); - gateway.setChainlinkStalePeriod(24 hours); - - // No L2 sequencer feed for Sepolia (it's L1 testnet) - console.log("Disabling L2 sequencer feed for Sepolia..."); - gateway.setL2SequencerFeed(address(0)); - - console.log("Gateway configuration completed!"); - } - - function _logDeploymentSummary() internal view { - console.log("\n=== DEPLOYMENT SUMMARY ==="); - console.log("Network: Sepolia Testnet"); - console.log("Deployer:", msg.sender); - console.log(""); - console.log("Deployed Contracts:"); - console.log(" Implementation:", implementationAddress); - console.log(" Proxy (Gateway):", proxyAddress); - console.log(" Proxy Admin:", getProxyAdmin()); - console.log("Deployment completed successfully!"); - console.log(""); - console.log("Gateway Address (use this): %s", proxyAddress); - } - - function _verifyAllAdmins() internal view { - console.log("--- Admin Verification ---"); - - // Get admin of TransparentProxy - address proxyAdmin = getProxyAdmin(); - console.log("TransparentProxy admin:", proxyAdmin); - - // Get admin (owner) of ProxyAdmin - address proxyAdminOwner = getProxyAdminOwner(); - console.log("ProxyAdmin owner:", proxyAdminOwner); - - if (proxyAdminOwner == DEPLOYER) { - console.log("OK: ProxyAdmin owner correctly points to DEPLOYER"); - } else { - console.log("WARNING: ProxyAdmin owner does not point to DEPLOYER"); - } - - if (proxyAdmin != DEPLOYER) { - console.log("OK: Proxy admin is auto-deployed and accurate"); - } else { - console.log("WARNING: Proxy admin is not auto-deployed and points to DEPLOYER ADDRESS"); - } - - console.log(""); - } - - // Helper function to verify deployment - function _verifyDeployment() internal view { - require(implementationAddress != address(0), "Implementation not deployed"); - require(proxyAddress != address(0), "Proxy not deployed"); - - UniversalGatewayV0 gateway = UniversalGatewayV0(payable(proxyAddress)); - - // Basic checks - require(gateway.TSS_ADDRESS() == tss, "TSS address mismatch"); - require(gateway.MIN_CAP_UNIVERSAL_TX_USD() == MIN_CAP_USD, "Min cap mismatch"); - require(gateway.MAX_CAP_UNIVERSAL_TX_USD() == MAX_CAP_USD, "Max cap mismatch"); - require(gateway.WETH() == SEPOLIA_WETH, "WETH address mismatch"); - require(gateway.USDT() == SEPOLIA_USDT, "USDT address mismatch"); - require(address(gateway.ethUsdFeed()) == SEPOLIA_ETH_USD_FEED, "ETH/USD feed mismatch"); - require(address(gateway.usdtUsdPriceFeed()) == SEPOLIA_USDT_USD_FEED, "USDT/USD feed mismatch"); - - console.log("Deployment verification passed!"); - } - - // HELPERS - /** - * @notice Get the admin of the TransparentProxy - * @return proxyADMIN The address of the proxy admin - */ - function getProxyAdmin() public view returns (address proxyADMIN) { - // Read admin directly from the EIP-1967 admin slot on the proxy - bytes32 raw = vm.load(proxyAddress, _ADMIN_SLOT); - proxyADMIN = address(uint160(uint256(raw))); - } - - /** - * @notice Get the owner (admin) of the ProxyAdmin contract - * @return owner The address of the ProxyAdmin owner - */ - function getProxyAdminOwner() public view returns (address owner) { - address proxyADMIN = getProxyAdmin(); - - ProxyAdmin proxyAdmin = ProxyAdmin(proxyADMIN); - owner = proxyAdmin.owner(); - } -} - -// VERIFICATION COMMAND: -// 1. For TransparentUpgradeableProxy: forge verify-contract --chain sepolia --constructor-args $(cast abi-encode "constructor(address,address,bytes)" src/UniversalGatewayV0.sol:UniversalGatewayV0 -// 3. For ProxyAdmin: forge verify-contract --chain sepolia --constructor-args $(cast abi-encode "constructor(address)" ) lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol:ProxyAdmin - -// DEPLOYMENT COMMAND: -// 1. For Deployment ( Proxy, Implementation, ProxyAdmin ): forge script script/1_DeployGatewayWithProxy.sol:DeployGatewayWithProxy --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast -// 2. For Upgrade ( Proxy, Implementation, ProxyAdmin ): forge script script/3_UpgradeGatewayNewImpl.sol:UpgradeGatewayNewImpl --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast diff --git a/contracts/evm-gateway/script/2_DeployGatewayImpl.sol b/contracts/evm-gateway/script/2_DeployGatewayImpl.sol deleted file mode 100644 index 23a7274..0000000 --- a/contracts/evm-gateway/script/2_DeployGatewayImpl.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import { Script } from "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; -import { UniversalGatewayV0 } from "../src/UniversalGatewayV0.sol"; - -/** - * @title DeployGatewayImpl - * @notice Deploy only the UniversalGatewayV0 implementation contract - * @dev This script deploys just the implementation without proxy setup - * Useful for testing or when you want to deploy implementation separately - */ -contract DeployGatewayImpl is Script { - // Deployed implementation address - address public implementationAddress; - - function run() external { - console.log("=== DEPLOYING GATEWAY IMPLEMENTATION ONLY ==="); - - // Start broadcasting transactions - vm.startBroadcast(); - - // Deploy implementation - _deployImplementation(); - - vm.stopBroadcast(); - - // Log deployment summary - _logDeploymentSummary(); - } - - function _deployImplementation() internal { - console.log("\n--- Deploying Implementation Contract ---"); - - UniversalGatewayV0 implementation = new UniversalGatewayV0(); - implementationAddress = address(implementation); - - console.log("Implementation deployed at:", implementationAddress); - } - - function _logDeploymentSummary() internal view { - console.log("\n=== DEPLOYMENT SUMMARY ==="); - console.log("Network: Sepolia Testnet"); - console.log("Deployer:", msg.sender); - console.log(""); - console.log("Deployed Contract:"); - console.log(" Implementation:", implementationAddress); - console.log(""); - console.log("Note: This is just the implementation contract."); - console.log("To use it, you need to deploy a proxy pointing to this implementation."); - console.log("Use DeployGatewayToSepolia.s.sol for complete proxy deployment."); - console.log(""); - console.log("Implementation Address: %s", implementationAddress); - } - - // Helper function to verify implementation deployment - function verifyImplementation() external view { - require(implementationAddress != address(0), "Implementation not deployed"); - - // Basic check that the contract exists and is not empty - require(implementationAddress.code.length > 0, "Implementation has no code"); - - console.log("Implementation verification passed!"); - console.log("Implementation Address:", implementationAddress); - } -} diff --git a/contracts/evm-gateway/script/3_UpgradeGatewayNewImpl.sol b/contracts/evm-gateway/script/3_UpgradeGatewayNewImpl.sol deleted file mode 100644 index 12f6788..0000000 --- a/contracts/evm-gateway/script/3_UpgradeGatewayNewImpl.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import { Script } from "forge-std/Script.sol"; -import { console } from "forge-std/console.sol"; -import { UniversalGatewayV0 } from "../src/UniversalGatewayV0.sol"; -import { - TransparentUpgradeableProxy, - ITransparentUpgradeableProxy -} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -/** - * @title UpgradeGatewayNewImpl - * @notice Upgrade an existing proxy to point to a new implementation - * @dev This script upgrades a proxy to a new implementation contract - * Requires the proxy admin to execute the upgrade - */ -contract UpgradeGatewayNewImpl is Script { - // ========================= - // CONFIGURATION - // ========================= - - // Existing proxy and admin addresses (set these before running) - address constant EXISTING_PROXY = 0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A; - address constant EXISTING_PROXY_ADMIN = 0x756C0bEa91F5692384AEe147C10409BB062Bf39b; - - // New implementation address (will be deployed or set) - address public newImplementationAddress; - - function run() external { - console.log("=== UPGRADING GATEWAY PROXY ==="); - - // Load configuration - _loadUpgradeConfig(); - - // Start broadcasting transactions - vm.startBroadcast(); - - // Deploy new implementation (or use existing) - _deployNewImplementation(); - - // Upgrade the proxy - _upgradeProxy(); - - vm.stopBroadcast(); - - // Log upgrade summary - _logUpgradeSummary(); - } - - function _loadUpgradeConfig() internal view { - console.log("\n--- Loading Upgrade Configuration ---"); - require(EXISTING_PROXY != address(0), "Existing Proxy is not set"); - require(EXISTING_PROXY_ADMIN != address(0), "Existing ProxyAdmin is not set"); - console.log("Existing Proxy:", EXISTING_PROXY); - console.log("Existing ProxyAdmin:", EXISTING_PROXY_ADMIN); - console.log("Deployer:", msg.sender); - } - - function _deployNewImplementation() internal { - console.log("\n--- Deploying New Implementation ---"); - - // Deploy new implementation - UniversalGatewayV0 newImplementation = new UniversalGatewayV0(); - newImplementationAddress = address(newImplementation); - - console.log("New implementation deployed at:", newImplementationAddress); - } - - function _upgradeProxy() internal { - console.log("\n--- Upgrading Proxy ---"); - - // Get the proxy admin contract - ProxyAdmin proxyAdmin = ProxyAdmin(EXISTING_PROXY_ADMIN); - - // Check current implementation (call proxy directly in v5) - ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy(EXISTING_PROXY); - - console.log("New implementation:", newImplementationAddress); - - // Perform the upgrade using upgradeAndCall with empty data - proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); - - console.log("Proxy upgraded successfully!"); - console.log("Upgrade verified - new implementation is active"); - } - - function _logUpgradeSummary() internal view { - console.log("\n=== UPGRADE SUMMARY ==="); - console.log("Network: Sepolia Testnet"); - console.log("Deployer:", msg.sender); - console.log(""); - console.log("Upgrade Details:"); - console.log(" Proxy Address:", EXISTING_PROXY); - console.log(" ProxyAdmin Address:", EXISTING_PROXY_ADMIN); - console.log(" New Implementation:", newImplementationAddress); - console.log(""); - console.log("Proxy Address (unchanged): %s", EXISTING_PROXY); - } - - // Helper function to verify upgrade - function verifyUpgrade() external view { - require(newImplementationAddress != address(0), "New implementation not deployed"); - - // Note: In OpenZeppelin v5, we can't easily get implementation from ProxyAdmin - // This verification is simplified - the upgrade call itself will revert if it fails - console.log("Upgrade verification: Implementation was set to:", newImplementationAddress); - } -} diff --git a/contracts/evm-gateway/script/DeployCommands.md b/contracts/evm-gateway/script/DeployCommands.md deleted file mode 100644 index ea35eea..0000000 --- a/contracts/evm-gateway/script/DeployCommands.md +++ /dev/null @@ -1,35 +0,0 @@ -## VERIFICATION COMMAND: -1. For TransparentUpgradeableProxy: - -``` -forge verify-contract --chain sepolia --constructor-args $(cast abi-encode "constructor(address,address,bytes)" src/UniversalGatewayV0.sol:UniversalGatewayV0 -``` - -3. For ProxyAdmin: -``` -forge verify-contract --chain sepolia --constructor-args $(cast abi-encode "constructor(address)" ) lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol:ProxyAdmin -``` ---- - -## DEPLOYMENT COMMAND: -1. For Deployment ( Proxy, Implementation, ProxyAdmin ): -``` -forge script script/1_DeployGatewayWithProxy.sol:DeployGatewayWithProxy --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast -``` - -2. For Upgrade ( Proxy, Implementation, ProxyAdmin ): -``` -forge script script/3_UpgradeGatewayNewImpl.sol:UpgradeGatewayNewImpl --rpc-url $SEPOLIA_RPC_URL --private-key $KEY --broadcast -``` - ---- - -Deployed Contracts: - Implementation: 0x0b9fC64DD358D9A7b5B1Af93cfdA69E743b31392 - Proxy (Gateway): 0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A - Proxy Admin: 0x756C0bEa91F5692384AEe147C10409BB062Bf39b \ No newline at end of file diff --git a/contracts/evm-gateway/script/deployment/DeployUniversalGateway.sol b/contracts/evm-gateway/script/deployment/DeployUniversalGateway.sol new file mode 100644 index 0000000..069fef6 --- /dev/null +++ b/contracts/evm-gateway/script/deployment/DeployUniversalGateway.sol @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {UniversalGateway} from "../../src/UniversalGateway.sol"; +import {Vault} from "../../src/Vault.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title DeployUniversalGateway + * @notice Deploy UniversalGateway + Vault together (handles circular dependency) + */ +contract DeployUniversalGateway is Script { + using stdJson for string; + + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address weth; + address uniswapV3Factory; + address uniswapV3Router; + address ethUsdFeed; + + address admin; + address pauser; + address tss; + + uint256 constant MIN_CAP_USD = 1e18; + uint256 constant MAX_CAP_USD = 10e18; + + address public vaultImplAddress; + address public vaultProxyAddress; + address public gatewayImplAddress; + address public gatewayProxyAddress; + + function run() external { + network = vm.envOr("NETWORK", string("sepolia")); + console.log( + "=== DEPLOYING UNIVERSAL GATEWAY + VAULT TO %s ===", + network + ); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployImplementations(); + _deployProxies(); + _linkContracts(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + string memory configPath = "config/chainConfig.json"; + string memory json = vm.readFile(configPath); + string memory path = string.concat(".", network); + + weth = abi.decode( + json.parseRaw(string.concat(path, ".weth")), + (address) + ); + uniswapV3Factory = abi.decode( + json.parseRaw(string.concat(path, ".uniswapV3Factory")), + (address) + ); + uniswapV3Router = abi.decode( + json.parseRaw(string.concat(path, ".uniswapV3Router")), + (address) + ); + ethUsdFeed = abi.decode( + json.parseRaw(string.concat(path, ".ethUsdFeed")), + (address) + ); + + admin = deployer; + pauser = deployer; + tss = deployer; + + console.log("Network:", network); + console.log("Deployer:", deployer); + } + + function _deployImplementations() internal { + console.log("\n--- Deploying Implementations ---"); + + Vault vaultImpl = new Vault(); + vaultImplAddress = address(vaultImpl); + console.log("Vault Implementation:", vaultImplAddress); + + UniversalGateway gatewayImpl = new UniversalGateway(); + gatewayImplAddress = address(gatewayImpl); + console.log("Gateway Implementation:", gatewayImplAddress); + } + + function _deployProxies() internal { + console.log("\n--- Deploying Proxies ---"); + + // Deploy Gateway with placeholder vault (use impl address) + bytes memory gatewayInitData = abi.encodeWithSelector( + UniversalGateway.initialize.selector, + admin, + tss, + vaultImplAddress, // Placeholder - will update + MIN_CAP_USD, + MAX_CAP_USD, + uniswapV3Factory, + uniswapV3Router, + weth + ); + + TransparentUpgradeableProxy gatewayProxy = new TransparentUpgradeableProxy( + gatewayImplAddress, + deployer, + gatewayInitData + ); + gatewayProxyAddress = address(gatewayProxy); + console.log("Gateway Proxy:", gatewayProxyAddress); + + // Deploy Vault with Gateway address + bytes memory vaultInitData = abi.encodeWithSelector( + Vault.initialize.selector, + admin, + pauser, + tss, + gatewayProxyAddress + ); + + TransparentUpgradeableProxy vaultProxy = new TransparentUpgradeableProxy( + vaultImplAddress, + deployer, + vaultInitData + ); + vaultProxyAddress = address(vaultProxy); + console.log("Vault Proxy:", vaultProxyAddress); + } + + function _linkContracts() internal { + console.log("\n--- Linking Gateway to Vault ---"); + + UniversalGateway gateway = UniversalGateway( + payable(gatewayProxyAddress) + ); + gateway.pause(); + gateway.updateVault(vaultProxyAddress); + gateway.unpause(); + + console.log("Linked!"); + } + + function _logSummary() internal view { + console.log("\n=== DEPLOYMENT SUMMARY ==="); + console.log("Network:", network); + console.log("Vault Implementation:", vaultImplAddress); + console.log("Vault Proxy:", vaultProxyAddress); + console.log("Vault Proxy Admin:", getProxyAdmin(vaultProxyAddress)); + console.log("Gateway Implementation:", gatewayImplAddress); + console.log("Gateway Proxy:", gatewayProxyAddress); + console.log("Gateway Proxy Admin:", getProxyAdmin(gatewayProxyAddress)); + + console.log("\n*** IMPORTANT:"); + console.log( + " 1. Addresses saved to: broadcast/DeployUniversalGateway.sol/%s/run-latest.json", + block.chainid + ); + console.log(" 2. Configure Gateway after deployment:"); + console.log(" - setEthUsdFeed(%s)", ethUsdFeed); + console.log(" - setChainlinkStalePeriod(24 hours)"); + console.log(" - setL2SequencerFeed(address) if on L2"); + } + + /** + * @notice Get the admin of a TransparentProxy + * @param proxy The proxy address + * @return proxyADMIN The address of the proxy admin + */ + function getProxyAdmin( + address proxy + ) public view returns (address proxyADMIN) { + // Read admin directly from the EIP-1967 admin slot on the proxy + bytes32 raw = vm.load(proxy, _ADMIN_SLOT); + proxyADMIN = address(uint160(uint256(raw))); + } +} diff --git a/contracts/evm-gateway/script/deployment/DeployUniversalGatewayPC.sol b/contracts/evm-gateway/script/deployment/DeployUniversalGatewayPC.sol new file mode 100644 index 0000000..ac5bca1 --- /dev/null +++ b/contracts/evm-gateway/script/deployment/DeployUniversalGatewayPC.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {UniversalGatewayPC} from "../../src/UniversalGatewayPC.sol"; +import {VaultPC} from "../../src/VaultPC.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +/** + * @title DeployUniversalGatewayPC + * @notice Deploy UniversalGatewayPC + VaultPC together for Push Chain + */ +contract DeployUniversalGatewayPC is Script { + using stdJson for string; + + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address universalCore; + + address admin; + address pauser; + address fundManager; + + address public vaultPCImplAddress; + address public vaultPCProxyAddress; + address public gatewayPCImplAddress; + address public gatewayPCProxyAddress; + + function run() external { + network = vm.envOr("NETWORK", string("push_chain")); + console.log("=== DEPLOYING GATEWAY PC + VAULT PC TO %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployImplementations(); + _deployProxies(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + string memory configPath = "config/chainConfig.json"; + string memory json = vm.readFile(configPath); + string memory path = string.concat(".", network); + + universalCore = abi.decode( + json.parseRaw(string.concat(path, ".universalCore")), + (address) + ); + require( + universalCore != address(0), + "UniversalCore must be set in chainConfig.json" + ); + + admin = deployer; + pauser = deployer; + fundManager = deployer; + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("UniversalCore:", universalCore); + } + + function _deployImplementations() internal { + console.log("\n--- Deploying Implementations ---"); + + VaultPC vaultImpl = new VaultPC(); + vaultPCImplAddress = address(vaultImpl); + console.log("VaultPC Implementation:", vaultPCImplAddress); + + UniversalGatewayPC gatewayImpl = new UniversalGatewayPC(); + gatewayPCImplAddress = address(gatewayImpl); + console.log("UniversalGatewayPC Implementation:", gatewayPCImplAddress); + } + + function _deployProxies() internal { + console.log("\n--- Deploying Proxies ---"); + + // Deploy VaultPC first (no dependencies) + bytes memory vaultInitData = abi.encodeWithSelector( + VaultPC.initialize.selector, + admin, + pauser, + fundManager, + universalCore + ); + + TransparentUpgradeableProxy vaultProxy = new TransparentUpgradeableProxy( + vaultPCImplAddress, + deployer, + vaultInitData + ); + vaultPCProxyAddress = address(vaultProxy); + console.log("VaultPC Proxy:", vaultPCProxyAddress); + + // Deploy GatewayPC with VaultPC address + bytes memory gatewayInitData = abi.encodeWithSelector( + UniversalGatewayPC.initialize.selector, + admin, + pauser, + universalCore, + vaultPCProxyAddress + ); + + TransparentUpgradeableProxy gatewayProxy = new TransparentUpgradeableProxy( + gatewayPCImplAddress, + deployer, + gatewayInitData + ); + gatewayPCProxyAddress = address(gatewayProxy); + console.log("UniversalGatewayPC Proxy:", gatewayPCProxyAddress); + } + + function _logSummary() internal view { + console.log("\n=== DEPLOYMENT SUMMARY ==="); + console.log("Network:", network); + console.log("VaultPC Implementation:", vaultPCImplAddress); + console.log("VaultPC Proxy:", vaultPCProxyAddress); + console.log("VaultPC Proxy Admin:", getProxyAdmin(vaultPCProxyAddress)); + console.log("UniversalGatewayPC Implementation:", gatewayPCImplAddress); + console.log("UniversalGatewayPC Proxy:", gatewayPCProxyAddress); + console.log( + "UniversalGatewayPC Proxy Admin:", + getProxyAdmin(gatewayPCProxyAddress) + ); + console.log( + "\n Addresses saved to: broadcast/DeployUniversalGatewayPC.sol/%s/run-latest.json", + block.chainid + ); + } + + /** + * @notice Get the admin of a TransparentProxy + * @param proxy The proxy address + * @return proxyADMIN The address of the proxy admin + */ + function getProxyAdmin( + address proxy + ) public view returns (address proxyADMIN) { + // Read admin directly from the EIP-1967 admin slot on the proxy + bytes32 raw = vm.load(proxy, _ADMIN_SLOT); + proxyADMIN = address(uint160(uint256(raw))); + } +} diff --git a/contracts/evm-gateway/script/deployment/DeployUniversalGatewayV0.sol b/contracts/evm-gateway/script/deployment/DeployUniversalGatewayV0.sol new file mode 100644 index 0000000..9f7040d --- /dev/null +++ b/contracts/evm-gateway/script/deployment/DeployUniversalGatewayV0.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {UniversalGatewayV0} from "../../src/UniversalGatewayV0.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title DeployUniversalGatewayV0 + * @notice Deploy UniversalGatewayV0 (legacy version with USDT support) + */ +contract DeployUniversalGatewayV0 is Script { + using stdJson for string; + + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address weth; + address uniswapV3Factory; + address uniswapV3Router; + address ethUsdFeed; + address usdt; + address usdtUsdFeed; + + address admin; + address pauser; + address tss; + + uint256 constant MIN_CAP_USD = 1e18; + uint256 constant MAX_CAP_USD = 10e18; + + address public implementationAddress; + address public proxyAddress; + + function run() external { + network = vm.envOr("NETWORK", string("sepolia")); + console.log("=== DEPLOYING UNIVERSAL GATEWAY V0 TO %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployImplementation(); + _deployProxy(); + _configure(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + string memory configPath = "config/chainConfig.json"; + string memory json = vm.readFile(configPath); + string memory path = string.concat(".", network); + + weth = abi.decode( + json.parseRaw(string.concat(path, ".weth")), + (address) + ); + uniswapV3Factory = abi.decode( + json.parseRaw(string.concat(path, ".uniswapV3Factory")), + (address) + ); + uniswapV3Router = abi.decode( + json.parseRaw(string.concat(path, ".uniswapV3Router")), + (address) + ); + ethUsdFeed = abi.decode( + json.parseRaw(string.concat(path, ".ethUsdFeed")), + (address) + ); + usdt = abi.decode( + json.parseRaw(string.concat(path, ".usdt")), + (address) + ); + usdtUsdFeed = abi.decode( + json.parseRaw(string.concat(path, ".usdtUsdFeed")), + (address) + ); + + admin = deployer; + pauser = deployer; + tss = deployer; + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("WETH:", weth); + console.log("USDT:", usdt); + } + + function _deployImplementation() internal { + console.log("\n--- Deploying Implementation ---"); + UniversalGatewayV0 impl = new UniversalGatewayV0(); + implementationAddress = address(impl); + console.log("Implementation:", implementationAddress); + } + + function _deployProxy() internal { + console.log("\n--- Deploying Proxy ---"); + + bytes memory initData = abi.encodeWithSelector( + UniversalGatewayV0.initialize.selector, + admin, + pauser, + tss, + MIN_CAP_USD, + MAX_CAP_USD, + uniswapV3Factory, + uniswapV3Router, + weth, + usdt, + usdtUsdFeed, + ethUsdFeed + ); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + implementationAddress, + deployer, + initData + ); + + proxyAddress = address(proxy); + console.log("Proxy:", proxyAddress); + } + + function _configure() internal { + console.log("\n--- Configuring ---"); + UniversalGatewayV0 gateway = UniversalGatewayV0(payable(proxyAddress)); + + gateway.setChainlinkStalePeriod(24 hours); + gateway.setL2SequencerFeed(address(0)); + + console.log("Configuration completed"); + } + + function _logSummary() internal view { + console.log("\n=== DEPLOYMENT SUMMARY ==="); + console.log("Network:", network); + console.log("Implementation:", implementationAddress); + console.log("Proxy:", proxyAddress); + console.log("Proxy Admin:", getProxyAdmin()); + console.log("USDT:", usdt); + console.log( + "\n Addresses saved to: broadcast/DeployUniversalGatewayV0.sol/%s/run-latest.json", + block.chainid + ); + } + + /** + * @notice Get the admin of the TransparentProxy + * @return proxyADMIN The address of the proxy admin + */ + function getProxyAdmin() public view returns (address proxyADMIN) { + // Read admin directly from the EIP-1967 admin slot on the proxy + bytes32 raw = vm.load(proxyAddress, _ADMIN_SLOT); + proxyADMIN = address(uint160(uint256(raw))); + } +} diff --git a/contracts/evm-gateway/script/upgrade/UpgradeUniversalGateway.sol b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGateway.sol new file mode 100644 index 0000000..233ff75 --- /dev/null +++ b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGateway.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {UniversalGateway} from "../../src/UniversalGateway.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title UpgradeUniversalGateway + * @notice Upgrade UniversalGateway proxy to new implementation + */ +contract UpgradeUniversalGateway is Script { + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address existingProxy; + address existingProxyAdmin; + + address public newImplementationAddress; + + function run() external { + network = vm.envOr("NETWORK", string("sepolia")); + console.log("=== UPGRADING UNIVERSAL GATEWAY ON %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployNewImplementation(); + _upgradeProxy(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal view { + console.log("\n--- Loading Configuration ---"); + + existingProxy = vm.envAddress("PROXY_ADDRESS"); + require(existingProxy != address(0), "PROXY_ADDRESS env var required"); + + // Read ProxyAdmin directly from EIP-1967 admin slot + bytes32 adminSlot = vm.load(existingProxy, _ADMIN_SLOT); + existingProxyAdmin = address(uint160(uint256(adminSlot))); + + require( + existingProxyAdmin != address(0), + "ProxyAdmin address is zero - check proxy deployment" + ); + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("Existing Proxy:", existingProxy); + console.log("Existing ProxyAdmin:", existingProxyAdmin); + } + + function _deployNewImplementation() internal { + console.log("\n--- Deploying New Implementation ---"); + + UniversalGateway newImpl = new UniversalGateway(); + newImplementationAddress = address(newImpl); + + console.log("New Implementation:", newImplementationAddress); + } + + function _upgradeProxy() internal { + console.log("\n--- Upgrading Proxy ---"); + + ProxyAdmin proxyAdmin = ProxyAdmin(existingProxyAdmin); + ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( + existingProxy + ); + + proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); + + console.log("Upgrade successful!"); + } + + function _logSummary() internal view { + console.log("\n=== UPGRADE SUMMARY ==="); + console.log("Network:", network); + console.log("Proxy:", existingProxy); + console.log("ProxyAdmin:", existingProxyAdmin); + console.log("New Implementation:", newImplementationAddress); + } +} diff --git a/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayPC.sol b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayPC.sol new file mode 100644 index 0000000..36e7e1e --- /dev/null +++ b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayPC.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {UniversalGatewayPC} from "../../src/UniversalGatewayPC.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title UpgradeUniversalGatewayPC + * @notice Upgrade UniversalGatewayPC proxy to new implementation + */ +contract UpgradeUniversalGatewayPC is Script { + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address existingProxy; + address existingProxyAdmin; + + address public newImplementationAddress; + + function run() external { + network = vm.envOr("NETWORK", string("push_chain")); + console.log("=== UPGRADING UNIVERSAL GATEWAY PC ON %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployNewImplementation(); + _upgradeProxy(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + existingProxy = vm.envAddress("PROXY_ADDRESS"); + // Read ProxyAdmin directly from EIP-1967 admin slot + existingProxyAdmin = address( + uint160(uint256(vm.load(existingProxy, _ADMIN_SLOT))) + ); + + require(existingProxy != address(0), "PROXY_ADDRESS env var required"); + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("Existing Proxy:", existingProxy); + console.log("Existing ProxyAdmin:", existingProxyAdmin); + } + + function _deployNewImplementation() internal { + console.log("\n--- Deploying New Implementation ---"); + + UniversalGatewayPC newImpl = new UniversalGatewayPC(); + newImplementationAddress = address(newImpl); + + console.log("New Implementation:", newImplementationAddress); + } + + function _upgradeProxy() internal { + console.log("\n--- Upgrading Proxy ---"); + + ProxyAdmin proxyAdmin = ProxyAdmin(existingProxyAdmin); + ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( + existingProxy + ); + + proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); + + console.log("Upgrade successful!"); + } + + function _logSummary() internal view { + console.log("\n=== UPGRADE SUMMARY ==="); + console.log("Network:", network); + console.log("Proxy:", existingProxy); + console.log("ProxyAdmin:", existingProxyAdmin); + console.log("New Implementation:", newImplementationAddress); + } +} diff --git a/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayV0.sol b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayV0.sol new file mode 100644 index 0000000..0d15be3 --- /dev/null +++ b/contracts/evm-gateway/script/upgrade/UpgradeUniversalGatewayV0.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {UniversalGatewayV0} from "../../src/UniversalGatewayV0.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title UpgradeUniversalGatewayV0 + * @notice Upgrade UniversalGatewayV0 proxy to new implementation + */ +contract UpgradeUniversalGatewayV0 is Script { + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address existingProxy; + address existingProxyAdmin; + + address public newImplementationAddress; + + function run() external { + network = vm.envOr("NETWORK", string("sepolia")); + console.log("=== UPGRADING UNIVERSAL GATEWAY V0 ON %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployNewImplementation(); + _upgradeProxy(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + existingProxy = vm.envAddress("PROXY_ADDRESS"); + require(existingProxy != address(0), "PROXY_ADDRESS env var required"); + + // Read ProxyAdmin directly from EIP-1967 admin slot + bytes32 adminSlot = vm.load(existingProxy, _ADMIN_SLOT); + existingProxyAdmin = address(uint160(uint256(adminSlot))); + + require( + existingProxyAdmin != address(0), + "ProxyAdmin address is zero - check proxy deployment" + ); + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("Existing Proxy:", existingProxy); + console.log("Existing ProxyAdmin:", existingProxyAdmin); + } + + function _deployNewImplementation() internal { + console.log("\n--- Deploying New Implementation ---"); + + UniversalGatewayV0 newImpl = new UniversalGatewayV0(); + newImplementationAddress = address(newImpl); + + console.log("New Implementation:", newImplementationAddress); + } + + function _upgradeProxy() internal { + console.log("\n--- Upgrading Proxy ---"); + + ProxyAdmin proxyAdmin = ProxyAdmin(existingProxyAdmin); + ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( + existingProxy + ); + + proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); + + console.log("Upgrade successful!"); + } + + function _logSummary() internal view { + console.log("\n=== UPGRADE SUMMARY ==="); + console.log("Network:", network); + console.log("Proxy:", existingProxy); + console.log("ProxyAdmin:", existingProxyAdmin); + console.log("New Implementation:", newImplementationAddress); + } +} diff --git a/contracts/evm-gateway/script/upgrade/UpgradeVault.sol b/contracts/evm-gateway/script/upgrade/UpgradeVault.sol new file mode 100644 index 0000000..47c5181 --- /dev/null +++ b/contracts/evm-gateway/script/upgrade/UpgradeVault.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {Vault} from "../../src/Vault.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title UpgradeVault + * @notice Upgrade Vault proxy to new implementation + */ +contract UpgradeVault is Script { + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address existingProxy; + address existingProxyAdmin; + + address public newImplementationAddress; + + function run() external { + network = vm.envOr("NETWORK", string("sepolia")); + console.log("=== UPGRADING VAULT ON %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployNewImplementation(); + _upgradeProxy(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + existingProxy = vm.envAddress("PROXY_ADDRESS"); + // Read ProxyAdmin directly from EIP-1967 admin slot + existingProxyAdmin = address( + uint160(uint256(vm.load(existingProxy, _ADMIN_SLOT))) + ); + + require(existingProxy != address(0), "PROXY_ADDRESS env var required"); + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("Existing Proxy:", existingProxy); + console.log("Existing ProxyAdmin:", existingProxyAdmin); + } + + function _deployNewImplementation() internal { + console.log("\n--- Deploying New Implementation ---"); + + Vault newImpl = new Vault(); + newImplementationAddress = address(newImpl); + + console.log("New Implementation:", newImplementationAddress); + } + + function _upgradeProxy() internal { + console.log("\n--- Upgrading Proxy ---"); + + ProxyAdmin proxyAdmin = ProxyAdmin(existingProxyAdmin); + ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( + existingProxy + ); + + proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); + + console.log("Upgrade successful!"); + } + + function _logSummary() internal view { + console.log("\n=== UPGRADE SUMMARY ==="); + console.log("Network:", network); + console.log("Proxy:", existingProxy); + console.log("ProxyAdmin:", existingProxyAdmin); + console.log("New Implementation:", newImplementationAddress); + } +} diff --git a/contracts/evm-gateway/script/upgrade/UpgradeVaultPC.sol b/contracts/evm-gateway/script/upgrade/UpgradeVaultPC.sol new file mode 100644 index 0000000..8ec2058 --- /dev/null +++ b/contracts/evm-gateway/script/upgrade/UpgradeVaultPC.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {VaultPC} from "../../src/VaultPC.sol"; +import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +/** + * @title UpgradeVaultPC + * @notice Upgrade VaultPC proxy to new implementation + */ +contract UpgradeVaultPC is Script { + bytes32 internal constant _ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + string network; + address deployer; + address existingProxy; + address existingProxyAdmin; + + address public newImplementationAddress; + + function run() external { + network = vm.envOr("NETWORK", string("push_chain")); + console.log("=== UPGRADING VAULT PC ON %s ===", network); + + string memory envKey = string.concat("PRIVATE_KEY_", network); + uint256 deployerKey = vm.envUint(envKey); + deployer = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + _loadConfig(); + _deployNewImplementation(); + _upgradeProxy(); + + vm.stopBroadcast(); + + _logSummary(); + } + + function _loadConfig() internal { + console.log("\n--- Loading Configuration ---"); + + existingProxy = vm.envAddress("PROXY_ADDRESS"); + // Read ProxyAdmin directly from EIP-1967 admin slot + existingProxyAdmin = address( + uint160(uint256(vm.load(existingProxy, _ADMIN_SLOT))) + ); + + require(existingProxy != address(0), "PROXY_ADDRESS env var required"); + + console.log("Network:", network); + console.log("Deployer:", deployer); + console.log("Existing Proxy:", existingProxy); + console.log("Existing ProxyAdmin:", existingProxyAdmin); + } + + function _deployNewImplementation() internal { + console.log("\n--- Deploying New Implementation ---"); + + VaultPC newImpl = new VaultPC(); + newImplementationAddress = address(newImpl); + + console.log("New Implementation:", newImplementationAddress); + } + + function _upgradeProxy() internal { + console.log("\n--- Upgrading Proxy ---"); + + ProxyAdmin proxyAdmin = ProxyAdmin(existingProxyAdmin); + ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy( + existingProxy + ); + + proxyAdmin.upgradeAndCall(proxy, newImplementationAddress, ""); + + console.log("Upgrade successful!"); + } + + function _logSummary() internal view { + console.log("\n=== UPGRADE SUMMARY ==="); + console.log("Network:", network); + console.log("Proxy:", existingProxy); + console.log("ProxyAdmin:", existingProxyAdmin); + console.log("New Implementation:", newImplementationAddress); + } +}