|
| 1 | +from web3 import Web3 |
| 2 | +from eth_account import Account |
| 3 | +from solcx import compile_standard, install_solc |
| 4 | +import json |
| 5 | +import os |
| 6 | + |
| 7 | +# Connect to Calypso Mainnet |
| 8 | +RPC_URL = "https://mainnet.skalenodes.com/v1/honorable-steel-rasalhague" |
| 9 | +CHAIN_ID = 1564830818 |
| 10 | + |
| 11 | +print("Connecting to SKALE Calypso...") |
| 12 | +w3 = Web3(Web3.HTTPProvider(RPC_URL)) |
| 13 | +assert w3.is_connected(), "Failed to connect to network" |
| 14 | +print("Connected successfully") |
| 15 | + |
| 16 | +# Account setup |
| 17 | +private_key = "1c734d612698d2f21bc54a6ed073f7cfa6920d02f346a7f15c7f0c5310cc0108" |
| 18 | +account = Account.from_key(private_key) |
| 19 | +print(f"Using account: {account.address}") |
| 20 | + |
| 21 | +# Check balance |
| 22 | +balance = w3.eth.get_balance(account.address) |
| 23 | +print(f"Balance: {w3.from_wei(balance, \"ether\")} sFUEL") |
| 24 | +
|
| 25 | +# Program Contract |
| 26 | +contract_source = """ |
| 27 | +// SPDX-License-Identifier: MIT |
| 28 | +pragma solidity ^0.8.20; |
| 29 | +
|
| 30 | +contract DreamProgram { |
| 31 | + address public owner; |
| 32 | + mapping(address => bool) public operators; |
| 33 | + mapping(address => uint256) public dreamCount; |
| 34 | + uint256 public totalDreams; |
| 35 | + |
| 36 | + event DreamRecorded(address indexed dreamer, string dream, uint256 dreamId); |
| 37 | + event OperatorAdded(address indexed operator); |
| 38 | + event OperatorRemoved(address indexed operator); |
| 39 | + |
| 40 | + constructor() { |
| 41 | + owner = msg.sender; |
| 42 | + operators[msg.sender] = true; |
| 43 | + } |
| 44 | + |
| 45 | + modifier onlyOwner() { |
| 46 | + require(msg.sender == owner, "Not owner"); |
| 47 | + _; |
| 48 | + } |
| 49 | + |
| 50 | + modifier onlyOperator() { |
| 51 | + require(operators[msg.sender], "Not operator"); |
| 52 | + _; |
| 53 | + } |
| 54 | + |
| 55 | + function addOperator(address operator) external onlyOwner { |
| 56 | + require(operator != address(0), "Zero address"); |
| 57 | + operators[operator] = true; |
| 58 | + emit OperatorAdded(operator); |
| 59 | + } |
| 60 | + |
| 61 | + function removeOperator(address operator) external onlyOwner { |
| 62 | + require(operator != owner, "Cannot remove owner"); |
| 63 | + require(operator != address(0), "Zero address"); |
| 64 | + operators[operator] = false; |
| 65 | + emit OperatorRemoved(operator); |
| 66 | + } |
| 67 | + |
| 68 | + function recordDream(string calldata dream) external { |
| 69 | + uint256 dreamId = totalDreams + 1; |
| 70 | + totalDreams = dreamId; |
| 71 | + dreamCount[msg.sender]++; |
| 72 | + emit DreamRecorded(msg.sender, dream, dreamId); |
| 73 | + } |
| 74 | + |
| 75 | + function getDreamerStats(address dreamer) external view returns (uint256) { |
| 76 | + return dreamCount[dreamer]; |
| 77 | + } |
| 78 | + |
| 79 | + function transferOwnership(address newOwner) external onlyOwner { |
| 80 | + require(newOwner != address(0), "Zero address"); |
| 81 | + owner = newOwner; |
| 82 | + } |
| 83 | +} |
| 84 | +""" |
| 85 | +
|
| 86 | +print("\nCompiling contract...") |
| 87 | +install_solc("0.8.20") |
| 88 | +
|
| 89 | +compiled = compile_standard( |
| 90 | + { |
| 91 | + "language": "Solidity", |
| 92 | + "sources": {"DreamProgram.sol": {"content": contract_source}}, |
| 93 | + "settings": { |
| 94 | + "outputSelection": { |
| 95 | + "*": {"*": ["abi", "evm.bytecode"]} |
| 96 | + }, |
| 97 | + "optimizer": { |
| 98 | + "enabled": True, |
| 99 | + "runs": 200 |
| 100 | + } |
| 101 | + } |
| 102 | + }, |
| 103 | + solc_version="0.8.20" |
| 104 | +) |
| 105 | + |
| 106 | +# Get bytecode and ABI |
| 107 | +contract_interface = compiled["contracts"]["DreamProgram.sol"]["DreamProgram"] |
| 108 | +bytecode = contract_interface["evm"]["bytecode"]["object"] |
| 109 | +abi = contract_interface["abi"] |
| 110 | + |
| 111 | +# Create contract |
| 112 | +Contract = w3.eth.contract(abi=abi, bytecode=bytecode) |
| 113 | + |
| 114 | +# Get nonce |
| 115 | +nonce = w3.eth.get_transaction_count(account.address) |
| 116 | + |
| 117 | +print("\nPreparing transaction...") |
| 118 | +# Build constructor transaction |
| 119 | +constructor_txn = Contract.constructor().build_transaction({ |
| 120 | + "chainId": CHAIN_ID, |
| 121 | + "gas": 500000, |
| 122 | + "gasPrice": w3.eth.gas_price, |
| 123 | + "nonce": nonce, |
| 124 | +}) |
| 125 | + |
| 126 | +print("Signing transaction...") |
| 127 | +signed_txn = w3.eth.account.sign_transaction(constructor_txn, private_key) |
| 128 | + |
| 129 | +print("Sending transaction...") |
| 130 | +tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) |
| 131 | +print(f"Transaction hash: {tx_hash.hex()}") |
| 132 | + |
| 133 | +print("\nWaiting for confirmation...") |
| 134 | +tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) |
| 135 | +contract_address = tx_receipt.contractAddress |
| 136 | +print(f"Contract deployed at: {contract_address}") |
| 137 | +print(f"Transaction status: {tx_receipt.status}") |
| 138 | +print(f"Gas used: {tx_receipt.gasUsed}") |
| 139 | + |
| 140 | +# Verify contract code exists |
| 141 | +code = w3.eth.get_code(contract_address) |
| 142 | +print(f"\nVerifying deployment:") |
| 143 | +print(f"Contract code exists: {len(code) > 0}") |
| 144 | +print(f"Code size: {len(code)} bytes") |
| 145 | + |
| 146 | +if len(code) > 0: |
| 147 | + print("\nContract deployed successfully!") |
| 148 | + |
| 149 | + # Save deployment info |
| 150 | + deployment_info = { |
| 151 | + "contract": "DreamProgram", |
| 152 | + "address": contract_address, |
| 153 | + "network": "SKALE Calypso Mainnet", |
| 154 | + "rpc": RPC_URL, |
| 155 | + "chainId": CHAIN_ID, |
| 156 | + "owner": account.address, |
| 157 | + "transactionHash": tx_hash.hex(), |
| 158 | + "abi": abi, |
| 159 | + "features": { |
| 160 | + "dreamRecording": True, |
| 161 | + "operatorControl": True, |
| 162 | + "dreamStats": True |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + with open("dream_program_deployment.json", "w") as f: |
| 167 | + json.dump(deployment_info, f, indent=2) |
| 168 | + print("Deployment information saved to dream_program_deployment.json") |
| 169 | + |
| 170 | + # Create contract instance |
| 171 | + contract = w3.eth.contract(address=contract_address, abi=abi) |
| 172 | + |
| 173 | + # Verify ownership and initial state |
| 174 | + owner = contract.functions.owner().call() |
| 175 | + is_operator = contract.functions.operators(account.address).call() |
| 176 | + total_dreams = contract.functions.totalDreams().call() |
| 177 | + |
| 178 | + print("\nContract verification:") |
| 179 | + print(f"Owner address: {owner}") |
| 180 | + print(f"Deployer is operator: {is_operator}") |
| 181 | + print(f"Total dreams: {total_dreams}") |
| 182 | + |
| 183 | + print("\nContract Usage Instructions:") |
| 184 | + print("1. Owner Functions:") |
| 185 | + print(" - addOperator(address) - Add new operators") |
| 186 | + print(" - removeOperator(address) - Remove operators") |
| 187 | + print(" - transferOwnership(address) - Transfer ownership") |
| 188 | + print("2. Public Functions:") |
| 189 | + print(" - recordDream(string) - Record a new dream") |
| 190 | + print(" - getDreamerStats(address) - Get dreamers total dreams") |
| 191 | + print("3. View Functions:") |
| 192 | + print(" - owner() - Get current owner") |
| 193 | + print(" - operators(address) - Check if address is operator") |
| 194 | + print(" - dreamCount(address) - Get dream count for address") |
| 195 | + print(" - totalDreams() - Get total number of dreams recorded") |
| 196 | +else: |
| 197 | + print("\nContract deployment failed!") |
0 commit comments