# @zkp2p/indexer-schema 0.22.0 GraphQL domain schema and TypeScript types for the ZKP2P Envio indexer. Core identities: - Deposit.id = escrowAddress_depositId - Intent.id = chainId_intentHash - QuoteCandidate.id = MethodCurrency.id - DisputeProtectionIntent.id = chainId_intentHash - DepositWhitelistPolicy.id = chainId_policyAddress_escrowAddress_depositId_paymentMethodHash - DepositWhitelistedAddress.id = chainId_policyAddress_escrowAddress_depositId_taker - DepositAllowedGroup.id = chainId_policyAddress_escrowAddress_depositId_paymentMethodHash_groupId - DepositDisputeProtectionConfig.id = chainId_policyAddress_escrowAddress_depositId_paymentMethodHash - DisputeProtectionRiskWindow.id = chainId_policyAddress_paymentMethod - DisputeProtectionPolicyState.id = chainId_policyAddress - OrchestratorRegistrationState.id = chainId_registryAddress_orchestratorAddress - IntentLifecycleHookState.id = chainId_intentHash - PaymentIntentBinding.id = chainId_registryAddress_nullifier - StakeAccountState.id = chainId_vaultAddress_stakeOwner - StakeLock.id = chainId_vaultAddress_lockId - CurrencyLiquidity.id = chainId_currencyCode - DepositCurrencyLiquidity.id = depositId_currencyCode - TokenLiquidity.id = chainId_token - DepositTokenLiquidity.id = depositId - CurrencyPlatformLiquidity.id = chainId_currencyCode_paymentMethodHash - DepositCurrencyPlatformLiquidity.id = depositId_currencyCode_paymentMethodHash Liquidity aggregates: - CurrencyLiquidity, TokenLiquidity, and CurrencyPlatformLiquidity are chain-level rollups of token liquidity immediately available for new intents through active quote rows. - DepositCurrencyLiquidity, DepositTokenLiquidity, and DepositCurrencyPlatformLiquidity are deduplicated per-deposit contributions that maintain those rollups. - currencyCode and paymentMethodHash are fiat-currency and payment-method bytes32 hashes, not human-readable codes. - currencyCode, paymentMethodHash, and token are lowercase-normalized in entity ids and stored fields, so exact equality works with lowercase values. - depositId is Deposit.id (`lowercaseEscrowAddress_depositIdOnContract`); DepositTokenLiquidity.id is the bare depositId with no suffix. - Aggregates apply deltas against stored per-deposit contributions; computed negative values are logged and refused, so aggregates never go negative. - Amounts use the deposited token's native units; USDC has 6 decimals. Transaction attribution: - Deposit.attributionCodes and Deposit.attributionSource identify the client that created a seller deposit. - Attribution decoding retains at most five ordered codes from direct calldata or an address-matched ERC-4337/ERC-7579 execution payload. - Intent.attributionCodes is the ordered ERC-8021 code list decoded from signal transaction calldata. - Intent.attributionSource is the first code other than ZKP2P's Base builder code bc_nbn6qkni. - Missing or invalid suffixes produce [] and null; attribution does not affect lifecycle semantics. Intent guardian: - Version 0.21.0-rc.1 adds Deposit.intentGuardian and QuoteCandidate.intentGuardian. - Both fields are lowercase-normalized; legacy V2 deposits use the zero address sentinel. - QuoteCandidate.intentGuardian is indexed; compare with exact equality or _in using lowercase values. V3 generation: - OrchestratorV3 is the revived V2-compatible intent surface from contracts PR #247. - AllowMultipleIntentsUpdated and RelayerRegistryUpdated are active again. - IntentReferralFeeDistributed replaces the deleted generalized IntentFeeDistributed event. - DisputeProtectionPolicy replaces RiskManager with stake-backed disputes only. - RiskMode, paid intent extensions, deferred payout, exposure aggregates, and RiskManager state are removed. - DisputeProtectionIntent transitions: PENDING -> CANCELLED, or PENDING -> SETTLED -> RELEASED/DISPUTED. - QuoteCandidate and OrderbookEntry expose disputeProtectionOptedOut separately from disputeProtectionRequiresStake. Only explicit `enabled: false` on the active policy means opted out; missing config or `enabled: true` keeps the tuple on by default. Stake is required only when the tuple is not opted out and the active policy has a nonzero risk window for the payment method. - Whitelist enabled state and curated groups are deposit/payment-method scoped. Direct whitelisted addresses remain deposit-wide. - Staging and production bind only the environment's configured active DisputeProtectionPolicy and StakeVault. - DisputeProtectionIntent.disputedAtBlockNumber and disputedAtLogIndex are the exact DisputeResolved cursor and remain null before a dispute. - OrderbookEntry.intentGatingService is lowercase-normalized unlike its QuoteCandidate source; zero address is the non-null ungated sentinel. Compare with exact equality. - Active-policy DisputeProtectionEnabledUpdated and RiskWindowUpdated refresh both projection facts. - DisputeProtectionPolicyState stores the current pause flag and normalized authorized lifecycle hooks. - OrchestratorRegistrationState stores current registry membership and remains present with registered false after removal. - IntentLifecycleHookState stores the exact per-intent lifecycle hook snapshot. - EscrowIntentPeriodState remains a V2.2 Escrow projection. StakeVault: - StakeAccountState is authoritative for totalStake, lockedStake, and freeStake. - TakerStakeState.selectedStakeOwner is raw preference; selectionAuthorized and stakeOwner are effective against TakerStakeAuthorization. Revocation falls back to self without erasing the raw selection until the selection event clears it. - ClaimAccountState is immediately withdrawable non-stake value. - StakeLock is a generic opaque lock keyed by the emitted lockId. - StakeActivity is append-only history; do not derive current balances by summing it. 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 is 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 dispute 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. Payment binding: - PaymentIntentBinding is the canonical nullifier -> intentHash relation. - Intent.paymentId is proof observability, not the canonical join key. Deployment: - DisputeProtectionPolicy bindings are environment-specific even though staging and production share Base chain ID 8453; projection resolution uses only the active address for the selected environment. - Retired Policy and StakeVault deployments are not indexed after the hard cut. - Clean staging and production reindexes are required before consumers rely on the split projection and dispute cursor fields. Scalar conventions: - BigInt serializes as a string in GraphQL clients. - Amounts are token base units. - Conversion rates use 1e18 precision unless a field says otherwise. - Timestamps are Unix seconds. - Addresses and hashes are normalized lowercase in domain projections.