SENTINEL

API for launchpads

Deference Launchpad requires a Sentinel attestation before a project can list. Any launchpad, wallet or explorer can do the same with one call, or by reading the registry directly.

GET /api/v1/attestations/:chainId/:address

Every audit of a deployed contract, newest first, read at a single block. CORS is open; responses are cached for 30 seconds.

curl https://sentinel.deference.dea.web.id/api/v1/attestations/84532/0xYourContract
{
  "chainId": 84532,
  "address": "0x…",
  "attested": true,
  "current": {
    "auditId": "3",
    "grade": "B",
    "score": 84,
    "tier": "deep",
    "counts": { "critical": 0, "high": 2, "medium": 2, "low": 2, "info": 1 },
    "needsHumanReview": false,
    "revoked": false,
    "timestamp": 1792409912,
    "sourceHash": "0x…",
    "reportHash": "0x…",
    "receiptsRoot": "0x…",
    "reportCid": "bafkrei…",
    "nftOwner": "0x…",
    "recordTx": "0x…",
    "recordBlock": "48331234",
    "reportUrl": "https://sentinel.deference.dea.web.id/r/bafkrei….json",
    "pageUrl": "https://sentinel.deference.dea.web.id/a/3"
  },
  "audits": [ … ],
  "readAtBlock": "48331301",
  "registry": { "chainId": 84532, "address": "0xF0aAc6f98F94Ed714387948f818b8eBeE959a751" },
  "badge": "https://sentinel.deference.dea.web.id/badge/84532/0x….svg"
}

current is the newest audit that is not revoked, or null. Use it, not audits[0].

A suggested listing rule: require attested, current.revoked == false, current.needsHumanReview == false, and a grade of C or better. Show the grade and link pageUrl.

Errors: 400 invalid_target for a malformed address, 503 chain_unavailable when the registry could not be read. Treat 503 as "unknown", never as "audited".

Reading the registry directly

AuditRegistry on Base Sepolia: 0xF0aAc6f98F94Ed714387948f818b8eBeE959a751.

function auditsOf(uint64 chainId, address target) external view returns (uint256[] memory);
function getAudit(uint256 auditId) external view returns (Audit memory);
function latestFor(uint64 chainId, address target) external view returns (uint256, Audit memory);
function auditsBySource(bytes32 sourceHash) external view returns (uint256[] memory);

latestFor returns the latest audit even if it is revoked and reverts NotAudited when there is none. To get the current one, walk auditsOf from the end and skip revoked records, as the API and the badge do.

Audits of pasted or uploaded source are stored with chainId = 0 and target = address(0); find them by sourceHash.

Badge

<a href="https://sentinel.deference.dea.web.id/verify?chain=84532&q=0xYourContract">
  <img src="https://sentinel.deference.dea.web.id/badge/84532/0xYourContract.svg" alt="Sentinel audit" width="200">
</a>

The badge is the attestation NFT's own SVG (AttestationNFT.badgeSvg) for the current audit. Without a valid audit it reads "Not audited by Sentinel".

Report files

/r/<cid>.json returns the exact bytes whose keccak256 is the onchain reportHash. /r/<cid>.md returns the Markdown rendering. Both are immutable and cacheable forever.