Reference
Verify an inscription
Rebuild a token's media from chain and check its fingerprint.
Each token stores a Keccak-256 digest for every file. You can rebuild the file from the chain and check that digest yourself. You don't need the Scrible app.
What you need#
- The token address.
- The public RPC:
https://rpc.mainnet.chain.robinhood.com - Foundry's
cast, or Node with ethers v6.
How the check works#
- Read the media info
Call
mediaInfo(i)on the token. You get the MIME type, the digest, the size, and the chunk addresses. - Read each chunk's code
Each chunk is a contract. Its code is a
0x00byte followed by the data. - Strip and join
Drop the first byte of each chunk. Join the chunks in order.
- Hash and compare
Take the Keccak-256 of the result. It must equal the digest. The length must equal the size.
With cast#
RPC=https://rpc.mainnet.chain.robinhood.com
TOKEN=0x39Fc9c8D24e38586f325fB8cFf7F9F1ae4635e59
# 1. File count and info for file 0
cast call $TOKEN "mediaCount()(uint256)" --rpc-url $RPC
cast call $TOKEN "mediaInfo(uint256)(string,bytes32,uint256,address[])" 0 --rpc-url $RPC
# 2. Join the chunks (drop the leading 00 of each)
DATA=0x
for CHUNK in 0xCHUNK_1 0xCHUNK_2; do
CODE=$(cast code $CHUNK --rpc-url $RPC)
DATA="$DATA${CODE:4}"
done
# 3. Compare with the digest from step 1
cast keccak $DATA
Replace 0xCHUNK_1 0xCHUNK_2 with the addresses from step 1, in order. Run the script in bash. For FIST, the result is 0xb877f648beceb5a0a95187602b8fcbb2e9215a6269f71537db7beaf664a44538.
With ethers#
import { Contract, JsonRpcProvider, concat, dataSlice, keccak256, getBytes } from "ethers";
import { writeFileSync } from "node:fs";
const provider = new JsonRpcProvider("https://rpc.mainnet.chain.robinhood.com", 4663);
const token = new Contract("0x39Fc9c8D24e38586f325fB8cFf7F9F1ae4635e59", [
"function mediaCount() view returns (uint256)",
"function mediaInfo(uint256) view returns (string mime, bytes32 digest, uint256 size, address[] chunks)",
], provider);
const count = Number(await token.mediaCount());
for (let i = 0; i < count; i++) {
const { mime, digest, size, chunks } = await token.mediaInfo(i);
const parts = [];
for (const chunk of chunks) parts.push(dataSlice(await provider.getCode(chunk), 1));
const data = concat(parts);
const ok = keccak256(data) === digest && getBytes(data).length === Number(size);
console.log(i, mime, ok ? "verified" : "MISMATCH");
writeFileSync(`media-${i}`, getBytes(data));
}
The script writes each file to disk. Open it with the matching file type.
The quick way#
readMedia(i) on the token returns the joined bytes in one call. It trusts the token's own logic, so use the chunk method above for an independent check.
Example#
FIST (0x39Fc…5e59) is the first Scrible inscription. It holds one JPEG of 45,325 bytes in 2 chunks.