Skip to content

Instantly share code, notes, and snippets.

@wenakita
Created April 20, 2026 01:39
Show Gist options
  • Select an option

  • Save wenakita/0beac860e1909deb7054995bd3383efa to your computer and use it in GitHub Desktop.

Select an option

Save wenakita/0beac860e1909deb7054995bd3383efa to your computer and use it in GitHub Desktop.
Zora sandbox probe — $PROBE coin source. Maps what an HTML content coin can actually do (window.ethereum? fetch? localStorage? signing?).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Zora sandbox probe</title>
<style>
:root { color-scheme: dark; }
html, body {
margin: 0; padding: 0; background: #0a0a0a; color: #e5e5e5;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace;
font-size: 12px; line-height: 1.55;
min-height: 100vh;
}
.wrap {
padding: 24px; max-width: 680px; margin: 0 auto;
}
h1 {
font-size: 13px; letter-spacing: 0.12em; text-transform: uppercase;
color: #8b8b8b; font-weight: 500; margin: 0 0 4px 0;
}
h2 {
font-size: 18px; margin: 0 0 18px 0; color: #fff; font-weight: 500;
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
}
.row {
display: flex; gap: 12px; align-items: baseline;
padding: 10px 0; border-bottom: 1px solid #1a1a1a;
}
.row:last-child { border-bottom: 0; }
.label {
color: #888; min-width: 190px; flex-shrink: 0;
}
.value {
color: #e5e5e5; word-break: break-all; flex: 1;
}
.tag {
display: inline-block; padding: 1px 7px; border-radius: 3px;
font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase;
margin-right: 6px; vertical-align: middle;
}
.tag.pass { background: #14321e; color: #6bd392; border: 1px solid #1f5b38; }
.tag.fail { background: #3a1414; color: #ee6a6a; border: 1px solid #5c2020; }
.tag.neutral { background: #1a1a1a; color: #999; border: 1px solid #262626; }
.tag.pending { background: #1a1a1a; color: #c89a2b; border: 1px solid #3a2d13; }
pre {
background: #141414; padding: 10px; border: 1px solid #242424;
border-radius: 4px; color: #cfcfcf; font-size: 11px;
overflow-x: auto; margin: 6px 0 0 0; white-space: pre-wrap;
}
button {
background: #fff; color: #000; border: 0; padding: 8px 14px;
font-family: inherit; font-size: 11px; letter-spacing: 0.06em;
text-transform: uppercase; cursor: pointer; border-radius: 4px;
margin: 4px 6px 0 0;
}
button:hover { background: #e0e0e0; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
button.secondary { background: transparent; color: #aaa; border: 1px solid #333; }
button.secondary:hover { background: #181818; color: #fff; }
.section {
margin-top: 28px; padding-top: 20px; border-top: 1px solid #1f1f1f;
}
.muted { color: #666; font-size: 11px; margin-top: 4px; }
#copied {
display: inline-block; margin-left: 10px; color: #6bd392;
opacity: 0; transition: opacity 0.3s;
}
#copied.show { opacity: 1; }
</style>
</head>
<body>
<div class="wrap">
<h1>Zora sandbox probe · v1</h1>
<h2>What can an HTML content coin actually do on Zora?</h2>
<div class="row">
<div class="label">iframe origin</div>
<div class="value" id="origin"></div>
</div>
<div class="row">
<div class="label">iframe location.href</div>
<div class="value" id="href"></div>
</div>
<div class="row">
<div class="label">is in iframe?</div>
<div class="value" id="is-iframe"></div>
</div>
<div class="row">
<div class="label">parent-window access</div>
<div class="value" id="parent-access"></div>
</div>
<div class="row">
<div class="label">top.location.href</div>
<div class="value" id="top-href"></div>
</div>
<div class="section">
<div class="row">
<div class="label">window.ethereum</div>
<div class="value" id="window-ethereum"></div>
</div>
<div class="row">
<div class="label">EIP-6963 providers</div>
<div class="value" id="eip6963"></div>
</div>
<div class="row">
<div class="label">eth_accounts (passive)</div>
<div class="value" id="eth-accounts"></div>
</div>
<div class="row">
<div class="label">eth_chainId (passive)</div>
<div class="value" id="eth-chain"></div>
</div>
</div>
<div class="section">
<div class="row">
<div class="label">fetch public Base RPC</div>
<div class="value" id="rpc-fetch"></div>
</div>
<div class="row">
<div class="label">fetch IPFS gateway</div>
<div class="value" id="ipfs-fetch"></div>
</div>
<div class="row">
<div class="label">fetch 4626 domain</div>
<div class="value" id="fourrsix-fetch"></div>
</div>
<div class="row">
<div class="label">localStorage</div>
<div class="value" id="localstorage"></div>
</div>
<div class="row">
<div class="label">sessionStorage</div>
<div class="value" id="sessionstorage"></div>
</div>
<div class="row">
<div class="label">cookies</div>
<div class="value" id="cookies"></div>
</div>
</div>
<div class="section">
<div class="muted">
Manual tests — these need your click (browsers block automatic versions):
</div>
<button id="test-open">Test window.open → 4626.fun</button>
<button id="test-wallet">Test wallet connect (eth_requestAccounts)</button>
<button id="test-sign">Test personal_sign</button>
<div id="manual-result" class="muted" style="margin-top: 10px"></div>
</div>
<div class="section">
<div class="muted">Copy all findings into your clipboard so you can paste them back to me:</div>
<button id="copy-btn">Copy results</button>
<button id="refresh-btn" class="secondary">Rerun probes</button>
<span id="copied">copied</span>
<pre id="dump" style="margin-top: 12px; max-height: 260px; overflow: auto"></pre>
</div>
<div class="section muted">
Zora sandbox probe. No wallet signatures are sent without your explicit click
on the manual-test buttons. Upload this .html to Zora as a content coin and
view the card to run the probes.
</div>
</div>
<script>
// ─── Helpers ─────────────────────────────────────────────────────────
const set = (id, html, tag) => {
const el = document.getElementById(id);
if (!el) return;
const tagHtml = tag
? `<span class="tag ${tag.cls}">${tag.text}</span>`
: "";
el.innerHTML = tagHtml + html;
};
const results = {};
const store = (k, v, tag) => { results[k] = { value: v, tag: tag?.text ?? null }; };
// Tag shortcuts
const pass = (text = "yes") => ({ cls: "pass", text });
const fail = (text = "no") => ({ cls: "fail", text });
const neutral = (text) => ({ cls: "neutral", text });
const pending = (text = "pending") => ({ cls: "pending", text });
// ─── 1. Basic iframe + origin info ───────────────────────────────────
(function () {
try {
const origin = window.location.origin || "(null origin)";
const href = window.location.href;
set("origin", origin, neutral(origin.includes("null") ? "null" : "set"));
store("origin", origin);
set("href", href);
store("href", href);
} catch (e) {
set("origin", String(e), fail());
set("href", String(e), fail());
}
const isFrame = window.parent !== window || window.top !== window;
set("is-iframe", String(isFrame), isFrame ? pass("sandboxed") : neutral("top-level"));
store("is-iframe", isFrame);
try {
const _ = window.parent.document; // throws on cross-origin
set("parent-access", "✓ parent.document readable", pass("allowed"));
store("parent-access", "allowed");
} catch (e) {
set("parent-access", `blocked: ${e.name}`, fail("blocked"));
store("parent-access", `blocked: ${e.name}`);
}
try {
const url = window.top.location.href;
set("top-href", url || "(empty)", pass("readable"));
store("top-href", url);
} catch (e) {
set("top-href", `blocked: ${e.name}`, fail("blocked"));
store("top-href", `blocked: ${e.name}`);
}
})();
// ─── 2. Wallet provider detection ────────────────────────────────────
(function () {
const hasEth = typeof window.ethereum !== "undefined";
if (hasEth) {
const info = [];
const e = window.ethereum;
if (e.isMetaMask) info.push("isMetaMask");
if (e.isRabby) info.push("isRabby");
if (e.isCoinbaseWallet) info.push("isCoinbaseWallet");
if (e.isPhantom) info.push("isPhantom");
if (e.isBraveWallet) info.push("isBraveWallet");
if (Array.isArray(e.providers)) info.push(`providers[${e.providers.length}]`);
set("window-ethereum", info.join(", ") || "injected (unknown flavor)", pass("injected"));
store("window-ethereum", info.join(", ") || "injected");
} else {
set("window-ethereum", "undefined", fail("absent"));
store("window-ethereum", "undefined");
}
// EIP-6963: modern wallet discovery
const providers = [];
const onAnnounce = (e) => {
const info = e.detail?.info || {};
providers.push(`${info.name || "?"} (rdns ${info.rdns || "?"})`);
renderEip6963();
};
const renderEip6963 = () => {
if (providers.length === 0) {
set("eip6963", "no announce events (yet)", neutral("pending"));
} else {
set("eip6963", providers.join(" · "), pass(`${providers.length} wallet(s)`));
store("eip6963", providers);
}
};
window.addEventListener("eip6963:announceProvider", onAnnounce);
window.dispatchEvent(new Event("eip6963:requestProvider"));
renderEip6963();
setTimeout(renderEip6963, 300);
setTimeout(renderEip6963, 1500);
})();
// ─── 3. Passive RPC calls (eth_accounts/chainId don't prompt user) ───
(async function () {
if (typeof window.ethereum === "undefined") {
set("eth-accounts", "skipped (no provider)", neutral("skip"));
set("eth-chain", "skipped (no provider)", neutral("skip"));
return;
}
try {
const accounts = await window.ethereum.request({ method: "eth_accounts" });
if (Array.isArray(accounts) && accounts.length > 0) {
set("eth-accounts", accounts.join(", "), pass("authorized"));
store("eth-accounts", accounts);
} else {
set("eth-accounts", "[] (not connected to this origin)", neutral("empty"));
store("eth-accounts", []);
}
} catch (e) {
set("eth-accounts", `error: ${e.message || e}`, fail());
store("eth-accounts", `error: ${e.message || e}`);
}
try {
const chain = await window.ethereum.request({ method: "eth_chainId" });
set("eth-chain", `${chain} (${parseInt(chain, 16)})`, pass());
store("eth-chain", chain);
} catch (e) {
set("eth-chain", `error: ${e.message || e}`, fail());
store("eth-chain", `error: ${e.message || e}`);
}
})();
// ─── 4. Network reachability ─────────────────────────────────────────
set("rpc-fetch", "running…", pending());
set("ipfs-fetch", "running…", pending());
set("fourrsix-fetch", "running…", pending());
(async function () {
// Base mainnet public RPC
try {
const r = await fetch("https://mainnet.base.org", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", method: "eth_blockNumber", params: [], id: 1 }),
});
const j = await r.json();
if (j.result) {
const block = parseInt(j.result, 16);
set("rpc-fetch", `OK, block ${block}`, pass("allowed"));
store("rpc-fetch", `block ${block}`);
} else {
set("rpc-fetch", `response: ${JSON.stringify(j)}`, neutral("weird"));
store("rpc-fetch", JSON.stringify(j));
}
} catch (e) {
set("rpc-fetch", `blocked: ${e.message || e}`, fail());
store("rpc-fetch", `blocked: ${e.message || e}`);
}
// Generic IPFS gateway (useful if we want to load ADDITIONAL on-chain assets)
try {
const r = await fetch("https://ipfs.io/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG", { method: "HEAD" });
set("ipfs-fetch", `status ${r.status}`, r.ok ? pass("allowed") : fail());
store("ipfs-fetch", `status ${r.status}`);
} catch (e) {
set("ipfs-fetch", `blocked: ${e.message || e}`, fail());
store("ipfs-fetch", `blocked: ${e.message || e}`);
}
// 4626 domain (test cross-domain fetch with CORS)
try {
const r = await fetch("https://4626.fun", { method: "HEAD", mode: "cors" });
set("fourrsix-fetch", `status ${r.status} (cors mode)`, r.ok ? pass() : neutral("reachable"));
store("fourrsix-fetch", `status ${r.status}`);
} catch (e) {
set("fourrsix-fetch", `blocked by CORS: ${e.message || e}`, fail("cors blocked"));
store("fourrsix-fetch", `cors blocked: ${e.message || e}`);
}
})();
// ─── 5. Storage + cookies ────────────────────────────────────────────
(function () {
try {
localStorage.setItem("__probe", "1");
const v = localStorage.getItem("__probe");
localStorage.removeItem("__probe");
set("localstorage", `roundtrip ok (${v})`, pass("works"));
store("localstorage", "works");
} catch (e) {
set("localstorage", `blocked: ${e.message || e}`, fail("blocked"));
store("localstorage", "blocked");
}
try {
sessionStorage.setItem("__probe", "1");
const v = sessionStorage.getItem("__probe");
sessionStorage.removeItem("__probe");
set("sessionstorage", `roundtrip ok (${v})`, pass("works"));
store("sessionstorage", "works");
} catch (e) {
set("sessionstorage", `blocked: ${e.message || e}`, fail("blocked"));
store("sessionstorage", "blocked");
}
try {
document.cookie = "probe=1; path=/";
const visible = document.cookie.includes("probe=1");
set("cookies", visible ? "readable/writable" : "read-only", visible ? pass() : neutral("read-only"));
store("cookies", visible ? "rw" : "read-only");
} catch (e) {
set("cookies", `blocked: ${e.message || e}`, fail("blocked"));
store("cookies", "blocked");
}
})();
// ─── 6. Manual tests (user-click-gated) ──────────────────────────────
const manualEl = document.getElementById("manual-result");
document.getElementById("test-open").addEventListener("click", () => {
try {
const w = window.open("https://4626.fun?from=zora-probe", "_blank");
if (w) {
manualEl.textContent = "window.open returned a handle — popup ALLOWED ✓";
results["window.open"] = { value: "allowed", tag: "allowed" };
} else {
manualEl.textContent = "window.open returned null — BLOCKED by sandbox or popup blocker";
results["window.open"] = { value: "blocked (null)", tag: "blocked" };
}
} catch (e) {
manualEl.textContent = `window.open threw: ${e.message || e}`;
results["window.open"] = { value: `threw: ${e.message}`, tag: "error" };
}
});
document.getElementById("test-wallet").addEventListener("click", async () => {
if (typeof window.ethereum === "undefined") {
manualEl.textContent = "No window.ethereum — nothing to call";
return;
}
try {
manualEl.textContent = "Requesting accounts… approve in wallet popup";
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
manualEl.textContent = `accounts: ${JSON.stringify(accounts)} ✓ WALLET INTERACTION WORKS IN SANDBOX`;
results["eth_requestAccounts"] = { value: accounts, tag: "allowed" };
} catch (e) {
manualEl.textContent = `wallet rejected or blocked: ${e.message || e}`;
results["eth_requestAccounts"] = { value: `error: ${e.message}`, tag: "error" };
}
});
document.getElementById("test-sign").addEventListener("click", async () => {
if (typeof window.ethereum === "undefined") {
manualEl.textContent = "No window.ethereum — nothing to call";
return;
}
try {
const accs = await window.ethereum.request({ method: "eth_accounts" });
if (!accs || !accs.length) {
manualEl.textContent = "No authorized account. Click 'Test wallet connect' first.";
return;
}
manualEl.textContent = "Requesting signature… approve in wallet popup";
const msg = `Zora sandbox probe · signing from ${window.location.origin}`;
const sig = await window.ethereum.request({
method: "personal_sign",
params: [msg, accs[0]],
});
manualEl.textContent = `sig: ${sig.slice(0, 20)}… ✓ SIGNING WORKS IN SANDBOX`;
results["personal_sign"] = { value: sig, tag: "allowed" };
} catch (e) {
manualEl.textContent = `signature rejected or blocked: ${e.message || e}`;
results["personal_sign"] = { value: `error: ${e.message}`, tag: "error" };
}
});
// ─── 7. Copy dump ────────────────────────────────────────────────────
const renderDump = () => {
const payload = {
userAgent: navigator.userAgent,
...Object.fromEntries(Object.entries(results).map(([k, v]) => [k, v.value])),
};
document.getElementById("dump").textContent = JSON.stringify(payload, null, 2);
};
setInterval(renderDump, 500);
renderDump();
document.getElementById("copy-btn").addEventListener("click", async () => {
const text = document.getElementById("dump").textContent;
try {
await navigator.clipboard.writeText(text);
} catch {
// fallback
const ta = document.createElement("textarea");
ta.value = text; document.body.appendChild(ta); ta.select();
document.execCommand("copy"); document.body.removeChild(ta);
}
const toast = document.getElementById("copied");
toast.classList.add("show");
setTimeout(() => toast.classList.remove("show"), 1200);
});
document.getElementById("refresh-btn").addEventListener("click", () => {
window.location.reload();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment