- The first cross-chain agent reputation protocol for the Polkadot ecosystem.
- ZK-proof-gated attestations with XCM cross-chain verification
AAS (Agent Attestation Service) provides verifiable, cross-chain reputation for AI agents on Polkadot. Agents earn cryptographic credentials by proving their performance through zero-knowledge proofs. Other parachains can query these credentials via XCM to verify an agent's trustworthiness before granting access to high-value tasks or resources.
- Two-tier reputation system: STANDARD (70% success, 10+ tasks) and VERIFIED (95% success, 100+ tasks)
- Zero-knowledge proof gates: Attestations require valid UltraHonk proofs (Noir circuits)
- Cross-chain queries: Parachains verify agents via XCM messages
- Polkadot-native: Uses XCM for inter-parachain communication
- On-chain performance oracle: Transparent task metrics and tier eligibility
- Time-based expiry: VERIFIED tier expires after 90 days (STANDARD never expires)
Polkadot Hub (Chain ID: 420420417)
┌──────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────────┐ ┌──────────────┐ │
│ │PerformanceOracle │ ◄─── updatePerformance │ AI Agent │ │
│ │ (task metrics) │ │ (wallet) │ │
│ └────────┬─────────┘ └──────┬───────┘ │
│ │ checkTierEligibility │ │
│ ▼ │ │
│ ┌──────────────────────────┐ │ │
│ │PolkadotAttestationRegistry│ ◄─── ZK proof ──────┘ │
│ │ - Agent registry │ (UltraHonk) │
│ │ - STANDARD / VERIFIED │ │
│ │ - Attestation storage │ │
│ └──────────┬───────────────┘ │
│ │ verifyAgent() │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ XCMAttestationBridge │ ◄─── handleXCMQuery() │
│ │ - Cross-chain queries │ │
│ │ - Activity tracking │ ───► XCMResponseSent event │
│ │ - XCM precompile ready │ (+ real XCM when enabled) │
│ └──────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
▲ XCM queries ▲ XCM queries
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ Moonbeam │ │ Astar │
│ (para 2004) │ │ (para 2006) │
└─────────────┘ └─────────────┘| Tier | Min Tasks | Min Success Rate | Expiry | Use Case |
|---|---|---|---|---|
| STANDARD | 10 | 70% | Never | General-purpose tasks, low-risk operations |
| VERIFIED | 100 | 95% | 90 days | High-value operations, sensitive data access |
Tier Checking: Uses gas-efficient integer cross-multiplication to avoid division:
successCount * 10000 >= taskCount * thresholdBpsAttestations require a Noir / Barretenberg UltraHonk proof whose public inputs
encode [taskThreshold, rateThresholdBps, dataCommitment]. The circuit is in
circuits/capability-threshold/. The verifier
contract is contracts/verifiers/HonkVerifier.sol.
| Contract | Address | Explorer |
|---|---|---|
PerformanceOracle |
0xDFfA5F28fb34fD544Bb1998C0B5D586f745303E0 |
Blockscout |
HonkVerifier |
0xa721e918450f063d5cc910C4FDF0fa59F5cCAbcc |
Blockscout |
PolkadotAttestationRegistry |
0xA7E98968A8D4CFccB32d0e94d0B54939796f9b3b |
Blockscout |
XCMAttestationBridge |
0xDD354018321bFd74205E235138e635cc6f47c985 |
Blockscout |
Full manifest: deployments/polkadot-hub.json.
| Contract | Purpose |
|---|---|
contracts/polkadot/PerformanceOracle.sol |
Stores per-agent task metrics; tier eligibility gate |
contracts/polkadot/PolkadotAttestationRegistry.sol |
Core registry: registration, ZK-gated attestation, verification, revocation |
contracts/polkadot/XCMAttestationBridge.sol |
Handles cross-chain queries; emits XCM events; optional precompile calls |
contracts/polkadot/interfaces/IXcm.sol |
Interface for the Polkadot Hub XCM precompile |
contracts/verifiers/HonkVerifier.sol |
Auto-generated UltraHonk verifier (78 KB, deployed via Remix) |
contracts/mocks/MockHonkVerifier.sol |
Test-only verifier (always returns true) |
- Node.js ≥ 18
- npm or yarn
- Hardhat
- (Optional)
nargo≥ 1.0.0-beta.6 andbb≥ 0.84.0 for ZK proof generation
git clone https://github.com/Lynette7/aas-xcm.git
cd aas-xcm
npm installnpx hardhat compile# All Polkadot tests (34 tests, ~1s)
npm run test:polkadot
# Individual test suites
npm run test:polkadot:oracle # PerformanceOracle tests
npm run test:polkadot:registry # PolkadotAttestationRegistry tests
npm run test:polkadot:bridge # XCMAttestationBridge tests
npm run test:polkadot:integration # End-to-end integration tests
# All tests
npm testCreate .env in project root:
DEPLOYER_PRIVATE_KEY=0x<your_private_key>
HONK_VERIFIER_ADDRESS=0x<address_from_remix> # See step 3Get PAS testnet tokens from the Paseo Faucet.
Why Remix? The HonkVerifier bytecode (~78 KB) exceeds Polkadot Hub's automated deployment limits on REVM.
Steps:
- Open Remix IDE
- Paste
contracts/verifiers/HonkVerifier.sol - Compiler settings:
- Version:
0.8.27 - Optimizer: Enabled, 200 runs
- EVM Version:
paris
- Version:
- Connect MetaMask to Polkadot Hub Testnet:
- Network Name:
Polkadot Hub Testnet - RPC URL:
https://eth-rpc-testnet.polkadot.io/ - Chain ID:
420420417 - Currency:
PAS - Explorer:
https://blockscout-testnet.polkadot.io/
- Network Name:
- Deploy contract in Remix
- Copy deployed address to
.envasHONK_VERIFIER_ADDRESS
# Deploy all contracts at once
npm run deploy:polkadot:all
# Or deploy individually
npm run deploy:polkadot:oracle # PerformanceOracle
npm run deploy:polkadot:registry # PolkadotAttestationRegistry
npm run deploy:polkadot:bridge # XCMAttestationBridgeDeployed addresses are saved to deployments/polkadot-hub.json.
# (Optional) Generate a real ZK proof
npm run proof:generate
# Seed 3 demo agents (VERIFIED, STANDARD, INELIGIBLE)
npm run demo:seed
# Run cross-chain query demo (4 scenarios)
npm run demo:xcmNote on proof generation: If nargo and bb aren't installed, the seed script automatically uses MockHonkVerifier for demo data and restores the real verifier afterward.
// Agent registers with their wallet address
bytes32 agentId = registry.registerAgent(agentWallet);
// agentId = keccak256(abi.encodePacked(walletAddress, block.chainid))// Authorized reporter updates agent metrics
oracle.updatePerformance(
agentId,
taskCount: 120,
successCount: 115, // 95.8% success rate
totalValue: 0,
ipfsArchiveCID: "bafybei..."
);
// Check tier eligibility
bool eligible = oracle.checkTierEligibility(agentId, TIER_VERIFIED);
// Returns true if: taskCount >= 100 AND successRate >= 95%// Agent generates ZK proof off-chain via Noir circuit
// Public inputs: [taskThreshold, rateThresholdBps, dataCommitment]
registry.createAttestation(
agentId,
tier: VERIFIED,
zkProof: proof, // UltraHonk proof bytes
publicInputs: inputs, // [100, 9500, commitmentHash]
parachainId: 2004, // Moonbeam
performanceCID: "bafybei..."
);
// Emits: AttestationCreated(attestationUID, agentId, tier, parachainId, expiresAt)// Parachain calls bridge to verify agent
bridge.handleXCMQuery(
sourceParachainId: 2004, // Moonbeam
agentId: agentId,
minTier: VERIFIED
);
// Emits two events:
// - XCMQueryReceived(queryId, sourceParachainId, agentId, minTier)
// - XCMResponseSent(queryId, sourceParachainId, agentId, verified, agentTier)The bridge operates in event-simulation mode (xcmEnabled = false) for now.
How it works:
Every handleXCMQuery call emits two on-chain events:
event XCMQueryReceived(
bytes32 indexed queryId,
uint32 indexed sourceParachainId,
bytes32 indexed agentId,
uint8 minTier
);
event XCMResponseSent(
bytes32 indexed queryId,
uint32 indexed sourceParachainId,
bytes32 indexed agentId,
bool verified,
uint8 agentTier
);Any off-chain relayer, indexer, or parachain can subscribe to these events and act on the response.
Real XCM has not been enabled yet because calling setXCMEnabled(true) would invoke the XCM precompile at 0x00000000000000000000000000000000000a0000. However, three requirements must be in place before that path is trustworthy:
| Requirement | Current Status | What's Needed |
|---|---|---|
| SCALE-encoded VersionedXcm payload | Uses abi.encode |
Replace with SCALE encoding (e.g., via @polkadot/api-codec or Solidity SCALE library) |
| Correct Multilocation encoding | Raw uint32 parachain ID |
SCALE compact encoding: X1::Parachain(id) → [0x00, compact(id)] |
| Receiver contracts on target parachains | Not yet deployed | Deploy contracts on parachains to decode and act on Transact payload |
Calling send() with the current encoding would either revert inside the
precompile or be silently dropped (try {} catch {} swallows failures).
To enable real cross-chain sends, the implementation needs:
- Encode the response as a
VersionedXcm::V3(Xcm([Transact { ... }]))message using SCALE encoding (e.g. via@polkadot/api-codecin a relayer, or a Solidity SCALE library). - Encode the Multilocation interior as SCALE compact:
X1::Parachain(id)→[0x00, compact(id)]. - Deploy a receiving contract on each target parachain that decodes
(bytes32 queryId, bool verified, uint8 agentTier)from the Transact calldata. - Fund the bridge's sovereign account on each parachain for XCM execution fees.
// When all the above are in place, a single owner call activates real XCM:
bridge.setXCMEnabled(true);- PerformanceOracle: Only authorized reporters can update performance data
- PolkadotAttestationRegistry: Anyone can create attestations (ZK proof is the gate)
- Revocation: Only agent wallet owner or contract owner can revoke
- On-chain verification via
HonkVerifier.verify(proof, publicInputs) - Public inputs encode:
[taskThreshold, rateThresholdBps, dataCommitment] - Proof hash stored on-chain (not full proof bytes)
- VERIFIED attestations expire after 90 days
- STANDARD attestations never expire
- Expiry checked in
verifyAgent()andgetValidAttestations()
- MockHonkVerifier in tests: Unit tests use a mock verifier that always returns
true. Integration tests should use realHonkVerifier. - No on-chain proof of performance: Performance data is reported by trusted oracles. Future versions could use TEEs or multi-oracle consensus.
- XCM event-based for now: Real XCM sends require SCALE encoding and receiver contracts.