208 lines
6.8 KiB
Bash
Executable File
208 lines
6.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Deploy Smart Contract via eth_sendSignedTransaction (JSON-RPC)
|
|
# Bypasses forge and uses direct JSON-RPC calls
|
|
|
|
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}"
|
|
PRIVATE_KEY="${PRIVATE_KEY:-}"
|
|
GAS_PRICE="${1:-20000000000}" # 20 gwei
|
|
GAS_LIMIT="${2:-10000000}" # 10M gas
|
|
|
|
if [ -z "$PRIVATE_KEY" ]; then
|
|
echo "Error: PRIVATE_KEY not set"
|
|
exit 1
|
|
fi
|
|
|
|
DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || echo "")
|
|
if [ -z "$DEPLOYER" ]; then
|
|
echo "Error: Invalid PRIVATE_KEY"
|
|
exit 1
|
|
fi
|
|
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
echo "║ DEPLOY CONTRACT VIA eth_sendSignedTransaction ║"
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
echo ""
|
|
echo "RPC: $RPC_URL"
|
|
echo "Deployer: $DEPLOYER"
|
|
echo "Gas Price: $GAS_PRICE"
|
|
echo "Gas Limit: $GAS_LIMIT"
|
|
echo ""
|
|
|
|
# Step 1: Compile contract
|
|
echo "Step 1: Compiling contract..."
|
|
TEMP_DIR=$(mktemp -d)
|
|
cd "$TEMP_DIR"
|
|
|
|
forge init --no-git --force . > /dev/null 2>&1
|
|
|
|
# Create minimal test contract
|
|
cat > src/TestMinimal.sol << 'EOF'
|
|
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
contract TestMinimal {
|
|
uint256 public x = 1;
|
|
|
|
function setX(uint256 _x) external {
|
|
x = _x;
|
|
}
|
|
}
|
|
EOF
|
|
|
|
forge build > /dev/null 2>&1
|
|
|
|
# Get bytecode
|
|
BYTECODE=$(cat out/TestMinimal.sol/TestMinimal.json | jq -r '.bytecode.object' 2>/dev/null || echo "")
|
|
if [ -z "$BYTECODE" ] || [ "$BYTECODE" = "null" ]; then
|
|
echo "❌ Failed to compile contract"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Contract compiled (bytecode length: ${#BYTECODE} chars)"
|
|
echo ""
|
|
|
|
# Step 2: Get nonce
|
|
echo "Step 2: Getting deployer nonce..."
|
|
NONCE=$(cast nonce "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
|
|
NONCE_HEX=$(printf "0x%x" "$NONCE")
|
|
echo "Nonce: $NONCE ($NONCE_HEX)"
|
|
echo ""
|
|
|
|
# Step 3: Get chain ID
|
|
echo "Step 3: Getting chain ID..."
|
|
CHAIN_ID=$(cast chain-id --rpc-url "$RPC_URL" 2>/dev/null || echo "138")
|
|
CHAIN_ID_HEX=$(printf "0x%x" "$CHAIN_ID")
|
|
echo "Chain ID: $CHAIN_ID ($CHAIN_ID_HEX)"
|
|
echo ""
|
|
|
|
# Step 4: Create transaction
|
|
echo "Step 4: Creating transaction..."
|
|
echo "Transaction details:"
|
|
echo " From: $DEPLOYER"
|
|
echo " To: null (contract creation)"
|
|
echo " Value: 0"
|
|
echo " Data: $BYTECODE (first 100 chars: ${BYTECODE:0:100}...)"
|
|
echo " Gas: $GAS_LIMIT"
|
|
echo " Gas Price: $GAS_PRICE"
|
|
echo " Nonce: $NONCE"
|
|
echo " Chain ID: $CHAIN_ID"
|
|
echo ""
|
|
|
|
# Step 5: Deploy using cast send directly
|
|
echo "Step 5: Deploying contract using cast send..."
|
|
echo "This uses eth_sendTransaction internally..."
|
|
echo ""
|
|
|
|
TX_HASH=$(cast send --private-key "$PRIVATE_KEY" \
|
|
--rpc-url "$RPC_URL" \
|
|
--gas "$GAS_LIMIT" \
|
|
--gas-price "$GAS_PRICE" \
|
|
--nonce "$NONCE" \
|
|
--value 0 \
|
|
--data "$BYTECODE" \
|
|
--legacy \
|
|
--json 2>/dev/null | jq -r '.transactionHash // empty' 2>/dev/null || echo "")
|
|
|
|
if [ -z "$TX_HASH" ]; then
|
|
echo "❌ Failed to send transaction via cast send"
|
|
echo ""
|
|
echo "Trying alternative: Create raw transaction and send via JSON-RPC..."
|
|
|
|
# Create raw transaction
|
|
RAW_TX=$(cast tx --from "$DEPLOYER" \
|
|
--to "" \
|
|
--nonce "$NONCE" \
|
|
--gas "$GAS_LIMIT" \
|
|
--gas-price "$GAS_PRICE" \
|
|
--value 0 \
|
|
--data "$BYTECODE" \
|
|
--chain "$CHAIN_ID" \
|
|
--rpc-url "$RPC_URL" \
|
|
--json 2>/dev/null | jq -r '.raw // empty' 2>/dev/null || echo "")
|
|
|
|
if [ -n "$RAW_TX" ]; then
|
|
echo "✅ Created raw transaction"
|
|
echo "Sending via eth_sendRawTransaction..."
|
|
|
|
RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
|
|
--data "{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"$RAW_TX\"],\"id\":1}" \
|
|
"$RPC_URL" 2>&1)
|
|
|
|
TX_HASH=$(echo "$RESPONSE" | jq -r '.result // empty' 2>/dev/null || echo "")
|
|
|
|
if [ -z "$TX_HASH" ] || [ "$TX_HASH" = "null" ]; then
|
|
ERROR=$(echo "$RESPONSE" | jq -r '.error.message // empty' 2>/dev/null || echo "")
|
|
echo "❌ Error: $ERROR"
|
|
echo "Response: $RESPONSE"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Step 6: Wait for confirmation
|
|
if [ -n "$TX_HASH" ] && [ "$TX_HASH" != "null" ]; then
|
|
echo "✅ Transaction sent: $TX_HASH"
|
|
echo ""
|
|
echo "Waiting for confirmation..."
|
|
sleep 15
|
|
|
|
RECEIPT=$(cast receipt "$TX_HASH" --rpc-url "$RPC_URL" --json 2>/dev/null || echo "")
|
|
if [ -n "$RECEIPT" ]; then
|
|
STATUS=$(echo "$RECEIPT" | jq -r '.status // empty' 2>/dev/null || echo "")
|
|
CONTRACT=$(echo "$RECEIPT" | jq -r '.contractAddress // empty' 2>/dev/null || echo "")
|
|
GAS_USED=$(echo "$RECEIPT" | jq -r '.gasUsed // empty' 2>/dev/null || echo "")
|
|
|
|
echo "Transaction Receipt:"
|
|
echo " Status: $STATUS"
|
|
echo " Gas Used: $GAS_USED"
|
|
echo " Contract Address: $CONTRACT"
|
|
echo ""
|
|
|
|
if [ "$STATUS" = "0x1" ]; then
|
|
echo "✅ Contract deployed successfully!"
|
|
|
|
# Verify contract exists
|
|
CODE=$(cast code "$CONTRACT" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
|
|
if [ -n "$CODE" ] && [ "$CODE" != "0x" ] && [ ${#CODE} -gt 100 ]; then
|
|
echo "✅ Contract verified on-chain (${#CODE} chars)"
|
|
echo ""
|
|
echo "Contract Address: $CONTRACT"
|
|
echo "Save this address for future use!"
|
|
else
|
|
echo "⚠️ Contract code not found on-chain"
|
|
fi
|
|
else
|
|
echo "❌ Transaction failed (status: $STATUS)"
|
|
echo "Contract Address: $CONTRACT"
|
|
echo ""
|
|
echo "If DEBUG API is enabled, get revert reason:"
|
|
echo " curl -X POST -H 'Content-Type: application/json' \\"
|
|
echo " --data '{\"jsonrpc\":\"2.0\",\"method\":\"debug_traceTransaction\",\"params\":[\"$TX_HASH\",{\"tracer\":\"callTracer\"}],\"id\":1}' \\"
|
|
echo " $RPC_URL | jq"
|
|
fi
|
|
else
|
|
echo "⏳ Transaction not yet confirmed"
|
|
echo "Transaction Hash: $TX_HASH"
|
|
echo "Check status later with: cast receipt $TX_HASH --rpc-url $RPC_URL"
|
|
fi
|
|
else
|
|
echo "❌ Could not deploy contract"
|
|
echo ""
|
|
echo "Troubleshooting:"
|
|
echo " 1. Check deployer balance: cast balance $DEPLOYER --rpc-url $RPC_URL"
|
|
echo " 2. Verify RPC is accessible: cast block-number --rpc-url $RPC_URL"
|
|
echo " 3. Check network allows contract creation"
|
|
fi
|
|
|
|
cd "$PROJECT_ROOT"
|
|
rm -rf "$TEMP_DIR"
|
|
|
|
echo ""
|
|
|