#!/usr/bin/env bash # Force Deploy LINK Token - All Methods # Tries multiple approaches to force forge to broadcast set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "$PROJECT_ROOT/.env" 2>/dev/null || source "$PROJECT_ROOT/../.env" 2>/dev/null || true RPC_URL="${RPC_URL_138:-http://192.168.11.250:8545}" FORCE_GAS="${1:-5000000000}" # Default 5 gwei (increased for better confirmation) # Export variables to ensure they're available in subshells export RPC_URL export PRIVATE_KEY echo "╔══════════════════════════════════════════════════════════════╗" echo "║ FORCE DEPLOY LINK TOKEN - ALL METHODS ║" echo "╚══════════════════════════════════════════════════════════════╝" echo "" echo "RPC: $RPC_URL" echo "Forced Gas: $(echo "scale=2; $FORCE_GAS / 1000000000" | bc) gwei" echo "" TEMP_DIR=$(mktemp -d) trap "rm -rf $TEMP_DIR" EXIT cd "$TEMP_DIR" forge init --no-git --force . > /dev/null 2>&1 cat > src/MockLinkToken.sol << 'EOF' // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; contract MockLinkToken { string public name = "Chainlink Token"; string public symbol = "LINK"; uint8 public decimals = 18; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; uint256 public totalSupply; event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function mint(address to, uint256 amount) external { balanceOf[to] += amount; totalSupply += amount; emit Transfer(address(0), to, amount); } function transfer(address to, uint256 amount) external returns (bool) { require(balanceOf[msg.sender] >= amount, "insufficient balance"); balanceOf[msg.sender] -= amount; balanceOf[to] += amount; emit Transfer(msg.sender, to, amount); return true; } function transferFrom(address from, address to, uint256 amount) external returns (bool) { require(balanceOf[from] >= amount, "insufficient balance"); require(allowance[from][msg.sender] >= amount, "insufficient allowance"); balanceOf[from] -= amount; balanceOf[to] += amount; allowance[from][msg.sender] -= amount; emit Transfer(from, to, amount); return true; } function approve(address spender, uint256 amount) external returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } } EOF cat > script/DeployLink.s.sol << 'EOF' // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Script, console} from "forge-std/Script.sol"; import {MockLinkToken} from "../src/MockLinkToken.sol"; contract DeployLink is Script { function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); MockLinkToken link = new MockLinkToken(); console.log("LINK_TOKEN_ADDRESS", address(link)); link.mint(vm.addr(deployerPrivateKey), 1_000_000e18); vm.stopBroadcast(); } } EOF cat > foundry.toml << EOF [profile.default] gas_price = $FORCE_GAS legacy = true [rpc_endpoints] chain138 = "$RPC_URL" EOF export PRIVATE_KEY echo "=== Method 1: forge script with --broadcast --skip-simulation ===" DEPLOY_OUTPUT=$(forge script script/DeployLink.s.sol:DeployLink \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ --skip-simulation \ --gas-price "$FORCE_GAS" \ --legacy \ -vv 2>&1) || true LINK_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE "LINK_TOKEN_ADDRESS[[:space:]]+0x[0-9a-fA-F]{40}" | awk '{print $2}' || echo "") # Verify broadcast actually happened if echo "$DEPLOY_OUTPUT" | grep -qi "dry run\|simulation only\|not broadcasting"; then echo "⚠️ WARNING: Script may have run in dry-run mode despite --broadcast flag" echo "Output contains dry-run indicators" LINK_ADDRESS="" # Clear address if dry-run detected fi # Verify deployment actually happened on-chain (not just simulation) if [ -n "$LINK_ADDRESS" ] && [ ${#LINK_ADDRESS} -eq 42 ]; then echo "Address extracted: $LINK_ADDRESS" echo "Verifying on-chain deployment (waiting 15 seconds)..." sleep 15 # Wait for transaction to propagate CODE=$(cast code "$LINK_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "") if [ -n "$CODE" ] && [ "$CODE" != "0x" ] && [ ${#CODE} -gt 100 ]; then echo "✓✓✓ SUCCESS! LINK deployed and CONFIRMED: $LINK_ADDRESS" echo "$LINK_ADDRESS" > /tmp/link_address.txt exit 0 else echo "⚠️ Address extracted but contract not yet on-chain" echo "This may be from simulation. Trying Method 2..." LINK_ADDRESS="" # Clear to force Method 2 fi fi echo "Method 1 failed, trying Method 2..." echo "" echo "=== Method 2: forge create with explicit gas and verify ===" # Ensure RPC_URL is set and not empty if [ -z "$RPC_URL" ]; then echo "ERROR: RPC_URL is not set!" RPC_URL="http://192.168.11.250:8545" echo "Using default: $RPC_URL" export RPC_URL fi # Ensure PRIVATE_KEY is set if [ -z "$PRIVATE_KEY" ]; then echo "ERROR: PRIVATE_KEY is not set!" echo "Cannot deploy without private key" exit 1 fi echo "Deploying with forge create (this may take a moment)..." DEPLOY_OUTPUT=$(forge create src/MockLinkToken.sol:MockLinkToken \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$FORCE_GAS" \ --gas-limit 10000000 \ --legacy \ --broadcast \ 2>&1) || true echo "Deployment output:" echo "$DEPLOY_OUTPUT" | head -20 LINK_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE "Deployed to: 0x[0-9a-fA-F]{40}" | awk '{print $3}' || echo "") # Also check for errors if echo "$DEPLOY_OUTPUT" | grep -qi "error\|fail\|revert"; then echo "⚠️ Deployment errors detected in output above" fi if [ -n "$LINK_ADDRESS" ] && [ ${#LINK_ADDRESS} -eq 42 ]; then echo "✓✓✓ SUCCESS! LINK deployed: $LINK_ADDRESS" echo "$LINK_ADDRESS" > /tmp/link_address.txt exit 0 fi echo "Method 2 failed, trying Method 3..." echo "" echo "=== Method 3: Get bytecode and deploy via cast send ===" forge build > /dev/null 2>&1 BYTECODE=$(cat out/MockLinkToken.sol/MockLinkToken.json | jq -r '.bytecode.object' 2>/dev/null || echo "") if [ -n "$BYTECODE" ] && [ "$BYTECODE" != "null" ] && [ ${#BYTECODE} -gt 100 ]; then ACCOUNT=$(cast wallet address "$PRIVATE_KEY") NONCE=$(cast nonce "$ACCOUNT" --rpc-url "$RPC_URL") echo "Deploying via cast send..." TX_OUTPUT=$(timeout 60 cast send --create "$BYTECODE" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$FORCE_GAS" \ --nonce "$NONCE" \ --legacy \ 2>&1) || true LINK_ADDRESS=$(echo "$TX_OUTPUT" | grep -oE "contractAddress[[:space:]]+0x[0-9a-fA-F]{40}" | awk '{print $2}' || echo "") if [ -z "$LINK_ADDRESS" ]; then LINK_ADDRESS=$(echo "$TX_OUTPUT" | grep -oE "0x[0-9a-fA-F]{40}" | head -1 || echo "") fi if [ -n "$LINK_ADDRESS" ] && [ ${#LINK_ADDRESS} -eq 42 ]; then echo "✓✓✓ SUCCESS! LINK deployed: $LINK_ADDRESS" echo "$LINK_ADDRESS" > /tmp/link_address.txt exit 0 fi fi echo "" echo "╔══════════════════════════════════════════════════════════════╗" echo "║ ALL METHODS FAILED ║" echo "╚══════════════════════════════════════════════════════════════╝" echo "" echo "Possible issues:" echo "1. Network RPC not responding" echo "2. Stuck transaction at nonce 37 blocking new transactions" echo "3. Network requires different gas configuration" echo "4. Private key or account issues" echo "" echo "Recommendation: Use Remix IDE to deploy" echo " https://remix.ethereum.org" echo "" exit 1