web/src/lookup.ts31 lines · 1308 bytes
| 1 | // Sourcify lookup of contract addresses (live Sepolia only): the page shows "verified" only after a confirmed match; |
| 2 | // a network failure shows nothing (no claim either way). GET only; nothing is signed or sent. |
| 3 | import { CHAIN } from './runtime' |
| 4 | import { store } from './store' |
| 5 | |
| 6 | /** One lookup per address; a network error may be retried after 15 s */ |
| 7 | export function checkVerified(addr: string | undefined | null) { |
| 8 | if (!addr || !CHAIN.sourcifyApi || /^0x0{40}$/i.test(addr)) return |
| 9 | const key = addr.toLowerCase() |
| 10 | if (store.verified.has(key)) return |
| 11 | store.verified.set(key, 'pending') |
| 12 | const ctl = new AbortController() |
| 13 | const timer = setTimeout(() => ctl.abort(), 8000) |
| 14 | fetch(CHAIN.sourcifyApi + addr, { signal: ctl.signal }) |
| 15 | .then(async (r) => { |
| 16 | if (r.status === 404) return store.verified.set(key, 'no') |
| 17 | if (!r.ok) throw new Error(`HTTP ${r.status}`) |
| 18 | const j = (await r.json()) as { match?: string | null; runtimeMatch?: string | null } |
| 19 | store.verified.set(key, j.match || j.runtimeMatch ? 'yes' : 'no') |
| 20 | }) |
| 21 | .catch(() => { |
| 22 | store.verified.set(key, 'err') |
| 23 | setTimeout(() => { |
| 24 | if (store.verified.get(key) === 'err') store.verified.delete(key) |
| 25 | }, 15000) |
| 26 | }) |
| 27 | .finally(() => { |
| 28 | clearTimeout(timer) |
| 29 | store.emit() |
| 30 | }) |
| 31 | } |