> ## Documentation Index
> Fetch the complete documentation index at: https://docs.giwa.tokscale.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# x402 Stage A: Credit Top-Up

> Learn why a plain token transfer can never mint credit, and what evidence the reconciler demands before it does.

Stage A tops up a project's prepaid credit balance with an exact, fixed amount, using the x402 `exact` scheme over ERC-3009.

x402 on GIWA is a port, not a builtin: GIWA does not officially support x402, and Coinbase's hosted facilitator does not support GIWA, so Tokscale runs a self-hosted, digest-pinned x402-rs facilitator (`ghcr.io/x402-rs/x402-facilitator@sha256:89ab5c03…`) and deployed the chain prerequisites itself.

## Direct ERC-3009 on tUSD: no proxy

The payment asset is tUSD ("Tokscale Test USD", ERC-20 with 6 decimals and an EIP-3009 subset), deployed on GIWA Sepolia at [`0x58d5608e89b5c1c3b96481a199756b1a292061a9`](https://sepolia-explorer.giwa.io/address/0x58d5608e89b5c1c3b96481a199756b1a292061a9) (byte-verified, domain and metadata validated).

Because the asset implements ERC-3009, the x402 `exact` flow needs no proxy contract. The client signs an ERC-3009 authorization for the `eip3009` asset, and the facilitator calls `transferWithAuthorization` directly on the token. The `ExactPermit2Proxy` exists only on the separate Permit2 branch and plays no role here (see [x402 Stage B](/gateway/x402-stage-b)).

## The flow

<Steps>
  <Step title="Return the 402 challenge">
    The top-up route responds `402` with `scheme=exact`, `network=eip155:91342`, `asset=tUSD`, `payTo=treasury`, and the exact requested amount.
  </Step>

  <Step title="Sign the ERC-3009 authorization">
    The payer signs one `transferWithAuthorization` payload covering token, payer, treasury, amount, validity window, and nonce.
  </Step>

  <Step title="Verify with the facilitator">
    The gateway posts to the facilitator's `/verify`. The facilitator exposes synchronous `/verify` and `/settle` only; every state transition is driven by Tokscale's own lifecycle and reconciler.
  </Step>

  <Step title="Persist the intent, then settle">
    Only after a successful verify does the gateway persist the intent and call `/settle`. A `/settle` timeout leaves the intent `dispatched`. It is never a silent failure and never an immediate retry that could obscure the on-chain outcome.
  </Step>

  <Step title="Credit from chain evidence only">
    Credit is written only by the reconciler, and only from canonical chain evidence.
  </Step>
</Steps>

## The durable intent lifecycle

Every top-up intent moves through a persisted state machine:

```text theme={null}
verified -> dispatched -> confirmed -> credited | abandoned
```

The rules that make it safe:

* Intents are unique on `(chain_id, asset, payer, authorization_nonce)`, with a stored hash of the full authorization payload. One authorization can fund one intent, once.
* The credit insert and the `confirmed -> credited` transition commit in one database transaction.
* An intent expires to `abandoned` only after `valid_before` plus the configured finality window with no matching on-chain authorization.
* Flashblocks `pending`-tag polling gives \~200ms "payment seen" feedback only. It is never a credit trigger: preconfirmation is not finality.

## The reconciler's exactly-once credit rule

The reconciler proves one authorization, not merely a transfer. For each `dispatched` intent it requires final-chain evidence that:

1. the expected token emitted `AuthorizationUsed(payer, nonce)` for the stored payer and nonce, and
2. the successful token call decodes to the stored `transferWithAuthorization` fields: token, payer, treasury, amount, validity window, nonce, and authorization commitment.

It then persists the transaction hash, block number, and block hash, and after the configured confirmation depth re-reads the block and receipt before crediting, so a reorg cannot turn a Flashblocks or early receipt observation into credit. `authorizationState` is a useful negative check but proves neither payee nor amount by itself.

Two consequences:

* **A plain transfer cannot mint credit.** A generic same-value tUSD transfer to the treasury never credits a pending intent, because it carries no `AuthorizationUsed` and no matching authorization calldata.
* **The reconciler sends no transactions.** It scans, matches, and writes credit rows. Settlement is the facilitator's job; crediting is the reconciler's.

## Proof on public GIWA Sepolia

On 2026-07-23 the pinned facilitator ran a full `exact` round trip against public GIWA Sepolia (`eip155:91342`): it advertised `exact` for the network, rejected a wrong chain (`unsupported_scheme`), rejected a wrong asset and a tampered signature, accepted one valid ERC-3009 authorization, and settled it on-chain. The settlement is recorded in the committed deployment manifest:

* Settlement transaction: [`0xad1a2f7b…`](https://sepolia-explorer.giwa.io/tx/0xad1a2f7b5aff4033e7779437ec487e8b51eb8170ba1c6c8cc971f6de37fcb9f8), 1.0 tUSD (1,000,000 base units), block 31,331,118
* Replay of the same authorization: rejected, reverting with the ERC-3009 authorization-used selector `0xd309466d`. No double settlement.

The on-chain evidence (bytecode hash, EIP-712 domain, and this authorization receipt) can be re-checked at any time:

```sh theme={null}
bun run contracts:giwa:sepolia:validate
```

Scope discipline: tUSD is a test-only asset and this run is evidence, not a payment service. Scheduled or production use still gates on a dedicated non-public RPC and approved key and treasury custody.

## Crash recovery, proven by killing the reconciler

The crash harness drives the worst case on the local localnet topology: an authorization settles on-chain, then the reconciler container is stopped and force-recreated before it credits. The harness then asserts, against both the database and the chain:

* pre-restart: the intent is `dispatch_unknown` with zero credit rows (settled but uncredited);
* post-restart: the new reconciler instance reconciles exactly one canonical settlement into exactly one credit (`scanned=1 claimed=1 confirmed=1`);
* a separate plain same-value tUSD transfer to the treasury (selector `0xa9059cbb`, zero `AuthorizationUsed` logs) mints no credit.

The crash harness runs under one target:

```sh theme={null}
bun run local:stage-a:crash:e2e
# pass marker: GIWA_LOCAL_STAGE_A_CRASH_E2E_OK ... authorization_used=1 credited=1
```

The `exact` mechanism is proven once on public GIWA Sepolia, with the evidence above. The full product top-up path (402 route, intent lifecycle, reconciler, crash recovery) is proven on the local localnet topology. Dedicated RPC, treasury custody, and production operation remain external gates.

## Next steps

* For the per-request scheme that settles actual usage instead of a fixed amount, see [x402 Stage B: Per-Request Settlement](/gateway/x402-stage-b).
* For the ported facilitator stack both stages run on, see [x402 Payments on GIWA](/gateway/x402-payments).
* For the tUSD deployment record and the settlement transaction, see [The Public Chain](/gateway/public-chain).
* For which of these gates are still open, see [Live Evidence](/overview/live-evidence).
