chore(cwusdc): optional DexScreener probes and Etherscan-value readiness subset
Some checks failed
Deploy to Phoenix / validate (push) Failing after 1s
Deploy to Phoenix / deploy (push) Has been skipped
Deploy to Phoenix / deploy-atomic-swap-dapp (push) Has been skipped
Deploy to Phoenix / cloudflare (push) Has been skipped

- Treat DexScreener token v1 APIs as optional; document in non-manual tasks.
- Align tracker checks, handoff/dossier builders, CMC sanity, monitors, and CI
  shell wrapper with ETHERSCAN_VALUE_PATH_READY_IDS and summary fields.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-05-12 00:00:52 -07:00
parent b36cd43b1d
commit 349ac415b9
8 changed files with 101 additions and 17 deletions

View File

@@ -14,8 +14,8 @@ Latest evidence source: [../../reports/status/cwusdc-provider-handoff-latest.md]
| CMC DEX visibility | Passing | External tracker probe sees the CMC DEX token page. |
| GeckoTerminal V3 pool visibility | Passing | V3 pool API returns `data`. |
| GeckoTerminal V2 pool visibility | Mitigated in automation | Probes use exponential backoff on HTTP **429** / **502** / **503** for GeckoTerminal pool URLs (`scripts/verify/check-cwusdc-external-trackers-live.py`, `--gecko-retries`). Same backoff for GeckoTerminal in `monitor-cwusdc-etherscan-value-propagation.py`. If all attempts fail, treat as advisory and rerun later. |
| CoinGecko price API | External blocker | API responds but does not include the cWUSDC contract key. |
| DexScreener token APIs | External blocker | Token-pairs and tokens endpoints return empty arrays. |
| CoinGecko price API | External blocker | API responds but does not include the cWUSDC contract key (primary listing gate). |
| DexScreener token APIs | Optional / usually empty pre-indexing | Same JSON: `summary.dexScreenerTokenApisIndexed`; not counted in `failedRequiredIds`. |
| EVM liquidity-gap planner rows | No current rows | Latest planner summary shows `rows = 0`. |
| Non-EVM funding requirements | Open, operator-bound | Solana, Tron, XRPL, and other non-EVM requirements need wallet/asset/target binding before claims. |
| Mainnet cWUSDC supply attestation | Refreshed | `reports/status/cwusdc-supply-circulating-attestation-latest.md`; circulating supply `10451316981.309788`. |
@@ -49,7 +49,7 @@ Latest evidence source: [../../reports/status/cwusdc-provider-handoff-latest.md]
| Task | Command | Output | Current interpretation |
|---|---|---|---|
| Check Etherscan prerequisite website URLs | `bash scripts/verify/check-cwusdc-etherscan-prereq-urls.sh --json-out reports/status/cwusdc-etherscan-prereq-urls-latest.json --md-out reports/status/cwusdc-etherscan-prereq-urls-latest.md` | URL evidence JSON/Markdown with HTTP status, attempts, and curl status. | Passing; rerun before Etherscan profile submission or CI. |
| Probe external tracker/indexing surfaces | `bash scripts/verify/check-cwusdc-external-trackers-live.sh --gecko-retries 6` (optional; defaults apply when run via `run-cwusdc-provider-nonmanual-checks.sh`) | `reports/status/cwusdc-external-trackers-live-latest.{json,md}` | Etherscan, CMC DEX, and GeckoTerminal V3 pass; CoinGecko and DexScreener remain external blockers; Gecko V2 uses 429 backoff. |
| Probe external tracker/indexing surfaces | `bash scripts/verify/check-cwusdc-external-trackers-live.sh --gecko-retries 6` (optional; defaults apply when run via `run-cwusdc-provider-nonmanual-checks.sh`) | `reports/status/cwusdc-external-trackers-live-latest.{json,md}` | Required probes: Etherscan token page, CoinGecko price API, CMC DEX page, GeckoTerminal V2/V3 pools. DexScreener token v1 APIs are **optional** (supplementary indexing); see `summary.dexScreenerTokenApisIndexed` in the JSON. |
| Re-run liquidity-gap funding planner | `node scripts/verify/plan-token-aggregation-liquidity-gap-funding.mjs` | `reports/status/token-aggregation-liquidity-gap-funding-plan-latest.{json,md}` | Read-only; latest EVM gap rows are `0`; non-EVM funding requirements remain open. |
| Build cWUSDC Etherscan Value dossier | `pnpm cwusdc:etherscan-dossier` | `reports/status/cwusdc-etherscan-value-dossier-latest.{json,md}` | Read-only dossier generation for the Etherscan USD Value path. |
| Generate Mainnet cWUSDC supply/circulating attestation | `python3 scripts/verify/generate-cwusdc-supply-circulating-attestation.py` | `reports/status/cwusdc-supply-circulating-attestation-latest.json` and related report output. | Safe when supply/exclusion evidence needs refresh. |

View File

@@ -325,6 +325,7 @@ def build(args: argparse.Namespace) -> dict[str, Any]:
unsupported_family_chain_ids = [chain_id for chain_id in family_chain_ids if chain_id not in chainlist.get("statusByChainId", {})]
blockers = list(((propagation.get("summary") or {}).get("blockers") or []))
propagation_advisory = list(((propagation.get("summary") or {}).get("advisoryNotes") or []))
command_failures = [item for item in commands if not item["ok"]]
for item in command_failures:
blockers.append("Command failed: " + " ".join(item["command"]))
@@ -378,6 +379,7 @@ def build(args: argparse.Namespace) -> dict[str, Any]:
"etherscanValueReady": (propagation.get("summary") or {}).get("etherscanValueReady"),
"coinGeckoPriceReady": (propagation.get("summary") or {}).get("coingeckoPriceReady"),
"blockers": blockers,
"advisoryNotes": propagation_advisory,
},
"evidence": {
"artifacts": {key: rel(path) for key, path in ARTIFACTS.items()},
@@ -424,6 +426,10 @@ def write_md(payload: dict[str, Any], path: Path) -> None:
lines.extend(f"- {item}" for item in readiness["blockers"])
else:
lines.append("- None detected by this dossier.")
advisory = readiness.get("advisoryNotes") or []
if advisory:
lines.extend(["", "## Advisory (non-gating)", ""])
lines.extend(f"- {item}" for item in advisory)
lines.extend(
[
@@ -519,6 +525,9 @@ def main() -> int:
print(f"readyForExternalSubmission={payload['readiness']['readyForExternalSubmission']}")
if payload["readiness"]["blockers"]:
print("Blockers: " + "; ".join(payload["readiness"]["blockers"]))
adv = payload["readiness"].get("advisoryNotes") or []
if adv:
print("Advisory (non-gating): " + "; ".join(adv))
if args.strict and payload["readiness"]["blockers"]:
return 1
return 0

View File

@@ -67,7 +67,8 @@ def build_payload(
tracker_summary = first(trackers, ["summary"], {})
failed_required = tracker_summary.get("failedRequiredIds") if isinstance(tracker_summary, dict) else []
liquidity_summary = first(liquidity, ["summary"], {})
blockers = []
blockers: list[dict[str, Any]] = []
advisory_open_items: list[dict[str, Any]] = []
if prereq is None:
blockers.append({
@@ -115,14 +116,14 @@ def build_payload(
})
if first(liquidity, ["summary", "nonEvmFundingRequirementRows"], 0):
blockers.append({
advisory_open_items.append({
"id": "non_evm_funding_requirements",
"type": "operator_bound",
"status": "open",
"nextAction": "Bind non-EVM wallets, asset IDs, and minimum funding targets before making non-EVM liquidity claims.",
})
if first(cmc_sanity, ["summary", "warningCount"], 0):
blockers.append({
advisory_open_items.append({
"id": "cmc_report_sanity_warnings",
"type": "repo_advisory",
"status": "open",
@@ -145,6 +146,7 @@ def build_payload(
"repoControlledPrereqsPassed": repo_ready,
"externalTrackersAllLive": bool(first(trackers, ["summary", "allTrackersLive"], False)),
"readyForEtherscanUsdValue": ready_for_etherscan_value,
"dexScreenerTokenApisIndexed": first(trackers, ["summary", "dexScreenerTokenApisIndexed"], None),
"externalRequiredPassed": first(trackers, ["summary", "requiredPassedCount"], None),
"externalRequiredCount": first(trackers, ["summary", "requiredCount"], None),
"liquidityRows": first(liquidity, ["summary", "rows"], None),
@@ -152,8 +154,10 @@ def build_payload(
"cmcSanityWarningCount": first(cmc_sanity, ["summary", "warningCount"], None),
"cmcPromotedTokenCount": first(cmc_sanity, ["summary", "promotedTokenCount"], None),
"blockerCount": len(blockers),
"advisoryOpenItemCount": len(advisory_open_items),
},
"blockers": blockers,
"advisoryOpenItems": advisory_open_items,
}
@@ -169,8 +173,11 @@ def write_markdown(payload: dict[str, Any], prereq: Any, trackers: Any, liquidit
"",
f"- Generated: `{payload['generatedAt']}`",
f"- Repo-controlled prerequisites passed: `{payload['summary']['repoControlledPrereqsPassed']}`",
f"- External trackers all live: `{payload['summary']['externalTrackersAllLive']}`",
f"- Ready for Etherscan USD Value path: `{payload['summary']['readyForEtherscanUsdValue']}`",
f"- Required external probes all pass: `{payload['summary']['externalTrackersAllLive']}` (same as tracker `summary.allTrackersLive`; DexScreener token v1 probes are optional)",
f"- Ready for Etherscan USD Value path (strict subset): `{payload['summary']['readyForEtherscanUsdValue']}`",
f"- DexScreener token APIs indexed (optional): `{payload['summary'].get('dexScreenerTokenApisIndexed', 'n/a')}`",
f"- Hard blocker count: `{payload['summary']['blockerCount']}`",
f"- Advisory open items: `{payload['summary'].get('advisoryOpenItemCount', 0)}`",
"",
"## Inputs",
"",
@@ -214,12 +221,19 @@ def write_markdown(payload: dict[str, Any], prereq: Any, trackers: Any, liquidit
[[w.get("id"), w.get("symbol", "-"), w.get("severity"), w.get("message")] for w in cmc_warnings],
) if cmc_warnings else "No CMC sanity warnings.",
"",
"## Blockers",
"## Blockers (hard)",
"",
table(
["ID", "Type", "Status", "Next action"],
[[b["id"], b["type"], b["status"], b["nextAction"]] for b in payload["blockers"]],
) if payload["blockers"] else "No current blockers detected.",
) if payload["blockers"] else "No hard blockers detected.",
"",
"## Advisory open items",
"",
table(
["ID", "Type", "Status", "Next action"],
[[b["id"], b["type"], b["status"], b["nextAction"]] for b in payload.get("advisoryOpenItems", [])],
) if payload.get("advisoryOpenItems") else "No advisory items.",
"",
"## Submission Boundary",
"",

View File

@@ -29,6 +29,18 @@ INTENTIONAL_DBIS_QUOTE_FACE = {
PROMOTED = {"cWUSDC", "cWUSDT", "cWXAUC", "cWXAUT", "cWBTC", "cWETH"}
def token_discards_listing_liquidity_claim(token: dict[str, Any]) -> bool:
"""True when the CMC-shaped row already tells reviewers not to use liquidity as listing evidence."""
prov = token.get("supply_proof_provenance") or {}
status = str(prov.get("status") or "")
source = str(prov.get("source") or "")
if status in {"proof_required", "non_reportable_until_erc20_deployed"}:
return True
if source == "deterministic-placeholder-address":
return True
return False
def load(path: Path) -> dict[str, Any]:
return json.loads(path.read_text()) if path.exists() else {}
@@ -90,7 +102,7 @@ def main() -> int:
"pairCount": len(pairs),
}
)
if liquidity <= 0:
if liquidity <= 0 and not token_discards_listing_liquidity_claim(token):
warnings.append(
{
"id": "zero_reported_liquidity",
@@ -105,7 +117,14 @@ def main() -> int:
for check in trackers.get("checks", []):
if not str(check.get("id", "")).startswith("geckoterminal"):
continue
attrs = (((check.get("jsonPreview") or {}).get("data") or {}).get("attributes") or {})
preview = check.get("jsonPreview")
if not isinstance(preview, dict):
continue
data = preview.get("data")
if not isinstance(data, dict):
continue
attrs_raw = data.get("attributes")
attrs = attrs_raw if isinstance(attrs_raw, dict) else {}
gecko_reserves.append(
{
"id": check.get("id"),

View File

@@ -1,5 +1,10 @@
#!/usr/bin/env python3
"""Probe cWUSDC public tracker/indexing surfaces and write evidence JSON."""
"""Probe cWUSDC public tracker/indexing surfaces and write evidence JSON.
DexScreener token-pairs/tokens v1 probes are supplementary DEX-terminal signals
(often empty pre-indexing). Etherscan USD value readiness follows the stricter
subset in ETHERSCAN_VALUE_PATH_READY_IDS (see summary.readyForEtherscanUsdValue).
"""
from __future__ import annotations
import argparse
@@ -23,6 +28,16 @@ POOLS = [
"0xc28706f899266b36bc43cc072b3a921bdf2c48d9",
]
# CoinGecko + public pair evidence surfaces aligned with CWUSDC_ETHERSCAN_VALUE_EXECUTION_PLAN.md;
# excludes DexScreener token-level v1 APIs (supplementary indexing, not primary price gate).
ETHERSCAN_VALUE_PATH_READY_IDS = frozenset({
"etherscan_token_page",
"coingecko_token_price_api",
"coinmarketcap_dex_token",
"geckoterminal_v3_pool",
"geckoterminal_v2_pool",
})
URLS = [
{
"id": "etherscan_token_page",
@@ -49,14 +64,14 @@ URLS = [
"id": "dexscreener_token_pairs_v1",
"kind": "dex_index",
"url": f"https://api.dexscreener.com/token-pairs/v1/ethereum/{CWUSDC}",
"required": True,
"required": False,
"jsonRootMinLength": 1,
},
{
"id": "dexscreener_tokens_v1",
"kind": "dex_index",
"url": f"https://api.dexscreener.com/tokens/v1/ethereum/{CWUSDC}",
"required": True,
"required": False,
"jsonRootMinLength": 1,
},
{
@@ -235,6 +250,8 @@ def write_markdown(payload: dict[str, Any], path: Path) -> None:
"",
f"- Generated: `{payload['generatedAt']}`",
f"- All trackers live: `{payload['summary']['allTrackersLive']}`",
f"- Ready for Etherscan USD value path (subset): `{payload['summary']['readyForEtherscanUsdValue']}`",
f"- DexScreener token APIs indexed (optional): `{payload['summary']['dexScreenerTokenApisIndexed']}`",
f"- Required passed: `{payload['summary']['requiredPassedCount']} / {payload['summary']['requiredCount']}`",
"",
"| Surface | Passed | HTTP | URL | Details |",
@@ -267,13 +284,21 @@ def main() -> int:
checks = [evaluate(spec, args.timeout, args.gecko_retries) for spec in URLS]
required = [c for c in checks if c["required"]]
required_passed = [c for c in required if c["passed"]]
passed_ids = {c["id"] for c in checks if c["passed"]}
dex_pair = next((c for c in checks if c["id"] == "dexscreener_token_pairs_v1"), None)
dex_tok = next((c for c in checks if c["id"] == "dexscreener_tokens_v1"), None)
dex_indexed = bool(
dex_pair and dex_pair["passed"] and dex_tok and dex_tok["passed"],
)
ready_for_etherscan = ETHERSCAN_VALUE_PATH_READY_IDS.issubset(passed_ids)
payload = {
"schema": "cwusdc-external-trackers-live/v1",
"generatedAt": datetime.now(timezone.utc).isoformat(),
"token": {"chainId": 1, "network": "ethereum", "address": CWUSDC, "symbol": "cWUSDC"},
"summary": {
"allTrackersLive": len(required_passed) == len(required),
"readyForEtherscanUsdValue": len(required_passed) == len(required),
"readyForEtherscanUsdValue": ready_for_etherscan,
"dexScreenerTokenApisIndexed": dex_indexed,
"requiredCount": len(required),
"requiredPassedCount": len(required_passed),
"failedRequiredIds": [c["id"] for c in required if not c["passed"]],

View File

@@ -32,6 +32,7 @@ doc_links = json.loads(doc_link_path.read_text())
repo_ok = bool(handoff["summary"]["repoControlledPrereqsPassed"])
doc_links_ok = doc_links.get("status") == "pass"
external_blockers = [b for b in handoff.get("blockers", []) if b.get("type") != "repo_controlled"]
advisory_open = handoff.get("advisoryOpenItems") or []
payload = {
"schema": "cwusdc-provider-readiness-ci/v1",
"generatedAt": datetime.now(timezone.utc).isoformat(),
@@ -42,6 +43,8 @@ payload = {
"institutionalDocLinksReport": str(doc_link_path),
"externalBlockersAdvisoryCount": len(external_blockers),
"externalBlockersAdvisory": external_blockers,
"advisoryOpenItemCount": len(advisory_open),
"advisoryOpenItems": advisory_open,
"handoffReport": str(handoff_path),
}
json_out.parent.mkdir(parents=True, exist_ok=True)
@@ -55,6 +58,7 @@ lines = [
f"- Base provider prerequisites passed: `{repo_ok}`",
f"- Institutional doc links passed: `{doc_links_ok}`",
f"- External blockers advisory count: `{len(external_blockers)}`",
f"- Handoff advisory open items: `{len(advisory_open)}`",
f"- Handoff report: `{handoff_path}`",
"",
"External provider blockers are advisory in this CI gate. They require provider acceptance or operator action and should not fail repo-controlled CI.",

View File

@@ -272,6 +272,7 @@ def build(gecko_retries: int, http_timeout: int) -> dict[str, Any]:
dexscreener = parse_dexscreener()
gecko = parse_geckoterminal(http_timeout, gecko_retries)
blockers: list[str] = []
advisory_notes: list[str] = []
if not etherscan["profileDetected"]:
blockers.append("Etherscan token profile text was not detected.")
if etherscan["onchainMarketCapMissing"]:
@@ -288,7 +289,9 @@ def build(gecko_retries: int, http_timeout: int) -> dict[str, Any]:
if not coingecko["priceReady"]:
blockers.append("CoinGecko contract price API does not return a positive USD price.")
if not dexscreener["indexed"]:
blockers.append("DexScreener token-pairs API still does not index cWUSDC pairs.")
advisory_notes.append(
"DexScreener token-pairs API has not indexed cWUSDC yet (supplementary DEX-terminal signal; not the same gate as CoinGecko for Etherscan Value)."
)
return {
"schema": "cwusdc-etherscan-value-propagation/v1",
@@ -306,6 +309,7 @@ def build(gecko_retries: int, http_timeout: int) -> dict[str, Any]:
"coingeckoPriceReady": coingecko["priceReady"],
"readyForEtherscanValuePropagation": etherscan["valueReady"] or coingecko["priceReady"],
"blockers": blockers,
"advisoryNotes": advisory_notes,
},
"checks": {
"etherscan": etherscan,
@@ -338,6 +342,10 @@ def write_md(payload: dict[str, Any], path: Path) -> None:
lines.extend(f"- {item}" for item in summary["blockers"])
else:
lines.append("- None detected by this monitor.")
advisory = summary.get("advisoryNotes") or []
if advisory:
lines.extend(["", "## Advisory (non-gating)", ""])
lines.extend(f"- {item}" for item in advisory)
lines.extend(
[
"",
@@ -388,6 +396,9 @@ def main() -> int:
print(f"etherscanValueReady={payload['summary']['etherscanValueReady']}")
if payload["summary"]["blockers"]:
print("Blockers: " + "; ".join(payload["summary"]["blockers"]))
adv = payload["summary"].get("advisoryNotes") or []
if adv:
print("Advisory (non-gating): " + "; ".join(adv))
if args.strict and not payload["summary"]["etherscanValueReady"]:
return 1
return 0

View File

@@ -46,6 +46,7 @@ payload = {
"coinGeckoPriceReady": dossier_readiness.get("coinGeckoPriceReady"),
"repoControlledPrereqsPassed": provider_ci.get("repoControlledPrereqsPassed"),
"externalBlockersAdvisory": provider_ci.get("externalBlockersAdvisory", []),
"advisoryOpenItems": provider_ci.get("advisoryOpenItems", []),
"docLinkStatus": links.get("status"),
"roleEventCount": role_appendix.get("eventCount"),
"artifacts": {
@@ -69,6 +70,7 @@ lines = [
f"- Institutional doc link status: `{payload['docLinkStatus']}`",
f"- Role event count: `{payload['roleEventCount']}`",
f"- External advisory blockers: `{len(payload['externalBlockersAdvisory'])}`",
f"- Handoff advisory open items: `{len(payload.get('advisoryOpenItems', []))}`",
]
md_out.write_text("\n".join(lines) + "\n")
print(f"Wrote {json_out}")