# Verify an ASP root on-chain

> Check whether an ASP-attested root has been published to the ASPRegistry. This controls which deposits are spendable.

## What this lets you do

Confirm that a specific [ASP](/protocol/asp/what-is-an-asp)-attested root is published to the on-chain [`ASPRegistry`](/protocol/contracts/asp-registry) contract. Roots are the ASP's batched attestation of "these deposit labels are approved", and the on-chain registry is what makes those attestations binding to the protocol's spending rules.

Spending a [note](/concepts/notes) requires proving membership of its deposit label in the *current latest* ASP root: [`PoolVault.transact`](/protocol/contracts/pool-vault) enforces `associationSetRoot == ASPRegistry.latestASPRoot()`, so a proof built against a stale root reverts with `PoolVault_InvalidASPRoot`. If you're skeptical of an ASP service's claims, verify their roots are actually on-chain before trusting them.

## Constraints & limits

-   **The root must be on-chain.** An ASP saying "this root is canonical" off-chain doesn't bind anything. Only roots that have been published to `ASPRegistry` by a holder of [`POSTMAN_ROLE`](/protocol/contracts/access-control) are valid.
-   **Roots are append-only history, but only the head is spendable.** The registry keeps an append-only list, yet `transact` only accepts the current `latestASPRoot()`. An older root is fine for auditing what was once published, but a spend proof must target the latest root. Walking the history tells you whether a root was *ever* published, not whether it is currently spendable.
-   **Doesn't tell you which labels are in the root.** The root is a Merkle root, so verifying inclusion of a specific label requires the merkle proof (which the ASP provides). This capability just checks "does this root exist on-chain at all."

## What it unlocks next

-   [Check a single note's attestation](/operations/deposit#check-a-deposits-attestation-status): once the root is on-chain, verify your specific deposit is in it.
-   Compliance-audit workflows: prove to a regulator that an ASP's claimed attestations are actually on-chain.

## How to use it

```ts
const aspRoot = await fetch(`${aspUrl}/association-set/root?chainId=${chainId}&entrypoint=${entrypointAddress}`).then(r => r.json());
const claimedRoot = aspRoot.root;

const onChainLatest = await publicClient.readContract({
    address: aspRegistryAddress,
    abi: ASP_REGISTRY_ABI,
    functionName: "latestASPRoot",
});

if (BigInt(claimedRoot) === onChainLatest) {
    console.log("Claimed root matches the latest on-chain root.");
} else {
    throw new Error("ASP's claimed root is not the latest; walk associationSets to verify.");
}
```

## Behind the scenes

Contract methods `ASPRegistry.latestASPRoot()` (returns `uint256`) for the head root, and `ASPRegistry.associationSets(uint256 _index)` (returns `AssociationSetData`) to walk history. There is no `isRootKnown` method.
SDK service `ASPRegistryInteractor.getLatestASPRoot()` and `getLatestAssociationSetData()`. No `isRootKnown` wrapper exists. Build the membership check yourself by comparing against the head or walking the array.
Publishing flow The ASP service generates a root from approved labels, then `POSTMAN_ROLE` calls `ASPRegistry.updateASPRoot(root, ipfsCID)`, and the root is appended to history
