Skill: xasus1/trustra-escrow (version 1.0.0)

--- name: trustra-escrow version: 1.0.0 description: Escrow as a Service for AI agents. Create trustless USDC escrow transactions on Solana. homepage: https://trustra.xyz metadata: {"emoji":"🔐","category":"payments","api_base":"https://api.trustra.xyz/api/v2"} --- # Trustra Escrow 🔐 Trustless USDC escrow for agent-to-agent transactions on Solana. ## I Want To BUY Something (Pay Someone) ```bash # 1. Register (once) python register.py --name "My Agent" # 2. Check your balance python balance.py # 3. Create escrow with seller's wallet python escrow_create.py <SELLER_WALLET> <AMOUNT> -d "Payment for service" # 4. Pay into escrow (funds held until delivery) python escrow_pay.py <ESCROW_ID> # 5. Wait for seller to deliver, then confirm to release funds python escrow_confirm.py <ESCROW_ID> ``` **If there's a problem:** `python escrow_dispute.py <ESCROW_ID> --reason "Issue description"` ## I Want To SELL Something (Receive Payment) ```bash # 1. Register (once) python register.py --name "My Agent" # 2. Share your wallet address with buyer python balance.py # Shows your wallet address # 3. Wait for buyer to create & pay escrow python escrow_list.py --status paid # 4. After delivering service/product, mark as delivered (12h after payment) python escrow_deliver.py <ESCROW_ID> # 5. Wait for buyer to confirm (or 7 days auto-release) python escrow_withdraw.py <ESCROW_ID> # After 7 days if no response ``` ## Quick Reference | Action | Command | |--------|---------| | Register | `python register.py --name "Agent Name"` | | Balance | `python balance.py` | | Create escrow | `python escrow_create.py <WALLET> <AMOUNT> [-d "desc"]` | | Pay escrow | `python escrow_pay.py <ID>` | | List escrows | `python escrow_list.py [--status STATUS]` | | Mark delivered | `python escrow_deliver.py <ID>` (seller) | | Confirm release | `python escrow_confirm.py <ID>` (buyer) | | Dispute | `python escrow_dispute.py <ID> --reason "..."` | | Cancel | `python escrow_cancel.py <ID>` (buyer, before delivery) | | Withdraw | `python escrow_withdraw.py <ID>` (seller, after 7d) | | Export key | `python export_key.py` | ## Escrow Flow ``` BUYER creates escrow → BUYER pays → (12h wait) → SELLER delivers → BUYER confirms ↘ Funds released to SELLER If problem: Either party can DISPUTE → Trustra resolves If no response: SELLER can WITHDRAW after 7 days ``` ## Escrow Statuses | Status | Who acts next? | |--------|----------------| | `created` | Buyer pays | | `paid` | Seller delivers (after 12h wait) | | `delivered` | Buyer confirms (or wait 7d) | | `completed` | Done - funds released | | `disputed` | Trustra team resolves | | `canceled` | Escrow canceled | | `withdrawn` | Seller got funds after 7d | ## Time Constraints | Constraint | Duration | Purpose | |------------|----------|---------| | Cancel window | 12 hours | Buyer can cancel within 12h after paying | | Seller deliver | After 12h | Seller can only mark delivered after cancel window | | Auto-release | 7 days | Seller can withdraw if buyer doesn't respond | ## Setup (one-time) ```bash python register.py --name "My Agent" ``` Creates a managed wallet + API key stored in `credentials.json`. Fund wallet with SOL (for tx fees) and USDC to use escrows. ## Errors | Error | Fix | |-------|-----| | `No API key found` | Run `register.py` | | `Escrow not found` | Wrong ID or you're not buyer/seller | | `Invalid status` | Check `escrow_list.py` for current status | | `CancelDurationNotEnded` | Wait 12 hours after payment to mark delivered | | `Too early to withdraw` | Wait 7 days after delivery | ## Credentials ```json { "api_key": "trustra_sk_...", "wallet_address": "7xKXtg..." } ``` Never share your API key.

path: .gitignore
content: # Credentials
credentials.json

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
.eggs/
dist/
build/
*.egg

# Virtual environments
venv/
env/
.env

# IDE
.idea/
.vscode/
*.swp
*.swo


path: scripts/balance.py
content: #!/usr/bin/env python3
"""
Check wallet balance.

Usage:
  python balance.py
"""

import requests
import sys
from config import BASE_URL, get_api_key, get_headers, get_wallet_address, print_json


def get_balance(api_key: str) -> dict:
    """Get wallet balance."""
    url = f"{BASE_URL}/wallet/balance"
    headers = get_headers(api_key)
    
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to get balance: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    [REDACTED_SECRET])
    wallet = get_wallet_address()
    
    print(f"Wallet: {wallet}")
    print("")
    
    result = get_balance(api_key)
    balances = result.get("balances", {})
    
    print("Balances:")
    for token, info in balances.items():
        amount = info.get("amount", 0)
        symbol = info.get("symbol", token)
        print(f"  {symbol}: {amount:.6f}")
    
    print("")
    print("Fund this wallet with USDC to create escrows.")


if __name__ == "__main__":
    main()


path: scripts/config.py
content: """
Trustra Escrow API Configuration & Credentials
"""

import sys
import json
import os
import shutil

# Prevent future __pycache__ and clean up existing
sys.dont_write_bytecode = True
_pycache = os.path.join(os.path.dirname(__file__), "__pycache__")
if os.path.exists(_pycache):
    shutil.rmtree(_pycache, ignore_errors=True)

# Paths
SKILL_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CREDS_FILE = os.path.join(SKILL_DIR, "credentials.json")

# API URL
BASE_URL = "https://api.trustra.xyz/api/v2"

# Solana RPC
RPC_URL = "https://api.mainnet-beta.solana.com"  # Production

# Request headers
HEADERS = {
    "Content-Type": "application/json",
}


def load_credentials() -> dict:
    """Load credentials from credentials.json file."""
    if not os.path.exists(CREDS_FILE):
        return {}
    
    try:
        with open(CREDS_FILE, "r") as f:
            return json.load(f)
    except (json.JSONDecodeError, IOError):
        return {}


def save_credentials(creds: dict) -> bool:
    """Save credentials to credentials.json file."""
    try:
        with open(CREDS_FILE, "w") as f:
            json.dump(creds, f, indent=2)
        return True
    except IOError as e:
        print(f"Failed to save credentials: {e}", file=sys.stderr)
        return False


def get_api_key(required: bool = True) -> str | None:
    """
    Get API key from credentials.json or environment.
    
    Priority:
    1. TRUSTRA_API_KEY environment variable
    2. credentials.json file
    
    If required=True and no key found, prints error and exits.
    """
    # Check environment first
    [REDACTED_SECRET]"TRUSTRA_API_KEY")
    if [REDACTED_SECRET] api_key
    
    # Check credentials file
    creds = load_credentials()
    [REDACTED_SECRET]"api_key")
    
    if [REDACTED_SECRET] api_key
    
    if required:
        print("No API key found.", file=sys.stderr)
        print("", file=sys.stderr)
        print("Run this to register:", file=sys.stderr)
        print("  python register.py --name 'My Agent' --email [REDACTED_SECRET]", file=sys.stderr)
        sys.exit(1)
    
    return None


def get_headers(api_key: str | None = None) -> dict:
    """Get request headers with optional API key."""
    headers = HEADERS.copy()
    if [REDACTED_SECRET]"x-api-key"] = api_key
    return headers


def get_wallet_address(required: bool = True) -> str | None:
    """
    Get wallet address from credentials.json.
    """
    creds = load_credentials()
    wallet = creds.get("wallet_address")
    
    if wallet:
        return wallet
    
    if required:
        print("No wallet address found.", file=sys.stderr)
        print("Run register.py first to create your wallet.", file=sys.stderr)
        sys.exit(1)
    
    return None


def get_agent_info() -> dict | None:
    """
    Get saved agent info from credentials.json.
    """
    creds = load_credentials()
    return creds.get("agent")


def print_json(data: dict, indent: int = 2):
    """Pretty print JSON data."""
    print(json.dumps(data, indent=indent, default=str))


path: scripts/escrow_cancel.py
content: #!/usr/bin/env python3
"""
Cancel an escrow (buyer only, before payment or within 12h window).

Usage:
  python escrow_cancel.py <ESCROW_ID> [--reason "..."]
  
Examples:
  python escrow_cancel.py 123
  python escrow_cancel.py 123 --reason "Changed my mind"
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def cancel_escrow(api_key: str, escrow_id: str, reason: str = None) -> dict:
    """Cancel an escrow."""
    url = f"{BASE_URL}/escrow/{escrow_id}/cancel"
    headers = get_headers(api_key)
    
    payload = {}
    if reason:
        payload["reason"] = reason
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to cancel: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Cancel an escrow")
    parser.add_argument("escrow_id", help="Escrow ID")
    parser.add_argument("--reason", "-r", help="Reason for cancellation")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Canceling escrow {args.escrow_id}...")
    
    result = cancel_escrow(api_key, args.escrow_id, args.reason)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Escrow canceled!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Reason: {escrow.get('cancelReason')}")
        print(f"  Canceled at: {escrow.get('canceledAt')}")
    else:
        print("Failed to cancel", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_confirm.py
content: #!/usr/bin/env python3
"""
Confirm receipt and release funds to seller (buyer only).

Usage:
  python escrow_confirm.py <ESCROW_ID>
  
Examples:
  python escrow_confirm.py 123
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def confirm_escrow(api_key: str, escrow_id: str) -> dict:
    """Confirm escrow and release funds on-chain."""
    url = f"{BASE_URL}/escrow/{escrow_id}/confirm"
    headers = get_headers(api_key)
    
    payload = {"execute": True}
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to confirm: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Confirm escrow and release funds")
    parser.add_argument("escrow_id", help="Escrow ID")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Confirming escrow {args.escrow_id}...")
    
    result = confirm_escrow(api_key, args.escrow_id)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Escrow confirmed!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Completed at: {escrow.get('completedAt')}")
        if escrow.get("completionHash"):
            print(f"  TX: {escrow.get('completionHash')}")
        print("")
        print("Funds released to seller on-chain.")
    else:
        print("Failed to confirm", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_create.py
content: #!/usr/bin/env python3
"""
Create a new escrow.

Usage:
  python escrow_create.py <COUNTERPARTY_WALLET> <AMOUNT_USDC> [--description "..."]
  
Examples:
  python escrow_create.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU 50.00
  python escrow_create.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU 100.00 --description "Payment for design work"
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, get_wallet_address, print_json


def create_escrow(api_key: str, counterparty: str, amount: float, description: str = None) -> dict:
    """Create a new escrow."""
    url = f"{BASE_URL}/escrow/create"
    headers = get_headers(api_key)
    
    payload = {
        "counterparty": counterparty,
        "amount": amount
    }
    if description:
        payload["description"] = description
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 201:
        return response.json()
    else:
        print(f"Failed to create escrow: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Create a new escrow")
    parser.add_argument("counterparty", help="Counterparty wallet address")
    parser.add_argument("amount", type=float, help="Amount in USDC")
    parser.add_argument("--description", "-d", help="Description of the escrow")
    
    args = parser.parse_args()
    
    if args.amount <= 0:
        print("Amount must be greater than 0", file=sys.stderr)
        sys.exit(1)
    
    [REDACTED_SECRET])
    wallet = get_wallet_address()
    
    print(f"Creating escrow...")
    print(f"  From: {wallet} (you)")
    print(f"  To: {args.counterparty}")
    print(f"  Amount: {args.amount} USDC")
    if args.description:
        print(f"  Description: {args.description}")
    print("")
    
    result = create_escrow(api_key, args.counterparty, args.amount, args.description)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("Escrow created!")
        print("")
        print(f"  ID: {escrow.get('id')}")
        print(f"  Contract ID: {escrow.get('contractOrderId')}")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Transaction: {escrow.get('transactionHash')}")
        print("")
        print("Next step: Fund the escrow by calling escrow_pay.py")
    else:
        print("Failed to create escrow", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_deliver.py
content: #!/usr/bin/env python3
"""
Mark an escrow as delivered (seller only).
Note: Must wait 12 hours after payment before marking delivered.

Usage:
  python escrow_deliver.py <ESCROW_ID>
  
Examples:
  python escrow_deliver.py 123
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def mark_delivered(api_key: str, escrow_id: str) -> dict:
    """Mark escrow as delivered on-chain."""
    url = f"{BASE_URL}/escrow/{escrow_id}/deliver"
    headers = get_headers(api_key)
    
    payload = {"execute": True}
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to mark as delivered: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Mark escrow as delivered")
    parser.add_argument("escrow_id", help="Escrow ID")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Marking escrow {args.escrow_id} as delivered...")
    
    result = mark_delivered(api_key, args.escrow_id)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Marked as delivered!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Delivered at: {escrow.get('deliveredAt')}")
        if escrow.get("deliveryHash"):
            print(f"  TX: {escrow.get('deliveryHash')}")
        print("")
        print(escrow.get("message", "Buyer has 7 days to confirm or dispute."))
    else:
        print("Failed to mark as delivered", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_dispute.py
content: #!/usr/bin/env python3
"""
Open a dispute on an escrow.

Usage:
  python escrow_dispute.py <ESCROW_ID> [--reason "..."]
  
Examples:
  python escrow_dispute.py 123
  python escrow_dispute.py 123 --reason "Item not as described"
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def open_dispute(api_key: str, escrow_id: str, reason: str = None) -> dict:
    """Open a dispute."""
    url = f"{BASE_URL}/escrow/{escrow_id}/dispute"
    headers = get_headers(api_key)
    
    payload = {}
    if reason:
        payload["reason"] = reason
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to open dispute: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Open a dispute on an escrow")
    parser.add_argument("escrow_id", help="Escrow ID")
    parser.add_argument("--reason", "-r", help="Reason for dispute")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Opening dispute for escrow {args.escrow_id}...")
    
    result = open_dispute(api_key, args.escrow_id, args.reason)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Dispute opened!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Reason: {escrow.get('disputeReason')}")
        print(f"  Disputed at: {escrow.get('disputedAt')}")
        print("")
        print("Trustra team will review and resolve the dispute.")
    else:
        print("Failed to open dispute", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_list.py
content: #!/usr/bin/env python3
"""
List all escrows.

Usage:
  python escrow_list.py [--status STATUS] [--limit N]
  
Examples:
  python escrow_list.py
  python escrow_list.py --status paid
  python escrow_list.py --limit 10
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def list_escrows(api_key: str, status: str = None, limit: int = 50, offset: int = 0) -> dict:
    """List all escrows."""
    url = f"{BASE_URL}/escrow"
    headers = get_headers(api_key)
    
    params = {"limit": limit, "offset": offset}
    if status:
        params["status"] = status
    
    response = requests.get(url, headers=headers, params=params)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to list escrows: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="List all escrows")
    parser.add_argument("--status", "-s", help="Filter by status (created, paid, delivered, completed, disputed, canceled)")
    parser.add_argument("--limit", "-l", type=int, default=50, help="Max results (default: 50)")
    parser.add_argument("--json", "-j", action="store_true", help="Output raw JSON")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    result = list_escrows(api_key, args.status, args.limit)
    
    if args.json:
        print_json(result)
        return
    
    escrows = result.get("escrows", [])
    total = result.get("total", 0)
    
    if not escrows:
        print("No escrows found.")
        return
    
    print(f"Found {total} escrow(s):")
    print("")
    
    for escrow in escrows:
        role = escrow.get("role", "unknown")
        status = escrow.get("status", "unknown")
        amount = escrow.get("amount", 0)
        
        # Color status
        status_display = status.upper()
        
        print(f"  [{escrow.get('id')}] {amount} USDC - {status_display} ({role})")
        print(f"      Buyer: {escrow.get('buyer')}")
        print(f"      Seller: {escrow.get('seller')}")
        print(f"      Created: {escrow.get('createdAt')}")
        print("")


if __name__ == "__main__":
    main()


path: scripts/escrow_pay.py
content: #!/usr/bin/env python3
"""
Pay into an escrow (buyer only).

Usage:
  python escrow_pay.py <ESCROW_ID>
  
Examples:
  python escrow_pay.py 123
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def pay_escrow(api_key: str, escrow_id: str) -> dict:
    """Execute payment for escrow."""
    url = f"{BASE_URL}/escrow/{escrow_id}/pay"
    headers = get_headers(api_key)
    
    payload = {"execute": True}
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to pay: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Pay into escrow")
    parser.add_argument("escrow_id", help="Escrow ID")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Executing payment for escrow {args.escrow_id}...")
    
    result = pay_escrow(api_key, args.escrow_id)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Payment successful!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Paid: {escrow.get('paidAmount', 0):.6f} USDC")
        if escrow.get("paymentHash"):
            print(f"  TX: {escrow.get('paymentHash')}")
        print("")
        print("Next step: Seller marks as delivered with escrow_deliver.py")
    else:
        print("Failed to pay", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/escrow_withdraw.py
content: #!/usr/bin/env python3
"""
Withdraw funds after 7-day auto-release (seller only).

Usage:
  python escrow_withdraw.py <ESCROW_ID>
  
Examples:
  python escrow_withdraw.py 123
"""

import argparse
import requests
import sys
from config import BASE_URL, get_api_key, get_headers, print_json


def withdraw_funds(api_key: str, escrow_id: str) -> dict:
    """Withdraw funds from escrow on-chain."""
    url = f"{BASE_URL}/escrow/{escrow_id}/withdraw"
    headers = get_headers(api_key)
    
    payload = {"execute": True}
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to withdraw: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Withdraw funds from escrow")
    parser.add_argument("escrow_id", help="Escrow ID")
    
    args = parser.parse_args()
    
    [REDACTED_SECRET])
    
    print(f"Withdrawing funds from escrow {args.escrow_id}...")
    
    result = withdraw_funds(api_key, args.escrow_id)
    
    if result.get("success"):
        escrow = result.get("escrow", {})
        print("")
        print("Funds withdrawn!")
        print(f"  Status: {escrow.get('status')}")
        print(f"  Withdrawn at: {escrow.get('withdrawnAt')}")
        if escrow.get("withdrawHash"):
            print(f"  TX: {escrow.get('withdrawHash')}")
    else:
        print("Failed to withdraw", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/export_key.py
content: #!/usr/bin/env python3
"""
Export private key from your managed wallet.
Use this if you want to use your wallet outside of Trustra.

Usage:
  python export_key.py
"""

import requests
import sys
from config import BASE_URL, get_api_key, get_headers, get_wallet_address, print_json


def export_key(api_key: str) -> dict:
    """Export wallet private key."""
    url = f"{BASE_URL}/wallet/export"
    headers = get_headers(api_key)
    
    response = requests.post(url, json={}, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Failed to export key: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    [REDACTED_SECRET])
    wallet = get_wallet_address()
    
    print(f"Exporting private key for wallet: {wallet}")
    print("")
    
    result = export_key(api_key)
    
    if result.get("success"):
        print(f"Wallet: {result.get('walletAddress')}")
        print(f"Private Key: {result.get('privateKey')}")
        print("")
        print("WARNING: Keep this key secret. Anyone with it can control your wallet.")
    else:
        print("Failed to export key", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/register.py
content: #!/usr/bin/env python3
"""
Register a new agent and get API key + wallet.

Usage:
  python register.py --name "My Agent"
  python register.py --name "My Agent" --email [REDACTED_SECRET]
"""

import argparse
import requests
import sys
from config import BASE_URL, HEADERS, save_credentials, load_credentials, print_json


def register_agent(name: str, email: str = None) -> dict:
    """Register a new agent with managed wallet."""
    url = f"{BASE_URL}/agent/register"
    
    payload = {"name": name}
    if email:
        payload["email"] = email
    
    response = requests.post(url, json=payload, headers=HEADERS)
    
    if response.status_code == 201:
        return response.json()
    else:
        print(f"Registration failed: {response.status_code}", file=sys.stderr)
        try:
            error = response.json()
            print(f"Error: {error.get('message', error)}", file=sys.stderr)
        except:
            print(response.text, file=sys.stderr)
        sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="Register a new Trustra agent")
    parser.add_argument("--name", required=True, help="Agent name")
    parser.add_argument("--email", help="Agent email (optional)")
    
    args = parser.parse_args()
    
    # Check if already registered
    creds = load_credentials()
    if creds.get("api_key"):
        print("Already registered!", file=sys.stderr)
        print(f"Wallet: {creds.get('wallet_address')}", file=sys.stderr)
        print("", file=sys.stderr)
        print("To register a new agent, delete credentials.json first.", file=sys.stderr)
        sys.exit(1)
    
    # Register
    email_info = f" ({args.email})" if args.email else ""
    print(f"Registering agent: {args.name}{email_info}")
    result = register_agent(args.name, args.email)
    
    # Save credentials
    agent = result.get("agent", {})
    creds = {
        "api_key": result.get("apiKey"),
        "wallet_address": agent.get("walletAddress"),
        "agent": {
            "id": agent.get("id"),
            "name": agent.get("name"),
            "email": agent.get("email")
        }
    }
    
    if save_credentials(creds):
        print("")
        print("Registration successful!")
        print("")
        print(f"Agent ID: {agent.get('id')}")
        print(f"Wallet: {agent.get('walletAddress')}")
        print("")
        print("API Key saved to credentials.json")
        print("")
        print("IMPORTANT: Back up your API key. It will not be shown again.")
        print(f"API Key: {result.get('apiKey')}")
        print("")
        print("Next: Fund your wallet with SOL (for tx fees) and USDC to use escrows.")
    else:
        print("Failed to save credentials!", file=sys.stderr)
        print_json(result)


if __name__ == "__main__":
    main()


path: scripts/requirements.txt
content: requests>=2.28.0


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)