File size: 7,056 Bytes
88d2f2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""W17-A diagnostic: dump on-chain reputation/registration state for all 6 seeder addresses.

Reads:
  - REPUTATION_REGISTRY_ADDRESS / TRANSLATION_AUCTION_ADDRESS / ARC_TESTNET_USDC_ADDRESS / ARC_TESTNET_RPC from .env
  - ABI from contracts/out/

For each of the 6 addresses (3 old gemini/deepseek/qwen + 3 v2 wallets derived
from HACKATHON_WALLET_PRIVATE_KEY), prints:
  - getReputation(addr)        β€” raw uint256 + scaled float
  - getStats(addr)             β€” totalBids/totalWins/qualityPasses/cumulativeFees/score
  - reps(addr).lastUpdated     β€” to distinguish "never touched" from "score reset"
  - auction.registered(addr)   β€” whether they finished registerAgent
  - auction.stakes(addr) / lockedStakes(addr) β€” staked USDC
  - reputation_registry.authorized(addr) β€” only relevant for owner check
  - USDC.balanceOf(addr) and ETH balance

Plus derives v2 wallets from HACKATHON_WALLET_PRIVATE_KEY and confirms the
addresses match outputs/agent_wallets.json (rules out hypothesis B).
"""
from __future__ import annotations

import json
import os
import sys
from pathlib import Path

# Load .env manually (avoid pulling in app deps)
ROOT = Path(__file__).resolve().parents[1]
ENV_PATH = ROOT / ".env"


def load_env() -> None:
    if not ENV_PATH.exists():
        return
    for raw in ENV_PATH.read_text().splitlines():
        line = raw.strip()
        if not line or line.startswith("#"):
            continue
        if "=" not in line:
            continue
        k, v = line.split("=", 1)
        os.environ.setdefault(k.strip(), v.strip())


load_env()
sys.path.insert(0, str(ROOT))

from web3 import Web3  # noqa: E402
from eth_account import Account  # noqa: E402

from polyglot_alpha.agents.wallets import derive_agent_wallet, AGENT_NAMES  # noqa: E402


def load_abi(path: Path) -> list:
    return json.loads(path.read_text())["abi"]


# ERC-20 minimal ABI for balanceOf
ERC20_ABI = [
    {
        "constant": True,
        "inputs": [{"name": "owner", "type": "address"}],
        "name": "balanceOf",
        "outputs": [{"name": "", "type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "constant": True,
        "inputs": [],
        "name": "decimals",
        "outputs": [{"name": "", "type": "uint8"}],
        "stateMutability": "view",
        "type": "function",
    },
]


def main() -> int:
    rpc = os.environ["ARC_TESTNET_RPC"]
    rep_addr = os.environ["REPUTATION_REGISTRY_ADDRESS"]
    auc_addr = os.environ["TRANSLATION_AUCTION_ADDRESS"]
    usdc_addr = os.environ["ARC_TESTNET_USDC_ADDRESS"]
    op_pk = os.environ["HACKATHON_WALLET_PRIVATE_KEY"]

    print(f"RPC                  = {rpc}")
    print(f"ReputationRegistry   = {rep_addr}")
    print(f"TranslationAuction   = {auc_addr}")
    print(f"USDC                 = {usdc_addr}")

    w3 = Web3(Web3.HTTPProvider(rpc, request_kwargs={"timeout": 30}))
    print(f"chain connected      = {w3.is_connected()}  chainId={w3.eth.chain_id}")

    rep_abi = load_abi(ROOT / "contracts/out/ReputationRegistry.sol/ReputationRegistry.json")
    auc_abi = load_abi(ROOT / "contracts/out/TranslationAuction.sol/TranslationAuction.json")

    rep = w3.eth.contract(address=Web3.to_checksum_address(rep_addr), abi=rep_abi)
    auc = w3.eth.contract(address=Web3.to_checksum_address(auc_addr), abi=auc_abi)
    usdc = w3.eth.contract(address=Web3.to_checksum_address(usdc_addr), abi=ERC20_ABI)

    # Confirm wallet derivation
    print("\n=== Wallet derivation cross-check (rules out hypothesis B) ===")
    derived: dict[str, str] = {}
    for name in AGENT_NAMES:
        w = derive_agent_wallet(op_pk, name)
        derived[name] = w.address
        print(f"  {name:<14} -> {w.address}")
    saved = json.loads((ROOT / "outputs/agent_wallets.json").read_text())
    for name in AGENT_NAMES:
        match = derived[name].lower() == saved[name]["address"].lower()
        print(
            f"  {name:<14} saved={saved[name]['address']} match={match}"
        )

    # 6 addresses to investigate. Old gemini/deepseek/qwen addresses
    # come from the original W14-CONTRACT-PREP keys (sha256(op_pk + ':gemini') etc).
    # If that derivation has been retired we still want to inspect the
    # historic addresses cited in the bug report.
    old_addresses = {
        "gemini-old":   "0x396B...",  # placeholder; only the v2 row is required
    }
    # We don't actually know the literal old hex from the env; derive what the
    # PRE-v2 naming would have produced (sha256(pk + ':gemini')).
    import hashlib
    for legacy_name in ("gemini", "deepseek", "qwen"):
        seed = hashlib.sha256(f"{op_pk}:{legacy_name}".encode()).hexdigest()
        acct = Account.from_key("0x" + seed)
        old_addresses[f"{legacy_name}-old"] = acct.address

    targets: list[tuple[str, str]] = []
    for legacy in ("gemini", "deepseek", "qwen"):
        targets.append((f"{legacy}-old", old_addresses[f"{legacy}-old"]))
    for name in AGENT_NAMES:
        targets.append((name, derived[name]))

    print("\n=== Per-address chain state ===")
    print(
        f"{'name':<15}{'address':<45}{'rep_raw':>22}{'rep_f':>10}"
        f"{'lastUpd':>12}{'tBids':>7}{'tWins':>7}{'qPass':>7}"
        f"{'cumFee':>10}{'reg':>5}{'stake':>10}{'lock':>10}"
        f"{'usdc':>10}{'eth':>10}"
    )
    for label, addr in targets:
        addr_cs = Web3.to_checksum_address(addr)
        rep_raw = rep.functions.getReputation(addr_cs).call()
        stats = rep.functions.getStats(addr_cs).call()
        reps_struct = rep.functions.reps(addr_cs).call()
        # reps struct: totalBids, totalWins, totalQualityPasses, cumulativeFeesEarned, score, lastUpdated
        last_updated = reps_struct[5]
        registered = auc.functions.registered(addr_cs).call()
        stake = auc.functions.stakes(addr_cs).call()
        try:
            locked = auc.functions.lockedStakes(addr_cs).call()
        except Exception:
            locked = 0
        usdc_bal = usdc.functions.balanceOf(addr_cs).call()
        eth_bal = w3.eth.get_balance(addr_cs)
        print(
            f"{label:<15}{addr_cs:<45}{rep_raw:>22}{rep_raw/1e18:>10.4f}"
            f"{last_updated:>12}{stats[0]:>7}{stats[1]:>7}{stats[2]:>7}"
            f"{stats[3]:>10}{int(registered):>5}{stake/1e6:>10.4f}{locked/1e6:>10.4f}"
            f"{usdc_bal/1e6:>10.4f}{eth_bal/1e18:>10.4f}"
        )

    # Owner of ReputationRegistry + authorized set
    try:
        owner = rep.functions.owner().call()
        print(f"\nReputationRegistry.owner = {owner}")
    except Exception as exc:
        print(f"\nReputationRegistry.owner read failed: {exc}")

    # Also dump bytecode size to confirm both contracts are deployed
    rep_code = w3.eth.get_code(Web3.to_checksum_address(rep_addr))
    auc_code = w3.eth.get_code(Web3.to_checksum_address(auc_addr))
    print(
        f"\nReputationRegistry bytecode bytes = {len(rep_code)}"
        f"  TranslationAuction bytecode bytes = {len(auc_code)}"
    )

    return 0


if __name__ == "__main__":
    sys.exit(main())