Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.x402r.org/llms.txt

Use this file to discover all available pages before exploring further.

Overview

PaymentIndexRecorderHook indexes payments by payer and receiver and stores the full PaymentInfo struct keyed by paymentInfoHash. Wire it into AUTHORIZE_POST_ACTION_HOOK on a HookCombinator (or directly when authorize is the only hook slot you use) so each new authorization registers itself for on-chain lookups.

When to use

  • You need on-chain payment lookups without a subgraph
  • Other contracts need to read the full PaymentInfo for a hash, or page through every payment by payer / receiver
  • You want a single chain-singleton index that aggregates across every operator routing through HookCombinator
Skip when: you’re using a subgraph for payment queries, since the subgraph can derive indexes from events without the on-chain gas cost.

State

mapping(bytes32 paymentInfoHash => AuthCaptureEscrow.PaymentInfo) private paymentInfoStore;
mapping(address payer    => mapping(uint256 index => bytes32 hash)) private payerPayments;
mapping(address payer    => uint256 count)                        public  payerPaymentCount;
mapping(address receiver => mapping(uint256 index => bytes32 hash)) private receiverPayments;
mapping(address receiver => uint256 count)                        public  receiverPaymentCount;

Methods

function run(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    uint256 /* amount */,
    address /* caller */,
    bytes calldata /* data */
) external {
    bytes32 hash = escrow.getHash(paymentInfo);
    paymentInfoStore[hash] = paymentInfo;
    payerPayments[paymentInfo.payer][payerPaymentCount[paymentInfo.payer]++] = hash;
    receiverPayments[paymentInfo.receiver][receiverPaymentCount[paymentInfo.receiver]++] = hash;
}

function getPaymentInfo(
    bytes32 paymentInfoHash
) external view returns (AuthCaptureEscrow.PaymentInfo memory);

function getPayerPayments(
    address payer,
    uint256 offset,
    uint256 count
) external view returns (AuthCaptureEscrow.PaymentInfo[] memory, uint256 total);

function getReceiverPayments(
    address receiver,
    uint256 offset,
    uint256 count
) external view returns (AuthCaptureEscrow.PaymentInfo[] memory, uint256 total);
amount, caller, and data are unused; they exist to satisfy IHook.run.

Querying

const info = await paymentIndex.read.getPaymentInfo([paymentInfoHash])

const [payerInfos, total] = await paymentIndex.read.getPayerPayments([
  payer,
  0n,
  10n,
])

Gas

Cost: ~175k gas per authorization (payer index + receiver index + full PaymentInfo SSTORE).

Next Steps

HookCombinator

Combine with other hooks in a single slot.

Hooks Overview

Compare recording strategies.