X402.AuthCapture.Engine (X402 v0.9.0)

Copy Markdown View Source

Explicit-consent auth-capture transaction execution and reconciliation.

Uses a dedicated EVM gas account, full pinned verification, a durable X402.AuthCapture.Journal, and strict escrow receipt checks. No caller supplied verification result is accepted. Transactions are signed through X402.Signer.sign_transaction/2, frozen before dispatch, and sent at most once. A timeout after dispatch is pending, not permission to rebroadcast.

execute/3 performs one transaction and one receipt check. Applications schedule reconcile/1; there is no polling process or automatic replacement. Confirmed results retain the signer scope until the caller durably records its payment effects and calls acknowledge/2. Reverted transactions follow the same acknowledgement rule. Abandoned preparations, expired frozen transactions, and missing receipts require application recovery.

A combined capture-and-void payload is rejected rather than silently ignoring its second leg. An orchestration layer must durably record the capture result before submitting the separately consented void.

Refunds require a request-specific :refund_authorize callback and existing token liquidity/allowances. This executor never approves or obtains refund funding itself. The callback receives canonical, signature-verified payment identity and terms; return :ok only for the exact application funding agreement. It must tolerate repeated evaluation.

Receipt confirmation uses the configured depth on the trusted RPC and rechecks the inclusion block hash. This is not an independent finality proof and cannot protect against reorgs deeper than the chosen depth.

Summary

Functions

Releases a finished scope after the caller durably mirrors its payment effects.

Verifies and executes a single lifecycle transaction, or reconciles its retry.

Builds an executor with explicit gas-price caps and mandatory storage.

Reconciles the active transaction without signing or sending anything.

Performs full, read-only verification with this executor's bound submission policy.

Verifies a pre-signed lifecycle consent without requiring its future escrow state.

Checks a current, unconsumed hold and remaining service deadline before handler admission.

Types

result()

@type result() :: %{
  id: binary(),
  status: :pending | :confirmed | :reverted,
  transaction: String.t() | nil,
  operation: atom(),
  payer: String.t(),
  amount: non_neg_integer(),
  payment_info_hash: String.t(),
  receipt: map() | nil
}

t()

@type t() :: %X402.AuthCapture.Engine{
  address: String.t(),
  chain_id: pos_integer(),
  journal: X402.AuthCapture.Journal.t(),
  network: String.t(),
  options: keyword(),
  rpc: X402.RPC.t(),
  signer: X402.Signer.t()
}

Functions

acknowledge(engine, id)

(since 0.9.0)
@spec acknowledge(t(), binary()) :: {:ok, result()} | {:error, term()}

Releases a finished scope after the caller durably mirrors its payment effects.

execute(engine, envelope, requirements)

(since 0.9.0)
@spec execute(t(), map(), map()) :: {:ok, result()} | {:error, term()}

Verifies and executes a single lifecycle transaction, or reconciles its retry.

Exact retries retain their request identity even after authorization expiry. A pending result never indicates that paid content may be released.

new(opts)

(since 0.9.0)
@spec new(keyword()) :: {:ok, t()} | {:error, term()}

Builds an executor with explicit gas-price caps and mandatory storage.

:clock returns Unix seconds. The default uses the system clock.

  • :rpc - Required.

  • :signer - Required.

  • :network (String.t/0) - Required.

  • :store - Required.

  • :max_fee_per_gas (pos_integer/0) - Required.

  • :max_priority_fee_per_gas (non_neg_integer/0) - Required.

  • :gas_limit (pos_integer/0) - The default value is 1000000.

  • :confirmations (pos_integer/0) - The default value is 2.

  • :history_limit (pos_integer/0) - The default value is 10000.

  • :clock (function of arity 0) - Required.

  • :eip6492_allowed_factories (list of String.t/0) - The default value is [].

  • :refund_authorize (function of arity 3)

reconcile(engine)

(since 0.9.0)
@spec reconcile(t()) :: {:ok, result() | nil} | {:error, term()}

Reconciles the active transaction without signing or sending anything.

An idle journal performs no RPC. Prepared but undispatched work remains pending; this conservative recovery path never assumes an interrupted caller relinquished permission to continue.

verify(engine, envelope, requirements)

(since 0.9.0)
@spec verify(t(), map(), map()) ::
  {:ok, X402.Verify.AuthCaptureEVM.verification()} | {:error, term()}

Performs full, read-only verification with this executor's bound submission policy.

verify_consent(engine, envelope, requirements)

(since 0.9.0)
@spec verify_consent(t(), map(), map()) ::
  {:ok, X402.Verify.AuthCaptureEVM.verification()} | {:error, term()}

Verifies a pre-signed lifecycle consent without requiring its future escrow state.

This establishes signature-level authorization only. Execution always repeats full verification. Used to validate the retained void before funding a hold.

verify_hold(engine, void, requirements, maximum)

(since 0.9.0)
@spec verify_hold(t(), map(), map(), pos_integer()) :: :ok | {:error, term()}

Checks a current, unconsumed hold and remaining service deadline before handler admission.