Skip to content

How Payments Work & Core Architecture

An overview of SoloPay's full payment pipeline and gasless architecture.

2.1 Full Payment Pipeline

Every SoloPay payment is processed in the following 5 steps.

[1] SoloPay Widget
    POST /payments → receives paymentId, contract addresses



[2] User Wallet (MetaMask)
    Generate EIP-712 signature (no transaction, no gas fees)



[3] SoloPay Relayer
    Receive signature → verify signature → submit on-chain TX



[4] Blockchain (PaymentGateway Contract)
    pay() executes → token transfer & event emitted



[5] SoloPay → Merchant Server
    Send PAID / INVALID Webhook event

When the payment is confirmed as PAID, the funds have been transferred directly to the merchant wallet. No additional finalize or cancel step is needed.

Step-by-Step

StepActorAction
1. Payment RequestSoloPay WidgetPOST /payments → get paymentId, contract addresses
2. SigningUser WalletEIP-712 sign only (no TX, no gas)
3. RelayerSoloPay ServerVerify signature → submit on-chain TX
4. ContractBlockchainpay() → token transferred to merchant
5. WebhookSoloPay ServerSends events to your Webhook URL (see rows below)
5a. PAIDSoloPay ServerPayment confirmed on-chain. Complete the order
5b. INVALIDSoloPay ServerOn-chain payment detected but validation failed

What happens next:

  • Success: You receive PAID → order complete (funds transferred to merchant wallet).
  • Refund (coming soon): After PAID, you can request a refund via POST /payments/refunds → status becomes REFUND_SUBMITTED → then REFUNDED when confirmed.

Details: Webhook Events · Refunds.

2.2 Gasless & Relayer System

Standard Payment vs Gasless Payment

Standard Payment (Direct Pay)           Gasless Payment (Gasless Pay)
────────────────────────────            ─────────────────────────────

  User                                    User
    │                                       │
    │ ① Sends transaction directly          │ ① Generates signature data only
    │   (gas: paid by user)                 │   (no transaction, no gas)
    ▼                                       ▼
PaymentGateway Contract              SoloPay Widget → SoloPay Relayer

                                             │ ② Verifies signature, submits TX
                                             │   (gas: paid by relayer)

                                    PaymentGateway Contract

The Relayer's Role

The relayer is a server operated by SoloPay. It acts as the core intermediary for gasless payments.

  1. Receive Signature: Receives the user's EIP-712 signature data from the SoloPay widget.
  2. Verify Signature: Validates that the EIP-712 signature is correctly formatted and matches the user's address.
  3. Cover Gas Fees: Pays gas from the relayer wallet and submits the transaction to PaymentGateway via the ERC2771Forwarder contract.
  4. Monitor Status: Tracks the on-chain status of the transaction (QUEUEDSUBMITTEDCONFIRMED/FAILED).

ERC-2771 Meta-Transactions

SoloPay uses OpenZeppelin's ERC2771Forwarder standard. This allows the relayer to submit transactions on behalf of the user while the contract can still correctly identify the original user (signer).

2.3 Gasless Behavior by Token Type (Permit Support)

The level of gasless support depends on whether the token supports Permit (EIP-2612).

A. Fully Gasless — Permit-Supported Tokens (e.g., USDC)

Tokens that support EIP-2612 Permit process everything — including the first payment — with a single signature, with no Approve transaction required.

All payments including the first:

  User

    │ ① EIP-2612 Permit signature (no gas)
    │ ② EIP-712 ForwardRequest signature (no gas)

  Relayer → Contract execution (gas: paid by relayer)

→ User gas cost: 0

The SoloPay payment widget automatically detects Permit support and handles it accordingly.

B. Partially Gasless — Non-Permit Tokens (Standard ERC-20)

Standard ERC-20 tokens (without Permit) require a one-time Approve via the allowance method.

First time only (user pays gas)

  User

    │ ① Send approve(gatewayAddress, max amount) transaction
    │   (gas: paid by user — one time only)

  Allowance registered on PaymentGateway contract

All subsequent payments (fully gasless)

  User

    │ ① EIP-712 ForwardRequest signature (no gas)

  Relayer → Contract execution (gas: paid by relayer)

→ No gas fees from the second payment onward

Infinite Approve Recommended

Approving the maximum value (BigInt(2**256 - 1)) in the first Approve allows hundreds of subsequent payments without additional Approves.

Permit Support Comparison

ItemPermit-Supported Tokens (USDC, etc.)Standard ERC-20
First payment gasNone ✅Required (once) ⚠️
Subsequent payment gasNone ✅None ✅
Implementation effortLowLow (one extra Approve)

2.4 Transaction Status Cycle

Payment Status

CREATED ──► PAID
PAID    ──► REFUND_SUBMITTED ──► REFUNDED (coming soon)
CREATED ──► INVALID
CREATED ──► EXPIRED
CREATED ──► FAILED
StatusDescription
CREATEDPayment created, awaiting on-chain transaction
PAIDPayment confirmed on-chain, funds transferred to merchant (terminal)
REFUND_SUBMITTEDRefund transaction submitted (coming soon)
REFUNDEDRefund completed (coming soon)
INVALIDOn-chain payment detected but validation failed
EXPIREDPayment expired
FAILEDTransaction failed

Relay Status (Gasless only)

QUEUED ──────▶ SUBMITTED ──────▶ CONFIRMED


                  FAILED
StatusDescription
QUEUEDRelayer received signature data, preparing TX
SUBMITTEDRelayer submitted TX to blockchain
CONFIRMEDTX included in block and confirmed
FAILEDTX failed (out of gas, contract revert, etc.)

Payment Status vs Relay Status

  • Payment Status reflects the on-chain state (e.g. PAID, INVALID, EXPIRED).
  • Relay Status reflects the relayer's TX submission process (QUEUED → SUBMITTED → CONFIRMED/FAILED).
  • When the payment TX is confirmed, payment status becomes PAID and funds are transferred directly to the merchant wallet.

Next Steps

Non-custodial Web3 payment infrastructure for ERC-20 checkout, sponsored gas, and wallet-to-wallet settlement.