Use Nuno in Your App
Nuno counts people, not wallets. The numbers on this site are open: read them as static JSON from any app or bot, or straight from NunoFeed on Monad. No key, no sign-up, no cost.
JSON API
Plain files served next to this site and rebuilt every 20 minutes. Addresses are lowercase. Select an endpoint to see its URL, examples and a real sample.
Sample from the current export
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/meta.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "sourceBlock": 113684810, "sourceTime": "2026-10-15T18:29:43.000Z", "chainHead": 116813277, "behindBlocks": 3128467, "generatedAt": "2026-10-26T17:18:27.605Z", "dbSizeBytes": 8564736, "window": { "startBlock": 110547485, "endBlock": 113684810, "startTime": "2026-10-04T19:16:10.000Z", "endTime": "2026-10-15T18:29:43.000Z", "days": 7, "coveredDays": 10.97 }, "counts": { "tokens": 439, "tokensWithMetrics": 439, "prunedTokens": 180, "entities": 330, "walletsInEntities": 1735, "curveTrades": 12715, "fundingEdges": 4910 }, "refreshIntervalMinutes": 20 }
Sample from the current export
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/tokens.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "count": 439, "tokens": [ { "address": "0x1b109ae28d5b9a4a9df129b97c921027faf17777", "name": "Ducki", "symbol": "Ducki", "creator": "0xdea8e378ac23000c6584f949e48fa80c6c7a99c2", "createBlock": 110817107, "createTx": "0xc03fb64b865196c78a7a0afdb7f6416953f74237f00f1d885ddd953a23e6eace", "graduatedPool": null, "metrics": { "sourceBlock": 113092810, "totalSupply": "1000000000000000000000000000", "rawHolders": 248, "realHolders": 49, "effectiveTop10Bps": 1075, "clusterSupplyBps": 52, "creatorLinkedSupplyBps": 0, "rawVolume": "1666123850589849973087359", "organicVolume": "332995683861151572280570", "organicVolumeBps": 1998, "evidenceRoot": "0xe1b001cd83f688e11b91707c64928b2796445ee2f45c24535d1dc1a80010a87c", "computedAt": "2026-10-14T07:31:41.234Z" }, "pruned": true }, "…" ] }
Sample from the current export
URL
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/tokens/0x1b109ae28d5b9a4a9df129b97c921027faf17777.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "address": "0x1b109ae28d5b9a4a9df129b97c921027faf17777", "name": "Ducki", "symbol": "Ducki", "creator": "0xdea8e378ac23000c6584f949e48fa80c6c7a99c2", "createBlock": 110817107, "createTx": "0xc03fb64b865196c78a7a0afdb7f6416953f74237f00f1d885ddd953a23e6eace", "graduatedPool": null, "metrics": { "sourceBlock": 113092810, "totalSupply": "1000000000000000000000000000", "rawHolders": 248, "realHolders": 49, "effectiveTop10Bps": 1075, "clusterSupplyBps": 52, "creatorLinkedSupplyBps": 0, "rawVolume": "1666123850589849973087359", "organicVolume": "332995683861151572280570", "organicVolumeBps": 1998, "evidenceRoot": "0xe1b001cd83f688e11b91707c64928b2796445ee2f45c24535d1dc1a80010a87c", "computedAt": "2026-10-14T07:31:41.234Z" }, "pruned": true, "latestSnapshot": null, "clusters": [], "evidenceCanonical": "…" }
Sample from the current export
URL
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/clusters/0x045faf9b5c95f6a13d771b359d67e7c0603959cf.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "id": "0x045faf9b5c95f6a13d771b359d67e7c0603959cf", "size": 323, "members": [ "0x045faf9b5c95f6a13d771b359d67e7c0603959cf", "0x04e03b13e811d971b3225301e384883594df8031", "0x055fc249faa36156e49843c2cef7ccbe7b7ca6a5", "…" ], "createdTokens": [ "0x474a6aea440a6d18c164181b2b106ac67d197777", "0x6c85970726a3f808a93a81ebcf4a15b981787777", "…" ], "sourceBlock": 113684810, "links": [ { "a": "0x41169d44a6e64babedffffc61a2656c7367d0c54", "b": "0xce2bafb357b86f5fe19ddb4d7f7178e3916a5599", "type": "same_direct_funder", "weight": 1, "evidence": [ { "type": "same_direct_funder", "txHash": "0xab8135c01083029c87c890b2ea4d1c880f7939f2317c51f834d283630b77e127", "block": 111873763, "detail": "0xc7bfbdbee0d9740c218f1f64d0eca6f79753754f" }, { "type": "same_direct_funder", "txHash": "0xddedc7d45533c6447ec45196cd7ca6839c2c15c4ecdfbfff2b2830caf1bcf88a", "block": 111715945, "detail": "0xc7bfbdbee0d9740c218f1f64d0eca6f79753754f" } ] }, "…" ], "nansenRelated": [ { "address": "0x241ac4326ba9f5ff6f4bf101ff5059b904c30e30", "label": "", "relation": "First Funder", "tx": "0x7fac9d720b27f70e6a04a3ab2e8426b84f8d2ea8418119b87d37fd42bd5fafec" } ], "labels": { "0x41169d44a6e64babedffffc61a2656c7367d0c54": { "label": "", "category": "unlabelled" }, "0xc7bfbdbee0d9740c218f1f64d0eca6f79753754f": { "label": "", "category": "unlabelled" } } }
Sample from the current export
URL
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/wallets/0x045faf9b5c95f6a13d771b359d67e7c0603959cf.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "address": "0x045faf9b5c95f6a13d771b359d67e7c0603959cf", "isContract": false, "entityId": "0x045faf9b5c95f6a13d771b359d67e7c0603959cf", "fundingStatus": "pending", "fundedBy": [], "funded": [], "trades": [] }
Sample from the current export
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/nansen.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "endpoint": "POST https://api.nansen.ai/api/v1/profiler/address/related-wallets", "checked": 47, "matches": 46, "checks": [ { "address": "0xc7bfbdbee0d9740c218f1f64d0eca6f79753754f", "entityId": null, "nansenFirstFunder": { "address": "0xaa6e392ca599f9a447bba9bd03608527a5360b0c", "label": null, "tx": "0xd728b0a3f511474177c969c4c51de4174f1097b72ef7b60d130d9cfd4ad21c25" }, "nunoFirstFunder": { "address": "0xaa6e392ca599f9a447bba9bd03608527a5360b0c", "tx": "0xd728b0a3f511474177c969c4c51de4174f1097b72ef7b60d130d9cfd4ad21c25", "block": 109967735 }, "match": true, "fetchedAt": "2026-10-12T04:06:13.606Z" }, { "address": "0x573ba1f65418629c524806b9a358f5df9e67190e", "entityId": null, "nansenFirstFunder": { "address": "0x41169d44a6e64babedffffc61a2656c7367d0c54", "label": null, "tx": "0xc1bf202fcf9b237fd10065409eead959bc40c5a75c0a24372d31b4e5b71d5216" }, "nunoFirstFunder": { "address": "0x41169d44a6e64babedffffc61a2656c7367d0c54", "tx": "0xc1bf202fcf9b237fd10065409eead959bc40c5a75c0a24372d31b4e5b71d5216", "block": 111878135 }, "match": true, "fetchedAt": "2026-10-12T04:06:18.444Z" }, "…" ] }
Sample from the current export
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/logos.json"); const data = await res.json(); console.log(data);Sample from the current export
{ "0x1b109ae28d5b9a4a9df129b97c921027faf17777": { "image": "https://storage.nadapp.net/coin/a7fa1f5e-0645-4ac1-aac5-af9ec5289379", "website": "https://www.ducki.fun", "twitter": "https://x.com/duckimonad", "telegram": null, "curve": "V2", "createdAt": "2026-10-05T17:54:58.000Z" }, "…": "…" }
api/meta.json
const res = await fetch("https://andrew1234-arch.github.io/nuno/api/meta.json");
const data = await res.json();
console.log(data);Sample from the current export
{ "sourceBlock": 113684810, "sourceTime": "2026-10-15T18:29:43.000Z", "chainHead": 116813277, "behindBlocks": 3128467, "generatedAt": "2026-10-26T17:18:27.605Z", "dbSizeBytes": 8564736, "window": { "startBlock": 110547485, "endBlock": 113684810, "startTime": "2026-10-04T19:16:10.000Z", "endTime": "2026-10-15T18:29:43.000Z", "days": 7, "coveredDays": 10.97 }, "counts": { "tokens": 439, "tokensWithMetrics": 439, "prunedTokens": 180, "entities": 330, "walletsInEntities": 1735, "curveTrades": 12715, "fundingEdges": 4910 }, "refreshIntervalMinutes": 20 }
How labels are decided
The site turns the metrics into a label with these rules. Any of the first three gives Many linked wallets, any other gives Some linked wallets, none gives No linked wallets found. Labels describe what was found, not risk. The cut-offs are our own choice and have not been tested against hand-labelled tokens.
- Many linked walletsThe creator belongs to a wallet group that launched 5 or more tokens in the window.
- Many linked walletsAt least 5 wallets hold it, and real owners are half the holder count or fewer.
- Many linked walletsWallet groups hold 20% or more of the supply, or the creator's side holds 10% or more.
- Some linked walletsThe creator belongs to a wallet group.
- Some linked walletsAt least 5 wallets hold it, and real owners are 85% of the holder count or fewer.
- Some linked walletsWallet groups hold 5% or more of the supply, or the creator's side holds 3% or more.
"The creator's wallet group" is the cluster whose members include the token's creator. How clusters are formed: methodology.
Labels
| Many linked wallets | Its creator or holders are linked to many other wallets. See who, and the proof. |
| Some linked wallets | Some of its creator's or holders' wallets are linked. See who, and the proof. |
| No linked wallets found | No links found between its creator and holders and other wallets. Not a guarantee. |
| Not enough data | Too little trading to say. |
Label names as shown: Many linked wallets · Some linked wallets · No linked wallets found · Not enough data.
Contracts (Monad testnet)
NunoFeed
Stores the latest cluster-adjusted numbers per nad.fun token; anyone can read them.
0xBeda259a77417E20839ebc2bDE4558Abcfd47042Explorer ↗
OrganicGate
Example consumer: reverts unless a token's snapshot is fresh and its cluster-held supply is under your limit.
0xec3b8718154f5a060bc9D29A11b23583999BBbd8Explorer ↗
function latest(address token) external view returns (Snapshot memory)
function hasSnapshot(address token) external view returns (bool)
Snapshot fields
| sourceBlock | uint64 | mainnet block the numbers are from |
| publishedAt | uint64 | testnet timestamp of the write |
| rawHolders | uint32 | wallets holding the token |
| realHolders | uint32 | real owners, entities counted once |
| clusterSupplyBps | uint16 | supply held by clusters (bps) |
| effectiveTop10Bps | uint16 | top 10 owners' share (bps) |
| creatorLinkedSupplyBps | uint16 | creator and linked wallets (bps) |
| organicVolumeBps | uint16 | organic share of volume (bps) |
| evidenceRoot | bytes32 | matches metrics.evidenceRoot in the JSON |
Read latest(token) with viem
import { createPublicClient, http, parseAbi } from "viem";
const client = createPublicClient({ transport: http("https://testnet-rpc.monad.xyz") });
const abi = parseAbi([
"function latest(address token) view returns ((uint64 sourceBlock, uint64 publishedAt, uint32 rawHolders, uint32 realHolders, uint16 clusterSupplyBps, uint16 effectiveTop10Bps, uint16 creatorLinkedSupplyBps, uint16 organicVolumeBps, bytes32 evidenceRoot))",
]);
const s = await client.readContract({
address: "0xBeda259a77417E20839ebc2bDE4558Abcfd47042", // NunoFeed
abi,
functionName: "latest",
args: ["0x1b109ae28d5b9a4a9df129b97c921027faf17777"],
});
console.log(s.rawHolders, "holders,", s.realHolders, "real owners");Gate a contract with OrganicGate
interface IOrganicGate {
function requireOrganic(address token, uint16 maxClusterBps, uint256 maxAge) external view;
function isOrganic(address token, uint16 maxClusterBps, uint256 maxAge) external view returns (bool);
}
// OrganicGate on Monad testnet: 0xec3b8718154f5a060bc9D29A11b23583999BBbd8
IOrganicGate constant GATE = IOrganicGate(0xec3b8718154f5a060bc9D29A11b23583999BBbd8);
function buy(address token) external {
// Reverts with NoSnapshot, StaleSnapshot or TooClustered:
// at most 20% of supply in clusters, data at most 1 day old.
GATE.requireOrganic(token, 2000, 1 days);
// ...
}Limits
- Covers nad.fun tokens launched in about the last week; older tokens drop out of the window.
- Rebuilt every 20 minutes; meta.json says how fresh the data is.
- The contracts are on testnet: the numbers are real mainnet data, but don't secure real funds with them.
- Clusters are a careful best guess from public transactions, not a certainty. Every link carries its proof so you can check it.
At a glance
- Refresh
- about every 20 minutes
- Window
- 7 days (now Oct 4–15, 2026)
- Reads
- nad.fun on Monad mainnet (chain 143)
- Publishes
- NunoFeed on Monad testnet (chain 10143)
- Key
- none required
- Rate
- static files on GitHub Pages; cache them and re-fetch after each refresh