How to Inspect a Diamond with Louper
Step-by-step guide to auditing any deployed diamond with Louper: reading facets, calling view functions, and exporting the combined ABI.
Louper reads a diamond's structure directly from chain state using the loupe functions, then enriches it with verified source from block explorers. This guide walks through the whole workflow, from looking up a contract to exporting an ABI you can script against.
1. Open a diamond
Use the search bar at the top of any page: paste the diamond's address, pick the network, and submit. You can also link directly, which is handy for documentation and bug reports:
https://louper.dev/diamond/<address>?network=<network>
# Examples
https://louper.dev/diamond/0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE?network=mainnet
https://louper.dev/diamond/0x86935f11c86623dec8a25696e1c19a8659cbf95d?network=polygon Every supported network has its own key. If you land on an error page, the two usual causes are
a wrong network selection and an address that is not actually a diamond — Louper needs a working facets() function to enumerate anything.
2. Read the Facets tab
The default view lists every facet the diamond currently routes to. For each one you get:
- The facet name, taken from verified source. An address shown without a meaningful name means the contract is unverified.
- The facet address, with copy and block-explorer buttons.
- A method count, expandable into the full list of function names and their 4-byte selectors.
- An ABI viewer for that individual facet.
Functions displayed as unknown_0x12345678 are selectors that Louper could not resolve
to a name — the facet is unverified and the selector is not in any public database. Treat these as
unknown code, especially on facets that hold privileges.
3. Call view functions in the Read tab
The Read tab exposes every view and pure function across
all facets, grouped by facet. Calls are free and require no wallet. This is the fastest way to answer
ownership questions during a review:
owner()— who can upgrade the diamondpaused()— whether an emergency stop is activefacetAddress(bytes4)— which facet handles a given selector
4. Simulate state changes in the Write tab
The Write tab lists state-changing functions and requires a connected wallet. Louper will prompt you to switch to the diamond's network, since sending a transaction on the wrong chain is a common and expensive mistake.
Write calls send real transactions and spend real funds. Confirm the network, the diamond address, and the exact arguments before signing anything.
5. Export the combined ABI
The View Diamond ABI button assembles every facet's filtered ABI into a single JSON array. This is the artifact you want for integration work: point ethers, viem or web3.py at the diamond address with this ABI and every function routes correctly, because from a caller's perspective a diamond is one contract.
Note that it is filtered — only functions actually registered on the diamond are included, so it will not contain entries that would revert. See the loupe guide for why that filtering step is necessary.
6. Automate with the JSON endpoint
Every diamond page has a JSON equivalent at the same path with /json appended:
# Machine-readable output for any diamond
curl "https://louper.dev/diamond/0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE/json?network=mainnet"
# Shape of the response:
# {
# "chain": "mainnet",
# "diamond": {
# "name": "LiFiDiamond",
# "address": "0x1231...",
# "facets": [ { "name": "...", "address": "0x...", "abi": [ ... ] } ]
# },
# "diamondAbi": [ ... ] // every facet ABI, combined
# } This is the building block for monitoring. Snapshot a diamond's selector table, then diff it after an upgrade to see exactly what changed on chain rather than what a deploy script claimed:
# Snapshot the selector set today...
curl -s "https://louper.dev/diamond/$D/json?network=mainnet" \
| jq -r '.diamond.facets[] | .address as $a | .abi[] | select(.type=="function") | "\($a) \(.name)"' \
| sort > before.txt
# ...and after an upgrade, then diff.
diff before.txt after.txt Wire that into CI or a scheduled job and you have upgrade detection for any diamond you depend on, which is item 10 on the security checklist.
7. Use the CLI for local work
The same inspection is available in a terminal:
npm install -g @mark3labs/louper-cli@latest
louper -a 0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE -n mainnet Troubleshooting
"Unable to fetch diamond details"
Either the address is not a diamond, the network is wrong, or the contract does not implement facets(). Verify with a direct call before assuming Louper is at fault.
Facet names are missing
The facet source is not verified on that network's explorer. Louper falls back to selector lookups, but names cannot be recovered from bytecode alone.
The page is slow on very large diamonds
A diamond with dozens of facets requires a verified-source lookup per facet on a cache miss. Results are cached, so a second load is substantially faster.
The data looks stale after an upgrade
Contract metadata is cached. The facet list itself is read live from chain, so a reload will show structural changes; names for a brand-new facet may lag until its source is verified and picked up.