const TRAIT_MAP_REGISTRY_ID = "344ac46ea140b52ef251b1759750a5899576af4c5f6a6905358a35f646801483i0"; const BASE_IMAGES = { 1: "inscription:BASE_IMG_1", 2: "inscription:BASE_IMG_2", 3: "df9c7b3a9cf41f2bfb595ef4d0275acd820bd85cab0cf72cb6d307b5ad980ba8i0", 4: "inscription:BASE_IMG_4", 5: "inscription:BASE_IMG_5", 6: "inscription:BASE_IMG_6", 7: "inscription:BASE_IMG_7", 8: "inscription:BASE_IMG_8" }; const SERVER_PUBKEY = "0261ff6a8a84c768db1ab9b90ffdc68fe57e29dc8a3782d8aa7dd25fd848f649f8"; const canvas = document.getElementById('dog'); const ctx = canvas.getContext('2d'); const sha256 = async msg => new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(msg))); const hexToBytes = hex => new Uint8Array(hex.match(/.{1,2}/g).map(b => parseInt(b, 16))); async function verifySignature(json, fields) { const payload = {}; for (const k of fields) payload[k] = json[k]; if (json.op_id) payload.op_id = json.op_id; const msg = JSON.stringify(payload); const hash = await sha256(msg); const sig = hexToBytes(json.signature); const pub = hexToBytes(SERVER_PUBKEY); const key = await crypto.subtle.importKey("raw", pub, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]); return await crypto.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, key, sig, hash); } async function fetchDedupedValidChildOrSelf(parentId, fields, keyField = "op_id", filterFn = null) { const children = await fetch(`/r/children/${parentId}/inscriptions`).then(r => r.json()); const seen = new Set(); const valid = []; for (const insc of children) { if (insc.content_type !== "application/json") continue; const json = await fetch(`/content/${insc.inscription_id}`).then(r => r.json()).catch(() => null); if (!json || !json.signature) continue; if (filterFn && !filterFn(json)) continue; if (!(await verifySignature(json, fields))) continue; const key = json[keyField]; if (!key || seen.has(key)) continue; seen.add(key); valid.push({ ...json, inscription_number: insc.inscription_number }); } if (valid.length > 0) { valid.sort((a, b) => a.inscription_number - b.inscription_number); return valid[0]; } // Fallback to the parent inscription itself const fallbackJson = await fetch(`/content/${parentId}`).then(r => r.json()).catch(() => null); if (fallbackJson && fallbackJson.signature && await verifySignature(fallbackJson, fields)) { return fallbackJson; } return null; } async function drawImageById(id) { const img = new Image(); img.crossOrigin = "anonymous"; img.src = `/content/${id}`; await new Promise((res, rej) => { img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); res(); }; img.onerror = rej; }); } (async () => { const { PUP_ID, INITIAL_PUP_TYPE } = window; const latestUpdate = await fetchDedupedValidChildOrSelf( TRAIT_MAP_REGISTRY_ID, ["pup_id", "pup_type", "traits", "op_id"], "op_id", json => json.pup_id === PUP_ID ); const traitMapWrap = await fetchDedupedValidChildOrSelf( TRAIT_MAP_REGISTRY_ID, ["trait_map", "op_id"], "op_id" ); const traitMap = traitMapWrap?.trait_map || {}; const pupType = latestUpdate?.pup_type || INITIAL_PUP_TYPE; const traits = latestUpdate?.traits || []; const baseImageId = BASE_IMAGES[pupType]; if (baseImageId) await drawImageById(baseImageId); for (const slug of traits) { const traitInsc = traitMap[slug]; if (traitInsc) await drawImageById(traitInsc); } const imgOut = new Image(); imgOut.src = canvas.toDataURL('image/png'); imgOut.style = 'width:100vw;height:100vh;object-fit:contain;background:black;margin:0;padding:0;display:block'; document.body.innerHTML = ''; document.body.style = 'margin:0;padding:0;background:black'; document.body.appendChild(imgOut); })();