Skip to main content
This guide walks through settling an invoice on-chain using ERC-3009 with a deterministic nonce derived from invoice metadata. The nonce links each payment to its invoice and prevents double payment.
Concept: For the invoice settlement model and comparison to traditional B2B invoicing, see Invoice settlement.

What you’ll build

A full invoice lifecycle: the buyer signs an ERC-3009 authorization off-chain, the vendor submits it on-chain, and reconciliation matches the resulting AuthorizationUsed event back to the invoice by deterministic nonce.

Demo

Overview

Buyer:
Vendor:

Configuration

Step 1: Generate a deterministic nonce

Both the buyer and the vendor can independently compute the same nonce from invoice metadata. No external registry is needed.

Step 2: Sign the authorization (buyer)

The buyer signs an ERC-3009 transferWithAuthorization using the deterministic nonce from Step 1.

Step 3: Submit the transaction

Two options depending on who submits.

Option A: Buyer submits

The buyer submits the transferWithAuthorization transaction directly and pays gas. Use this when the buyer controls when and how the payment is executed, for example when the buyer’s accounting system needs the tx hash tied to an internal approval flow.

Option B: Vendor submits

The buyer sends {authorization, signature} to the vendor through API, email, or any channel. The vendor (or a facilitator) submits the transaction on the buyer’s behalf, so the buyer does not need to manage gas. Use this when the vendor needs synchronous confirmation within the same request flow.

Step 4: Reconcile via on-chain events (vendor)

Regardless of who submitted the transaction, every invoice payment emits an AuthorizationUsed event carrying the deterministic nonce. The vendor listens for this event and matches it to a pending invoice by nonce. Because the nonce is derived from invoice metadata, matching is exact.
Matching by nonce identifies which invoice was paid, but the vendor should also verify the Transfer event in the same transaction to confirm that the correct amount was sent to the correct recipient. The code below includes this verification.

Handle failed payments

A submitted transferWithAuthorization can revert for several reasons. Detect and surface each one to the vendor or buyer so the invoice can be retried or closed. Catch reverts and classify them before retrying.
Never retry a failed submission without classifying the error. Blind retries on a reverted transferWithAuthorization can pass validation after the buyer tops up their balance, which may not match the buyer’s latest intent.

Invoice settlement concept

Understand the deterministic-nonce reconciliation model.

ERC-3009

Review the signed-authorization standard behind this flow.

Enable gas-free transactions

Combine with Gas Waiver to eliminate gas from the settlement path.
Last modified on April 23, 2026