#!/usr/bin/env bash # Deploy LINK Token and Verify Confirmation # This script actually waits for network confirmation set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "$PROJECT_ROOT/scripts/lib/address-inventory.sh" load_explorer_runtime_env RPC_URL="${RPC_URL_138:-http://192.168.11.250:8545}" GAS_PRICE="${1:-$(cast --to-wei 20 gwei)}" ACCOUNT=$(cast wallet address "$PRIVATE_KEY") echo "╔══════════════════════════════════════════════════════════════╗" echo "║ DEPLOY AND VERIFY LINK TOKEN ║" echo "╚══════════════════════════════════════════════════════════════╝" echo "" echo "Account: $ACCOUNT" echo "RPC: $RPC_URL" echo "Gas: $(echo "scale=2; $GAS_PRICE / 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 export PRIVATE_KEY echo "=== Compiling ===" forge build > /dev/null 2>&1 echo "✓ Compiled" echo "" echo "=== Deploying ===" DEPLOY_OUTPUT=$(forge script script/DeployLink.s.sol:DeployLink \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ --skip-simulation \ --gas-price "$GAS_PRICE" \ --legacy \ -vv 2>&1) || true # Extract address from console output LINK_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE "LINK_TOKEN_ADDRESS[[:space:]]+0x[0-9a-fA-F]{40}" | awk '{print $2}' || echo "") if [ -z "$LINK_ADDRESS" ] || [ ${#LINK_ADDRESS} -ne 42 ]; then echo "❌ Failed to extract deployment address" echo "Output:" echo "$DEPLOY_OUTPUT" | tail -20 exit 1 fi echo "✓ Transaction sent: $LINK_ADDRESS" echo "" echo "=== Waiting for Network Confirmation ===" echo "This may take 1-5 minutes..." echo "" MAX_WAIT=300 # 5 minutes ELAPSED=0 CONFIRMED=false while [ $ELAPSED -lt $MAX_WAIT ]; do CODE=$(cast code "$LINK_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "") if [ -n "$CODE" ] && [ "$CODE" != "0x" ] && [ ${#CODE} -gt 100 ]; then echo "✅✅✅ CONFIRMED!" echo "Address: $LINK_ADDRESS" echo "Bytecode: ${#CODE} chars" CONFIRMED=true break fi if [ $((ELAPSED % 30)) -eq 0 ]; then echo " Waiting... (${ELAPSED}s / ${MAX_WAIT}s)" fi sleep 10 ELAPSED=$((ELAPSED + 10)) done if [ "$CONFIRMED" != "true" ]; then echo "" echo "⏳ Deployment not confirmed after ${MAX_WAIT} seconds" echo "Address: $LINK_ADDRESS" echo "Check manually: cast code $LINK_ADDRESS --rpc-url $RPC_URL" echo "" echo "Possible reasons:" echo "1. Network is slow to confirm" echo "2. Transaction may have failed" echo "3. RPC node may be out of sync" echo "" echo "Check block explorer: https://explorer.d-bis.org/address/$ACCOUNT" exit 1 fi echo "" echo "=== Updating address inventory ===" persist_inventory_value "LINK_TOKEN" "$LINK_ADDRESS" persist_inventory_value "CCIP_CHAIN138_FEE_TOKEN" "$LINK_ADDRESS" echo "✓ Updated config/address-inventory.json" echo "" echo "=== Verifying Token Functions ===" NAME=$(cast call "$LINK_ADDRESS" "name()" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-ascii 2>/dev/null | tr -d '\0' || echo "") SYMBOL=$(cast call "$LINK_ADDRESS" "symbol()" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-ascii 2>/dev/null | tr -d '\0' || echo "") BALANCE=$(cast call "$LINK_ADDRESS" "balanceOf(address)" "$ACCOUNT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") BALANCE_ETH=$(cast --from-wei "$BALANCE" ether 2>/dev/null || echo "0") echo "Name: $NAME" echo "Symbol: $SYMBOL" echo "Account Balance: $BALANCE_ETH LINK" echo "" if (( $(echo "$BALANCE_ETH < 20" | bc -l 2>/dev/null || echo 1) )); then echo "=== Minting Additional Tokens ===" MINT_AMOUNT="1000000000000000000000000" cast send "$LINK_ADDRESS" "mint(address,uint256)" "$ACCOUNT" "$MINT_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$GAS_PRICE" \ --legacy \ 2>&1 | tail -3 echo "Waiting 20 seconds for mint confirmation..." sleep 20 BALANCE=$(cast call "$LINK_ADDRESS" "balanceOf(address)" "$ACCOUNT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") BALANCE_ETH=$(cast --from-wei "$BALANCE" ether 2>/dev/null || echo "0") echo "New Balance: $BALANCE_ETH LINK" echo "" fi echo "✅✅✅ LINK TOKEN DEPLOYMENT COMPLETE!" echo "Address: $LINK_ADDRESS" echo ""