Monorepo for Aesthetic.Computer
aesthetic.computer
1"""
2Deploy FA2 contract to Ghostnet using PyTezos (pure Python, no octez-client needed)
3"""
4
5import sys
6from pathlib import Path
7from pytezos import pytezos, Key
8
9# Load kidlisp wallet credentials
10vault_dir = Path(__file__).parent.parent / "aesthetic-computer-vault" / "tezos" / "kidlisp"
11env_file = vault_dir / ".env"
12
13KIDLISP_ADDRESS = None
14KIDLISP_KEY = None
15
16if env_file.exists():
17 with open(env_file) as f:
18 for line in f:
19 if line.startswith('KIDLISP_ADDRESS='):
20 KIDLISP_ADDRESS = line.split('=')[1].strip().strip('"')
21 elif line.startswith('KIDLISP_KEY='):
22 KIDLISP_KEY = line.split('=')[1].strip().strip('"')
23
24if not KIDLISP_ADDRESS or not KIDLISP_KEY:
25 print("❌ Error: KIDLISP credentials not found in vault/tezos/kidlisp/.env")
26 sys.exit(1)
27
28# Ghostnet configuration
29GHOSTNET_RPC = "https://ghostnet.ecadinfra.com"
30
31
32def deploy_contract():
33 print("=" * 70)
34 print("🚀 Deploying FA2 Contract to Ghostnet (PyTezos)")
35 print("=" * 70)
36 print()
37
38 # Connect to Ghostnet with kidlisp key
39 print("🔧 Connecting to Ghostnet...")
40 ptz = pytezos.using(shell=GHOSTNET_RPC, key=Key.from_encoded_key(KIDLISP_KEY))
41
42 print(f" ✓ RPC: {GHOSTNET_RPC}")
43 print(f" ✓ Address: {ptz.key.public_key_hash()}")
44
45 # Check balance
46 print("\n💰 Checking balance...")
47 balance = ptz.balance()
48 balance_xtz = balance / 1_000_000
49 print(f" ✓ Balance: {balance_xtz:.6f} XTZ")
50
51 if balance_xtz < 1:
52 print(" ⚠️ Low balance! Get testnet tez from: https://faucet.ghostnet.teztnets.com/")
53
54 # Load contract
55 print("\n📄 Loading contract...")
56 contract_file = Path(__file__).parent / "michelson-lib" / "keeps-fa2-complete.tz"
57
58 if not contract_file.exists():
59 print(f"❌ Contract file not found: {contract_file}")
60 sys.exit(1)
61
62 contract_code = contract_file.read_text()
63 print(f" ✓ Loaded: {contract_file.name}")
64
65 # Initial storage (Michelson format)
66 # Structure: (pair (pair address ledger) (pair next_token_id (pair operators token_metadata)))
67 admin_address = ptz.key.public_key_hash()
68 initial_storage = f'(Pair (Pair "{admin_address}" {{}}) (Pair 0 (Pair {{}} {{}})))'
69
70 print(f"\n💾 Initial storage:")
71 print(f" ✓ Administrator: {admin_address}")
72 print(f" ✓ Next token ID: 0")
73
74 # Deploy
75 print("\n📤 Deploying contract...")
76 print(" (This may take 1-2 minutes...)")
77
78 try:
79 # Originate
80 op = ptz.origination(script={
81 'code': contract_code,
82 'storage': initial_storage
83 }).autofill().sign()
84
85 print(f" ⏳ Operation: {op.hash}")
86 print(" ⏳ Waiting for confirmation...")
87
88 # Inject and wait
89 result = op.inject(_async=False)
90
91 # Get contract address from result
92 contract_address = None
93 if hasattr(result, 'contents'):
94 for content in result.contents:
95 if hasattr(content, 'metadata') and content.metadata:
96 results = content.metadata.get('operation_result', {}).get('originated_contracts', [])
97 if results:
98 contract_address = results[0]
99 break
100
101 if not contract_address:
102 # Try to find from operation receipt
103 print("\n⚠️ Looking for contract address in operation receipt...")
104 op_result = ptz.shell.blocks['head'].operations[3][op.hash].get()
105 for content in op_result:
106 if 'metadata' in content:
107 results = content['metadata'].get('operation_result', {}).get('originated_contracts', [])
108 if results:
109 contract_address = results[0]
110 break
111
112 if contract_address:
113 print("\n" + "=" * 70)
114 print("✅ Contract Deployed Successfully!")
115 print("=" * 70)
116 print()
117 print(f"📍 Contract Address: {contract_address}")
118 print(f"🔍 View on TzKT: https://ghostnet.tzkt.io/{contract_address}")
119 print()
120
121 # Save contract address
122 address_file = Path(__file__).parent / "contract-address.txt"
123 address_file.write_text(contract_address)
124 print(f"💾 Saved to: {address_file}")
125
126 return contract_address
127 else:
128 print("\n⚠️ Deployment succeeded but couldn't extract contract address")
129 print(f" Check operation: https://ghostnet.tzkt.io/{op.hash}")
130
131 except Exception as e:
132 print(f"\n❌ Deployment failed: {e}")
133 import traceback
134 traceback.print_exc()
135 sys.exit(1)
136
137
138if __name__ == "__main__":
139 deploy_contract()