ASP Compliance
Association Set Provider architecture
Architecture Exploration
The ASP compliance architecture is in active exploration. We are designing a system where compliance flows through the entire note lifecycle - ensuring the bona fide rule that a compliant note today was always handled by compliant parties. This includes exploring note-centric ASP models where notes carry their own compliance requirements. The current implementation is one of several approaches we are evaluating.
What is an ASP?
An Association Set Provider maintains a list of addresses meeting specific compliance criteria. When withdrawing, users prove their funds' origin is on an ASP's allowlist.
How It Works
- Monitor deposits: ASP watches Shield events, checks if depositor meets criteria
- Build Merkle tree: Approved addresses organized in a tree
- Publish root: Updated root posted on-chain
- User withdrawal: Proves origin is in the ASP tree
// ASP backend monitors deposits
pool.on('Shield', (commitment, origin) => {
if (meetsCriteria(origin)) {
allowlist.add(origin)
updateMerkleRoot()
}
})Origin Semantics
Origin is the address that originally deposited funds.
- Preserved through transfers
- Only changes via merge (merger becomes new origin)
- Used for compliance checking
Alice shields → origin = Alice
Alice → Bob transfer → origin still = Alice
Bob merges → origin = Bob (Bob vouches for funds)Withdrawal Paths
Ragequit
Original depositors can always withdraw their own funds, regardless of ASP status.
If origin is later sanctioned, they can still ragequit. But notes they sent to others become restricted - recipients must merge to become new origin or ragequit to the original origin.
Multiple ASPs
Different ASPs serve different use cases:
| ASP Type | Criteria | Use Case |
|---|---|---|
| OFAC Screen | Not sanctioned | General compliance |
| Institutional | Verified institutions | B2B |
| Exchange KYC | Passed KYC | Exchange integration |
Recipients can require specific ASPs:
// Exchange only accepts its own ASP
function receiveFromPool(bytes proof) external {
require(verifyASPRoot(proof, EXCHANGE_ASP_ID));
}Privacy Properties
ASPs know:
- List of all depositors (public Shield events)
- Which addresses meet their criteria
ASPs don't know:
- Who is withdrawing (ZK proof hides identity)
- Which origin is being used
- Transaction patterns
ASPs cannot censor specific withdrawals.