#!/usr/bin/env python3 """ Deployment script for OpenLearnX smart contracts """ import os import json from pathlib import Path from web3 import Web3 from eth_account import Account from dotenv import load_dotenv # Load environment variables from backend/.env BASE_DIR = Path(__file__).resolve().parent.parent load_dotenv(BASE_DIR / ".env") def deploy_contract(): # Load environment variables provider_url = os.getenv('WEB3_PROVIDER_URL', 'http://127.0.0.1:8545') private_key = os.getenv('DEPLOYER_PRIVATE_KEY') if not private_key: raise ValueError("DEPLOYER_PRIVATE_KEY environment variable required") # Connect to Web3 w3 = Web3(Web3.HTTPProvider(provider_url)) if not w3.is_connected(): raise Exception(f"Failed to connect to {provider_url}") account = Account.from_key(private_key) print(f"Deploying from account: {account.address}") print(f"Balance: {w3.eth.get_balance(account.address) / 10**18} ETH") # Load contract bytecode and ABI contract_path = BASE_DIR / "out" / "CertificateNFT.sol" / "CertificateNFT.json" if not contract_path.exists(): print("Contract not compiled. Running forge build...") import subprocess result = subprocess.run(["forge", "build"], cwd=BASE_DIR, capture_output=True, text=True) if result.returncode != 0: raise Exception(f"forge build failed: {result.stderr}") with open(contract_path, 'r') as f: contract_data = json.load(f) # Deploy contract contract = w3.eth.contract( abi=contract_data['abi'], bytecode=contract_data['bytecode']['object'] ) # Build transaction with higher gas limit transaction = contract.constructor().build_transaction({ 'from': account.address, 'nonce': w3.eth.get_transaction_count(account.address), 'gas': 5000000, # Increased gas limit 'gasPrice': w3.to_wei('20', 'gwei') }) # Sign and send transaction signed_txn = w3.eth.account.sign_transaction(transaction, private_key) tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction) print(f"Transaction hash: {tx_hash.hex()}") # Wait for receipt with timeout try: receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=300) # Check if transaction was successful if receipt.status == 0: raise Exception("Transaction failed - check gas limit and contract code") contract_address = receipt.contractAddress if not contract_address: raise Exception("Contract address is None - deployment failed") print(f"Contract deployed at: {contract_address}") print(f"Gas used: {receipt.gasUsed}") print(f"Transaction status: {'Success' if receipt.status == 1 else 'Failed'}") except Exception as e: print(f"Error waiting for transaction receipt: {e}") return None # Save deployment info deployment_info = { 'contract_address': contract_address, 'transaction_hash': tx_hash.hex(), 'deployer': account.address, 'network': 'local' if 'localhost' in provider_url or '127.0.0.1' in provider_url else 'unknown', 'abi': contract_data['abi'], 'gas_used': receipt.gasUsed, 'block_number': receipt.blockNumber, 'status': receipt.status } deployment_file = BASE_DIR / "deployment.json" with open(deployment_file, 'w') as f: json.dump(deployment_info, f, indent=2) print(f"Deployment info saved to: {deployment_file}") print(f"\nAdd this to your .env file:") print(f"CONTRACT_ADDRESS={contract_address}") return contract_address if __name__ == '__main__': try: contract_address = deploy_contract() if contract_address: print(f"\nāœ… Deployment successful!") print(f"Contract Address: {contract_address}") else: print(f"\nāŒ Deployment failed!") except Exception as e: print(f"āŒ Deployment failed: {e}")