# @zkp2p/indexer-schema field reference

This reference documents the current domain schema exported by `@zkp2p/indexer-schema@0.22.0`. Raw event audit entities are part of the live merged schema and are not exported by this package.

## Conventions

- Amounts are exact token base-unit integers.
- Conversion rates use 1e18 fixed-point precision unless stated otherwise.
- GraphQL `BigInt` values serialize as strings.
- Domain addresses and hashes are lowercase.
- `Deposit.id` is `escrowAddress_depositId`.
- `Intent.id` and `DisputeProtectionIntent.id` are `chainId_intentHash`.

## Transaction attribution

All supported generations decode ERC-8021 attribution when a deposit is created or an intent is signaled. Direct transactions use the terminal calldata suffix. ERC-4337 transactions use the terminal suffix in the address-matched user operation's ERC-7579 execution payload.

| Field | Meaning |
|---|---|
| `attributionCodes` | Up to five ordered decoded codes, including ZKP2P's Base builder code when present. Empty when the suffix is missing, invalid, ambiguous, or unsupported. |
| `attributionSource` | First decoded code other than `bc_nbn6qkni`; null when none exists. This is the analytics client/referrer dimension. |

On `Deposit`, attribution identifies the client that created the seller's liquidity position. On `Intent`, it identifies the client that signaled the buyer's intent. Attribution is observational metadata and does not alter lifecycle, payment method, owner, amount, or settlement state.

## Quote projections

### `QuoteCandidate`

Read-optimized join of `Deposit`, `DepositPaymentMethod`, and `MethodCurrency`.

| Field | Meaning |
|---|---|
| `id` | Same tuple identity as the backing `MethodCurrency`. |
| `depositId` | Foreign key to `Deposit.id`. |
| `conversionRate` | Gross resolved conversion rate. |
| `takerConversionRate` | All-in taker-facing rate. |
| `availableTokenAmount` | Current immediately available liquidity. |
| `intentGuardian` | Lowercase guardian configured on the source deposit; legacy V2 deposits use the zero address sentinel. Indexed for exact `_eq` and `_in` filtering. |
| `whitelistEnabled` | Whether the V3 whitelist policy is enabled. |
| `allowedGroupIds` | Allowed V3 address-group identifiers. |
| `disputeProtectionOptedOut` | Whether the depositor explicitly opted this deposit/payment-method tuple out on the active policy. Missing config and `enabled: true` are not opted out. |
| `disputeProtectionRequiresStake` | Whether the active policy routes this non-opted-out tuple through stake-backed admission because the payment method has a nonzero risk window. |
| `isActive` | Payment method active, deposit accepting intents, and non-zero taker rate. |
| `updatedAt` | Latest projection refresh timestamp. |

### `OrderbookEntry`

Consumer-facing projection materialized from an active supported `QuoteCandidate`. `disputeProtectionOptedOut`, `disputeProtectionRequiresStake`, `whitelistEnabled`, and `allowedGroupIds` are copied without reinterpretation. `intentGatingService` is projected from `QuoteCandidate` and is non-null, with the zero address as the ungated sentinel; unlike its source, it is lowercase-normalized so consumers can compare addresses with exact equality.

## Liquidity aggregates

These projections report token amounts immediately available for new intents through active quote rows. Amounts use the deposited token's native units; USDC amounts therefore have 6 decimals. The `Deposit*` rows are deduplicated per-deposit contributions used to maintain the chain-level aggregates, which are updated by applying deltas against the stored contribution. `currencyCode` is the fiat currency bytes32 hash; `currencyCode`, `paymentMethodHash`, and `token` are lowercase-normalized in both entity IDs and stored fields, so consumers can use exact equality with lowercase values. A computed negative aggregate is refused and logged instead of written, so aggregates never go negative.

### `CurrencyLiquidity`

Current liquidity for one fiat currency across all active deposits on a chain.

| Field | Meaning |
|---|---|
| `id` | `chainId_currencyCode`. |
| `chainId` | Chain containing the active deposits. Indexed. |
| `currencyCode` | Fiat currency bytes32 hash selected by the active quotes. Indexed. |
| `availableTokenAmount` | Immediately available liquidity, in the deposited token's native units. |
| `updatedAt` | Latest aggregate refresh timestamp. |

### `DepositCurrencyLiquidity`

Deduplicated contribution from one deposit to `CurrencyLiquidity`. Multiple active payment methods for the same deposit/currency count once.

| Field | Meaning |
|---|---|
| `id` | `depositId_currencyCode`. |
| `chainId` | Chain containing the deposit. Indexed. |
| `depositId` | Foreign key to `Deposit.id`, formatted `escrowAddress_depositIdOnContract` with the escrow address lowercase-normalized. Indexed. |
| `currencyCode` | Fiat currency bytes32 hash for this contribution. Indexed. |
| `availableTokenAmount` | Deposit contribution, in the deposited token's native units. |
| `updatedAt` | Latest contribution refresh timestamp. |

### `TokenLiquidity`

Current liquidity for one deposited token across all active deposits on a chain.

| Field | Meaning |
|---|---|
| `id` | `chainId_token`. |
| `chainId` | Chain containing the active deposits. Indexed. |
| `token` | Deposited token address. Indexed. |
| `availableTokenAmount` | Immediately available liquidity, in the token's native units. |
| `updatedAt` | Latest aggregate refresh timestamp. |

### `DepositTokenLiquidity`

Deduplicated contribution from one deposit to `TokenLiquidity`. A deposit contributes once when it has at least one active quote.

| Field | Meaning |
|---|---|
| `id` | Bare `depositId` with no suffix; exactly `Deposit.id`. |
| `chainId` | Chain containing the deposit. Indexed. |
| `depositId` | Foreign key to `Deposit.id`, formatted `escrowAddress_depositIdOnContract` with the escrow address lowercase-normalized. Indexed. |
| `token` | Deposited token address. Indexed. |
| `availableTokenAmount` | Deposit contribution, in the token's native units. |
| `updatedAt` | Latest contribution refresh timestamp. |

### `CurrencyPlatformLiquidity`

Current liquidity for one fiat currency and payment-platform pair across all active deposits on a chain.

| Field | Meaning |
|---|---|
| `id` | `chainId_currencyCode_paymentMethodHash`. |
| `chainId` | Chain containing the active deposits. Indexed. |
| `currencyCode` | Fiat currency bytes32 hash selected by the active quotes. Indexed. |
| `paymentMethodHash` | Payment method identifying the platform. Indexed. |
| `availableTokenAmount` | Immediately available liquidity, in the deposited token's native units. |
| `updatedAt` | Latest aggregate refresh timestamp. |

### `DepositCurrencyPlatformLiquidity`

Deduplicated contribution from one deposit to `CurrencyPlatformLiquidity`.

| Field | Meaning |
|---|---|
| `id` | `depositId_currencyCode_paymentMethodHash`. |
| `chainId` | Chain containing the deposit. Indexed. |
| `depositId` | Foreign key to `Deposit.id`, formatted `escrowAddress_depositIdOnContract` with the escrow address lowercase-normalized. Indexed. |
| `currencyCode` | Fiat currency bytes32 hash for this contribution. Indexed. |
| `paymentMethodHash` | Payment method identifying the platform. Indexed. |
| `availableTokenAmount` | Deposit contribution, in the deposited token's native units. |
| `updatedAt` | Latest contribution refresh timestamp. |

## V3 dispute state

### `DisputeProtectionIntent`

Current dispute protection intent keyed by `chainId_intentHash`.

| Field | Meaning |
|---|---|
| `policyAddress` | DisputeProtectionPolicy that emitted the lifecycle. |
| `status` | `PENDING`, `CANCELLED`, `SETTLED`, `RELEASED`, or `DISPUTED`. |
| `stakeOwner` | Owner whose StakeVault collateral backs the intent. |
| `depositor` | Deposit owner and dispute compensation beneficiary. |
| `taker` | Intent taker. |
| `paymentMethod` | Payment-method hash used to select the risk window. |
| `amount` | Full intent amount locked as collateral at open; settlement resizes collateral to `releaseAmount`. |
| `riskWindow` | Window snapshotted at admission. |
| `releaseAmount` | Amount released from Escrow before fees and collateralized after settlement. |
| `releaseEligibleAt` | Earliest collateral-release time. Disputes remain valid until release executes. |
| `isManualRelease` | Whether the underlying settlement was manual. |
| `compensatedAmount` | Amount awarded by `DisputeResolved`. |
| `disputeId` | Consumed dispute identifier. |
| `disputedAtBlockNumber` | Block number of `DisputeResolved`; null before a dispute. |
| `disputedAtLogIndex` | Log index of `DisputeResolved`; null before a dispute. |
| lifecycle timestamps and hashes | Exact provenance for open, cancel, settle, release, and slash transitions. |

Transitions are `PENDING -> CANCELLED`, `PENDING -> SETTLED -> RELEASED`, and `PENDING -> SETTLED -> DISPUTED`.

### `DepositDisputeProtectionConfig`

Deposit/payment-method-scoped configuration keyed by
`chainId_policyAddress_escrowAddress_depositIdOnContract_paymentMethodHash`.

| Field | Meaning |
|---|---|
| `depositId` | Foreign key to `Deposit.id`. |
| `paymentMethodHash` | Payment method whose future intents use this default-on, per-tuple opt-out setting. |
| `enabled` | Raw event value: `false` records a depositor opt-out, `true` undoes it, and absence is the default (on for windowed methods). |
| `updatedAt` | Latest `DisputeProtectionEnabledUpdated` timestamp. |

Active-policy `DisputeProtectionEnabledUpdated` and `RiskWindowUpdated` events re-derive both dispute projection facts for each existing `QuoteCandidate` and `OrderbookEntry` payment-method row. Passive-policy events retain raw/config rows without fan-out. New rows resolve the same active-policy facts while being built. Retired policy and vault deployments are not bound.

### `DepositWhitelistPolicy`

Whitelist-group configuration keyed by
`chainId_policyAddress_escrowAddress_depositIdOnContract_paymentMethodHash`.

| Field | Meaning |
|---|---|
| `depositId` | Foreign key to `Deposit.id`. |
| `paymentMethodHash` | Payment method whose group gate is configured. |
| `enabled` | Whether the tuple enforces direct-address or curated-group membership. |
| `allowedGroupCount` | Count of `DepositAllowedGroup` rows for this tuple. |
| `whitelistedAddressCount` | Deposit-wide direct-address count repeated on each method policy. |

### `DepositWhitelistedAddress`

Deposit-wide direct taker admission keyed by
`chainId_policyAddress_escrowAddress_depositIdOnContract_taker`. These rows intentionally have no
payment-method or `DepositWhitelistPolicy` foreign key.

### `DepositAllowedGroup`

One curated group admitted for a deposit/payment-method tuple. Its ID appends `groupId` to the
corresponding `DepositWhitelistPolicy.id`.

### `DisputeProtectionRiskWindow`

Future-admission minimum hold keyed by `chainId_policyAddress_paymentMethod`. Existing intents retain their snapshotted `DisputeProtectionIntent.riskWindow`.

### `DisputeProtectionPolicyState`

Current admission governance keyed by `chainId_policyAddress`. `admissionsPaused` is the latest
pause state. `authorizedLifecycleHooks` is a lowercase, sorted, duplicate-free set. Either governance
event can initialize the row while preserving the other field's safe default/current value.

### `OrchestratorRegistrationState`

Current registry membership keyed by `chainId_registryAddress_orchestratorAddress`. Add events set
`registered: true`; removal overwrites the same row with `registered: false`, including when removal
is the first indexed event.

### `IntentLifecycleHookState`

Per-intent OrchestratorV3 lifecycle-hook snapshot keyed by `chainId_intentHash`. A zero-address hook is stored as null.

## StakeVault state

### `TakerStakeState`

`selectedStakeOwner` preserves the raw emitted preference. `selectionAuthorized` reflects the
matching `TakerStakeAuthorization`, and `stakeOwner` is the effective owner: the selected owner only
while authorized, otherwise the taker. Authorization and revocation recompute effective state;
unrelated owner updates do not rewrite it. An absent selection means self-backed operation.

### `StakeAccountState`

Authoritative total, locked, and free stake for one owner. `freeStake = max(totalStake - lockedStake, 0)`.

### `ClaimAccountState`

Immediately withdrawable beneficiary claim balance, separate from stake principal.

### `TakerStakeAuthorization`

One stake owner's authorization for one taker. Multiple owners may authorize the same taker.

### `StakeLock`

Generic opaque lock lifecycle. Current status is `ACTIVE`, `UNLOCKED`, or `RESOLVED`.

| Field | Meaning |
|---|---|
| `id` | Immutable opaque pagination cursor, keyed by `chainId_vaultAddress_lockId`. |
| `chainId` | Exact chain filter. |
| `vaultAddress` | Exact StakeVault filter. |
| `stakeOwner` | Exact merchant stake-owner filter. |
| `status` | Optional lifecycle filter. |
| `maturesAt` | Current maturity surfaced to the UI. This value is mutable and is not the cursor. |

### `StakeActivity`

Append-only stake, authorization, selection, lock, resolution, and claim history. Current balances come from state entities, not activity sums.

| Field | Meaning |
|---|---|
| `id` | Immutable final tie-breaker in `chainId_blockNumber_logIndex` form. |
| `chainId` | Exact chain filter. |
| `vaultAddress` | Exact StakeVault filter. |
| `stakeOwner` | Optional owner side of merchant relevance. |
| `taker` | Optional taker side of merchant relevance. |
| `kind` | Optional activity-kind filter. |
| `blockNumber` | First ascending event cursor component. |
| `logIndex` | Second ascending event cursor component. |

### Merchant stake and dispute pagination

- `StakeLock` pages require exact `chainId`, `vaultAddress`, and `stakeOwner` filters plus optional status. Advance with `id > afterId` and `id` ascending. `maturesAt` is mutable and therefore not the cursor.
- `StakeActivity` pages require exact `chainId` and `vaultAddress`, merchant relevance `(stakeOwner == merchant OR taker == merchant)`, and optional kind. Order `(blockNumber, logIndex, id)` ascending. After cursor `(b, l, i)`, continue with `blockNumber > b OR (blockNumber = b AND logIndex > l) OR (blockNumber = b AND logIndex = l AND id > i)`. StakeActivity cursor stability comes from immutable append-only event positions.
- Finalized dispute pages require exact `chainId`, `status = DISPUTED`, and the active `policyAddress`, with no merchant-address predicate. Order `(disputedAtBlockNumber, disputedAtLogIndex, id)` ascending. After cursor `(b, l, i)`, continue with `disputedAtBlockNumber > b OR (disputedAtBlockNumber = b AND disputedAtLogIndex > l) OR (disputedAtBlockNumber = b AND disputedAtLogIndex = l AND id > i)`. The event cursor fields are non-null under the `DISPUTED` filter invariant even though the schema remains nullable before dispute. Finalized DISPUTED cursor stability comes from terminal rows and immutable dispute event positions.

These keysets guarantee strict forward progress; use no offset pagination. Page sizes `1..100` are validated by the clients SDK; the indexer schema does not enforce a page-size limit.

### `StakeVaultConfig`

Current controller plus pending delayed-controller handoff.

## Reindex requirement

The current Policy/registry entities, split dispute-projection facts, and dispute cursor fields require
a clean staging and production reindex. An older database cannot distinguish an absent field from an
explicit opt-out.

## Payment binding

### `PaymentIntentBinding`

Immutable binding keyed by `chainId_registryAddress_nullifier`.

| Field | Meaning |
|---|---|
| `intentHash` | Intent permanently bound to the nullifier. |
| `writer` | Authorized verifier that created the binding. |
| transaction fields | Exact transaction, log, block, and timestamp provenance. |

`Intent.paymentId` remains payment-proof observability and is not the canonical join key.

## Retained non-V3 domains

The package continues to export deposits, intents, payment methods, currencies, delegated-rate entities, maker/taker/manager statistics, daily analytics, whitelist-policy state, prices, profit snapshots, and activity/cursor entities. `EscrowIntentPeriodState` remains because the surviving V2.2 Escrow handlers write it.

## Removed in 0.19.0-rc.0

The RiskManager generation is removed without aliases: `RiskPosition`, `RiskPositionState`, `DisputeCoverage`, platform risk/dispute/extension configs, attestation config, RiskManager state, stake-owner and LP exposure aggregates/buckets, intent-extension activity/resolution, deferred settlement funding, risk hook settlement/cancellation state, and their RiskManager-owned enums.
