DocssecurityCustody Verification

Custody Verification

How to verify your transaction history and prove that every action was properly authorized.

6 min read

Custody Verification

Every transaction signed through Kairo creates a verifiable record. This guide shows you how to verify your custody trail—proving that every action was properly authorized according to your policy.

What Is the Custody Trail?

Your custody trail is a chain of records stored on Sui blockchain. Each record (called a CustodyEvent) contains:

  • What happened — Transaction details, destination, amount
  • When it happened — Timestamp from the blockchain
  • What authorized it — Reference to the PolicyReceipt
  • Proof of integrity — Cryptographic hash linking to previous events

These records are immutable—once created, they can't be changed or deleted.

Why Verification Matters

Verification serves several purposes:

Personal Security

Confirm that:

  • No unauthorized transactions occurred
  • Every action was policy-approved
  • Your wallet history is complete

Compliance

Provide auditors with:

  • Verifiable proof of transaction authorization
  • Complete activity history
  • Cryptographic guarantees of integrity

Dispute Resolution

If questioned about a transaction:

  • Prove when it was authorized
  • Show which policy version approved it
  • Demonstrate the full decision chain

Understanding Custody Events

Each custody event captures:

CustodyEvent
├── chain_id: Reference to your custody chain
├── seq: Sequence number (0, 1, 2, ...)
├── kind: Type of event (transfer, approval, etc.)
├── recorded_at_ms: When recorded on Sui
│
├── prev_hash: Hash of previous event (32 bytes)
├── event_hash: Hash of this event (32 bytes)
│
├── src_namespace: Source chain (1=EVM, 2=BTC, 3=SOL)
├── src_chain_id: Network ID
├── src_tx_hash: Transaction hash on source chain
├── to_addr: Destination address
│
├── policy_object_id: Which policy authorized
├── policy_version: Policy version at time of signing
├── intent_hash: Hash of the unsigned transaction
├── receipt_object_id: The receipt that authorized signing
│
└── payload: Additional application data

How to Verify a Single Event

Step 1: Fetch the Event

Using Kairo's explorer or directly from Sui:

  1. Go to the Kairo Explorer
  2. Enter your wallet address
  3. Find the event you want to verify
  4. Click to view full details

Or via Sui directly:

https://explorer.sui.io/object/[event_object_id]

Step 2: Verify the Hash

The event_hash is computed from all other fields. To verify:

  1. Collect all event fields
  2. Encode them using BCS (Binary Canonical Serialization)
  3. Compute keccak256 hash
  4. Compare to stored event_hash

If they match, the event hasn't been tampered with.

Step 3: Verify Chain Linkage

Check that prev_hash matches the previous event:

  1. Fetch event with seq - 1
  2. Check its event_hash
  3. Should match this event's prev_hash

For the first event (seq = 0), prev_hash should be all zeros.

Step 4: Cross-Reference with Source Chain

Verify the transaction actually occurred:

  1. Take src_tx_hash from the event
  2. Look it up on the source chain's explorer
  3. Confirm destination, amount, and other details match

Verifying Your Complete Trail

To verify your entire custody history:

Using Kairo Explorer

  1. Go to Explorer → Your Wallet
  2. Click Custody Trail
  3. Click Verify All
  4. Wait for verification to complete
  5. Green checkmarks indicate valid events

Manual Full Verification

For complete independence:

Start with seq = 0
├── Verify prev_hash = 0x0000...0000
├── Verify event_hash computation
│
For each subsequent event:
├── Verify prev_hash = previous event_hash
├── Verify event_hash computation
├── Verify receipt_object_id was valid
└── Continue until latest event

Finally:
└── Verify chain's head_hash = last event_hash

Verifying Policy Authorization

Each event references the receipt that authorized it:

Check the Receipt

  1. Note the receipt_object_id from the event
  2. Since receipts are consumed, you can't fetch them directly
  3. Instead, check the IntentRecord in the PolicyVault

Verify Intent Record

The PolicyVault stores IntentRecords proving authorization:

  1. Query the vault for the intent_hash
  2. The record shows:
    • Which receipt authorized it (receipt_id)
    • Which policy version was active (binding_version_id)
    • When it was recorded (recorded_at_ms)

This proves the transaction was properly authorized before signing.

Using the Kairo SDK

For programmatic verification:

import { fetchAndVerifyCustodyEvent } from "@kairo/sdk";

// Verify a single event
const result = await fetchAndVerifyCustodyEvent({
  suiRpcUrl: "https://fullnode.testnet.sui.io:443",
  custodyEventObjectId: "0x...",
});

if (result.ok) {
  console.log("Event verified successfully");
} else {
  console.error("Verification failed:", result.error);
}
// Verify a complete chain
import { verifyFullCustodyChain } from "@kairo/sdk";

const chainResult = await verifyFullCustodyChain({
  suiRpcUrl: "https://fullnode.testnet.sui.io:443",
  custodyChainObjectId: "0x...",
});

if (chainResult.valid) {
  console.log(`Verified ${chainResult.eventCount} events`);
} else {
  console.error("Chain verification failed at seq:", chainResult.failedAt);
}

Creating Audit Reports

For compliance purposes, you can generate verification reports:

From Kairo Explorer

  1. Navigate to your custody trail
  2. Select date range
  3. Click Export Verification Report
  4. Choose format (PDF, JSON)
  5. Download includes:
    • Event details
    • Verification proofs
    • Cross-references to source chains

Report Contents

A complete audit report includes:

| Section | Contents | |---------|----------| | Summary | Total events, date range, verification status | | Event List | Each event with full details | | Verification Proofs | Hash computations and chain links | | Policy History | Policy versions active during period | | Source References | Links to transactions on source chains |

What to Do If Verification Fails

If you encounter a verification failure:

Hash Mismatch

The computed hash doesn't match stored hash.

Possible causes:

  • Bug in verification code
  • Data corruption during fetch
  • (Extremely unlikely) Actual tampering

Steps:

  1. Retry the verification
  2. Try a different RPC endpoint
  3. Verify your SDK version is current
  4. Contact Kairo support if persistent

Chain Break

prev_hash doesn't match previous event's event_hash.

Possible causes:

  • Missing event in your query
  • Events created out of order (shouldn't happen)

Steps:

  1. Ensure you're fetching all events
  2. Check for gaps in sequence numbers
  3. Report to Kairo if genuine break detected

Receipt Not Found

Can't verify the authorizing receipt.

Explanation: Receipts are consumed after use—this is expected. Use IntentRecords instead:

  1. Query the PolicyVault for the intent
  2. The record proves authorization occurred
  3. This is the correct verification path

Verification Best Practices

Regular Verification

  • Verify your trail periodically (monthly for active wallets)
  • Set up automated verification for high-value wallets
  • Export and archive verification reports

Independent Verification

  • Don't rely solely on Kairo's tools
  • Use the SDK or manual verification for critical audits
  • Cross-reference with source chain explorers

Long-Term Archival

  • Keep copies of verification reports
  • Archive custody event data independently
  • Store proofs that can be verified without Kairo

Technical Details

Hash Algorithm

Events use keccak256 over BCS-encoded data:

hash = keccak256(bcs_encode(EventCanonical))

Canonical Encoding

The EventV2Canonical struct defines what's hashed:

EventV2Canonical {
    chain_id: object::ID
    seq: u64
    kind: u8
    recorded_at_ms: u64
    prev_hash: vector<u8>
    src_namespace: u8
    src_chain_id: u64
    src_tx_hash: vector<u8>
    to_addr: vector<u8>
    policy_object_id: object::ID
    policy_version: vector<u8>
    intent_hash: vector<u8>
    receipt_object_id: object::ID
    payload: vector<u8>
}

Order matters for BCS encoding—fields must be in this exact order.

Next Steps

© 2026 Kairo Guard. All rights reserved.