#!/usr/bin/env python3
"""
Julie Autonomous Security Agent — Python x402 Client
Automates the EIP-712 payment challenge on Base Mainnet ($0.01 Base Native USDC)
and retrieves smart contract bytecode vulnerability audits.

Settlement Target: 0x75F05Da87cDFf3f6bAcAc3C07CD49F1D7dC7b20C
Asset: Base Native USDC (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)
Price: $0.01 USDC (10,000 base units)
"""

import os
import json
import base64
import requests
from web3 import Web3
from eth_account import Account
from eth_account.messages import encode_typed_data

# Configuration
API_URL = "https://julie.freysa.dev/api/audit"
BASE_RPC = os.getenv("BASE_RPC_URL", "https://mainnet.base.org")
PRIVATE_KEY = os.getenv("CLIENT_PRIVATE_KEY", "")  # Set your bot's funded Base wallet key

def audit_contract(target_contract: str):
    print(f"[*] Requesting audit for contract: {target_contract}")
    
    # 1. Initial Probe Request
    resp = requests.get(f"{API_URL}?contract={target_contract}")
    
    if resp.status_code == 200:
        print("[+] Audit response (Cached / Free preview):")
        print(json.dumps(resp.json(), indent=2))
        return resp.json()
    
    if resp.status_code != 402:
        print(f"[-] Unexpected response status: {resp.status_code}")
        print(resp.text)
        return None
    
    print("[!] Received HTTP 402 Payment Required handshake from Julie.")
    
    # 2. Extract x402 Payment Challenge
    payment_b64 = resp.headers.get("payment-required") or resp.headers.get("x-payment-required")
    if not payment_b64:
        # Fallback to JSON body if header is empty
        challenge_data = resp.json()
    else:
        challenge_data = json.loads(base64.b64decode(payment_b64).decode())
        
    accepts = challenge_data.get("accepts", [{}])[0]
    recipient = accepts.get("payTo")
    amount = int(accepts.get("amount", 10000))  # 10,000 units = 0.01 USDC
    token_addr = accepts.get("asset")
    
    print(f"[+] Payment Requirement:")
    print(f"    - Network: Base Mainnet (ChainID 8453)")
    print(f"    - Recipient: {recipient}")
    print(f"    - Cost: {amount / 1e6} USDC ({amount} base units)")
    print(f"    - Token: {token_addr}")

    if not PRIVATE_KEY:
        print("\n[!] Please set CLIENT_PRIVATE_KEY in your environment with a Base wallet funded with >= 0.01 USDC to complete automated on-chain payment.")
        return challenge_data

    # 3. Sign EIP-712 Payment Permit on Base
    w3 = Web3(Web3.HTTPProvider(BASE_RPC))
    acct = Account.from_key(PRIVATE_KEY)
    
    # Standard EIP-712 Permit domain & types for Base Native USDC
    domain_data = {
        "name": "USD Coin",
        "version": "2",
        "chainId": 8453,
        "verifyingContract": token_addr
    }
    
    message_types = {
        "Permit": [
            {"name": "owner", "type": "address"},
            {"name": "spender", "type": "address"},
            {"name": "value", "type": "uint256"},
            {"name": "nonce", "type": "uint256"},
            {"name": "deadline", "type": "uint256"}
        ]
    }
    
    # Query nonces from USDC contract
    nonce_abi = [{"constant":True,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"type":"function"}]
    usdc = w3.eth.contract(address=Web3.to_checksum_address(token_addr), abi=nonce_abi)
    nonce = usdc.functions.nonces(acct.address).call()
    deadline = w3.eth.get_block('latest')['timestamp'] + 3600  # 1 hour validity
    
    permit_message = {
        "owner": acct.address,
        "spender": recipient,
        "value": amount,
        "nonce": nonce,
        "deadline": deadline
    }
    
    structured_data = {
        "types": {
            "EIP712Domain": [
                {"name": "name", "type": "string"},
                {"name": "version", "type": "string"},
                {"name": "chainId", "type": "uint256"},
                {"name": "verifyingContract", "type": "address"}
            ],
            **message_types
        },
        "primaryType": "Permit",
        "domain": domain_data,
        "message": permit_message
    }
    
    encoded = encode_typed_data(full_message=structured_data)
    signed = acct.sign_message(encoded)
    
    # Format payment payload
    payment_payload = {
        "scheme": "exact",
        "network": "eip155:8453",
        "payer": acct.address,
        "payTo": recipient,
        "amount": amount,
        "signature": signed.signature.hex(),
        "deadline": deadline,
        "nonce": nonce
    }
    
    payment_header = base64.b64encode(json.dumps(payment_payload).encode()).decode()
    
    # 4. Retry with Payment Header Attached
    print("[*] Submitting payment authorization to Julie...")
    headers = {
        "PAYMENT-SIGNATURE": payment_header,
        "X-PAYMENT": payment_header
    }
    
    final_resp = requests.get(f"{API_URL}?contract={target_contract}", headers=headers)
    print(f"[+] Final Status Code: {final_resp.status_code}")
    print("[+] Audit Result:")
    print(json.dumps(final_resp.json(), indent=2))
    return final_resp.json()

if __name__ == "__main__":
    # Test query against Base Native USDC contract or any target token
    TARGET = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    audit_contract(TARGET)
