Files
proxmox/scripts/verify/build-non-evm-lane-status.py

338 lines
15 KiB
Python
Executable File

#!/usr/bin/env python3
"""Build a repo-backed status report for Solana, Tron, and XRPL lanes."""
from __future__ import annotations
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[2]
SOLANA_LINEUP = ROOT / "config/solana-gru-bridge-lineup.json"
SNAPSHOT = ROOT / "reports/inventory/contract-inventory-onchain-snapshot.json"
COMPLETION_MATRIX = ROOT / "reports/inventory/deployed-contracts-completion-matrix.json"
HEALTH_JSON = ROOT / "reports/status/non-evm-network-health-latest.json"
OUT_JSON = ROOT / "reports/status/non-evm-lane-status-latest.json"
OUT_MD = ROOT / "reports/status/non-evm-lane-status-latest.md"
def load_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8"))
def find_snapshot_row(rows: list[dict[str, Any]], address: str) -> dict[str, Any]:
needle = address.lower()
for row in rows:
if str(row.get("address", "")).lower() == needle:
return row
raise KeyError(address)
def find_matrix_row(rows: list[dict[str, Any]], address: str) -> dict[str, Any]:
needle = address.lower()
for row in rows:
if str(row.get("address", "")).lower() == needle:
return row
raise KeyError(address)
def md_table(headers: list[str], rows: list[list[str]]) -> str:
out = ["| " + " | ".join(headers) + " |", "| " + " | ".join(["---"] * len(headers)) + " |"]
out.extend("| " + " | ".join(row) + " |" for row in rows)
return "\n".join(out)
def load_health() -> dict[str, Any] | None:
if not HEALTH_JSON.exists():
return None
return load_json(HEALTH_JSON)
def build_report() -> dict[str, Any]:
lineup = load_json(SOLANA_LINEUP)
snapshot = load_json(SNAPSHOT)
matrix = load_json(COMPLETION_MATRIX)
health = load_health()
snapshot_rows = snapshot.get("rows", [])
matrix_rows = matrix.get("rows", [])
solana_evidence = lineup["liveBridgeEvidence"]
solana_asset = next(
asset
for asset in lineup.get("assets", [])
if asset.get("chain138Symbol") == solana_evidence["chain138Symbol"]
)
inventory_targets = {
"tronAdapter": "0x28a94FB4bC415Ac3273211429338f768074CBEF6",
"xrplAdapter": "0x351f207F2DE66bF166ec730a0133613A10691439",
"mintBurnController": "0x44F79a3cec3fb829973d9b8d630839726D19E9C5",
"wXRP": "0xe8572f3ABD73Eff0A2e8AC5C88C2b6D180735f97",
}
inventory = {}
for key, address in inventory_targets.items():
snap_row = find_snapshot_row(snapshot_rows, address)
matrix_row = find_matrix_row(matrix_rows, address)
inventory[key] = {
"address": address,
"label": snap_row.get("labels_merged", ""),
"codeOnChain": snap_row.get("code_on_chain"),
"sourceBlockscout": snap_row.get("source_blockscout"),
"completionStatus": matrix_row.get("completion_status"),
"recommendedAction": matrix_row.get("recommended_action"),
}
generated_at = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
return {
"generatedAt": generated_at,
"sources": {
"solanaLineup": str(SOLANA_LINEUP.relative_to(ROOT)),
"contractSnapshot": str(SNAPSHOT.relative_to(ROOT)),
"completionMatrix": str(COMPLETION_MATRIX.relative_to(ROOT)),
"healthReport": str(HEALTH_JSON.relative_to(ROOT)) if health else None,
},
"health": health,
"lanes": {
"solana": {
"classification": "documented_non_evm_gru_lane",
"networkHealth": next((c for c in (health or {}).get("checks", []) if c.get("network") == "Solana"), None),
"sourceAsset": {
"symbol": solana_evidence["chain138Symbol"],
"address": solana_evidence["chain138Address"],
},
"destinationAsset": {
"symbol": solana_evidence["solanaSymbol"],
"mint": solana_asset.get("solanaMint") or "pending",
},
"adapter": {
"address": solana_evidence["solanaAdapter"],
"contractPath": "smom-dbis-138/contracts/bridge/adapters/non-evm/SolanaAdapter.sol",
},
"evidence": {
"evidenceDate": solana_evidence["evidenceDate"],
"bridgeRequestId": solana_evidence["bridgeRequestId"],
"mintedRaw": solana_evidence["mintedRaw"],
"bridgedRaw": solana_evidence["bridgedRaw"],
"finalStatus": solana_evidence["finalStatus"],
"finalStatusLabel": solana_evidence["finalStatusLabel"],
"transactions": solana_evidence["transactions"],
},
"repoStatus": lineup["status"],
"gaps": [
"Solana SPL mint addresses are still null in config/solana-gru-bridge-lineup.json.",
"The repo records a confirmed cAUSDT -> cWAUSDT send/confirm, but broader mint inventory and production relay surface remain incomplete.",
],
},
"tron": {
"classification": "chain_138_adapter_only",
"networkHealth": next((c for c in (health or {}).get("checks", []) if c.get("network") == "Tron"), None),
"adapter": {
"address": inventory["tronAdapter"]["address"],
"contractPath": "smom-dbis-138/contracts/bridge/adapters/non-evm/TronAdapter.sol",
"completionStatus": inventory["tronAdapter"]["completionStatus"],
"sourceBlockscout": inventory["tronAdapter"]["sourceBlockscout"],
},
"flowSummary": [
"Chain 138 users initiate non-EVM sends through TronAdapter on Chain 138.",
"The adapter is an off-chain relay/oracle path, not a native Tron program inventory committed in this repo.",
"Repo closure work is currently explorer/source publication on Chain 138, not public Tron RPC reachability.",
],
"gaps": [
inventory["tronAdapter"]["recommendedAction"],
"No native Tron-side contract/program inventory is promoted in the unified repo-backed deployment status.",
],
},
"xrpl": {
"classification": "chain_138_adapter_plus_bridge_asset",
"networkHealth": next((c for c in (health or {}).get("checks", []) if c.get("network") == "XRPL"), None),
"adapter": {
"address": inventory["xrplAdapter"]["address"],
"contractPath": "smom-dbis-138/contracts/bridge/adapters/non-evm/XRPLAdapter.sol",
"completionStatus": inventory["xrplAdapter"]["completionStatus"],
"sourceBlockscout": inventory["xrplAdapter"]["sourceBlockscout"],
},
"wrappedAsset": {
"address": inventory["wXRP"]["address"],
"contractPath": "smom-dbis-138/contracts/bridge/interop/wXRP.sol",
"completionStatus": inventory["wXRP"]["completionStatus"],
},
"controller": {
"address": inventory["mintBurnController"]["address"],
"contractPath": "smom-dbis-138/contracts/bridge/interop/MintBurnController.sol",
"completionStatus": inventory["mintBurnController"]["completionStatus"],
},
"uiPath": "smom-dbis-138/frontend-dapp/src/components/bridge/XRPLBridgeForm.tsx",
"flowSummary": [
"XRPL sends are initiated on Chain 138 through XRPLAdapter with XRPL destination address and optional destination tag handling.",
"wXRP is the bridge-side ERC-20 representation of XRP locked on XRPL.",
"MintBurnController applies HSM-signed mint/burn authorization for the wXRP corridor.",
],
"gaps": [
f"XRPLAdapter: {inventory['xrplAdapter']['recommendedAction']}",
f"wXRP: {inventory['wXRP']['recommendedAction']}",
f"MintBurnController: {inventory['mintBurnController']['recommendedAction']}",
],
},
},
"auditConclusion": {
"summary": "Public network health for Solana, Tron, and XRPL is separate from Chain 138 explorer/source verification closure. The live endpoints can be healthy while the repo still reports NEEDS_BLOCKSCOUT_SOURCE_IMPORT for the corresponding Chain 138 adapter or bridge-asset contracts.",
"actionableDistinction": [
"Use reports/status/non-evm-network-health-latest.json for public endpoint reachability.",
"Use reports/inventory/deployed-contracts-completion-matrix.json for Chain 138 source-publication closure.",
"Use config/solana-gru-bridge-lineup.json as the source of truth for the current Solana AUSDT corridor evidence.",
],
},
}
def write_markdown(report: dict[str, Any]) -> None:
health = report.get("health") or {}
health_checks = {row["network"]: row for row in health.get("checks", [])}
lines = [
"# Non-EVM Lane Status",
"",
f"- Generated: `{report['generatedAt']}`",
f"- Solana lineup source: `{report['sources']['solanaLineup']}`",
f"- Contract snapshot source: `{report['sources']['contractSnapshot']}`",
f"- Completion matrix source: `{report['sources']['completionMatrix']}`",
]
if report["sources"]["healthReport"]:
lines.append(f"- Health source: `{report['sources']['healthReport']}`")
lines.append("")
if health_checks:
lines += [
"## Live Endpoint Health",
"",
md_table(
["Network", "Endpoint", "OK", "Key detail"],
[
[
"Solana",
"`https://api.mainnet-beta.solana.com`",
"yes" if health_checks["Solana"]["ok"] else "no",
f"health={health_checks['Solana'].get('health')}; slot={health_checks['Solana'].get('slot')}",
],
[
"Tron",
"`https://api.trongrid.io/jsonrpc`",
"yes" if health_checks["Tron"]["ok"] else "no",
f"chainId={health_checks['Tron'].get('chainId')}; block={health_checks['Tron'].get('blockNumber')}",
],
[
"XRPL",
"`https://s1.ripple.com:51234/`",
"yes" if health_checks["XRPL"]["ok"] else "no",
f"status={health_checks['XRPL'].get('status')}; validatedLedger={health_checks['XRPL'].get('validatedLedger')}",
],
],
),
"",
]
solana = report["lanes"]["solana"]
tron = report["lanes"]["tron"]
xrpl = report["lanes"]["xrpl"]
lines += [
"## Solana Lane",
"",
md_table(
["Field", "Value"],
[
["Classification", solana["classification"]],
["Source asset", f"`{solana['sourceAsset']['symbol']}` at `{solana['sourceAsset']['address']}`"],
["Destination asset", f"`{solana['destinationAsset']['symbol']}`; SPL mint `{solana['destinationAsset']['mint']}`"],
["Solana adapter", f"`{solana['adapter']['address']}`"],
["Evidence date", f"`{solana['evidence']['evidenceDate']}`"],
["Bridge request", f"`{solana['evidence']['bridgeRequestId']}`"],
["Final status", f"`{solana['evidence']['finalStatus']}` / `{solana['evidence']['finalStatusLabel']}`"],
["Mint / bridge / confirm txs", f"`{solana['evidence']['transactions']['mint']}`, `{solana['evidence']['transactions']['bridge']}`, `{solana['evidence']['transactions']['confirm']}`"],
["Repo status", f"`{solana['repoStatus']}`"],
],
),
"",
"Gaps:",
"",
*[f"- {item}" for item in solana["gaps"]],
"",
"## Tron Lane",
"",
md_table(
["Field", "Value"],
[
["Classification", tron["classification"]],
["Adapter", f"`{tron['adapter']['address']}`"],
["Contract path", f"`{tron['adapter']['contractPath']}`"],
["Completion status", f"`{tron['adapter']['completionStatus']}`"],
["Blockscout source", f"`{tron['adapter']['sourceBlockscout']}`"],
],
),
"",
"Flow summary:",
"",
*[f"- {item}" for item in tron["flowSummary"]],
"",
"Gaps:",
"",
*[f"- {item}" for item in tron["gaps"]],
"",
"## XRPL Lane",
"",
md_table(
["Field", "Value"],
[
["Classification", xrpl["classification"]],
["XRPL adapter", f"`{xrpl['adapter']['address']}`"],
["wXRP", f"`{xrpl['wrappedAsset']['address']}`"],
["MintBurnController", f"`{xrpl['controller']['address']}`"],
["XRPL UI", f"`{xrpl['uiPath']}`"],
["Adapter completion", f"`{xrpl['adapter']['completionStatus']}`"],
["wXRP completion", f"`{xrpl['wrappedAsset']['completionStatus']}`"],
["Controller completion", f"`{xrpl['controller']['completionStatus']}`"],
],
),
"",
"Flow summary:",
"",
*[f"- {item}" for item in xrpl["flowSummary"]],
"",
"Gaps:",
"",
*[f"- {item}" for item in xrpl["gaps"]],
"",
"## Audit Conclusion",
"",
f"- {report['auditConclusion']['summary']}",
*[f"- {item}" for item in report["auditConclusion"]["actionableDistinction"]],
"",
]
OUT_MD.write_text("\n".join(lines), encoding="utf-8")
def main() -> int:
if not SNAPSHOT.is_file() or not COMPLETION_MATRIX.is_file():
missing = [p.name for p in (SNAPSHOT, COMPLETION_MATRIX) if not p.is_file()]
print(
"SKIP non-evm lane status: missing "
+ ", ".join(missing)
+ ". Regenerate: python3 scripts/verify/build-deduped-onchain-inventory.py"
" && python3 scripts/verify/build-inventory-completion-matrix.py"
" (needs reports/inventory/DEPLOYED_CONTRACTS_UNIFIED_EXTENDED.md).",
file=sys.stderr,
)
return 0
report = build_report()
OUT_JSON.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
write_markdown(report)
return 0
if __name__ == "__main__":
raise SystemExit(main())