Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Payment Relayer

dataprism-payment-relayer bridges fiat card payments to on-chain DPC tokens. After a user completes a Stripe payment on the Frontend, this service buys DPC from the Exchange with USDC and transfers it to the user's wallet.

Not to be confused with the Relayer: that service relays user data meta-transactions, while the payment relayer handles the fiat → DPC on-ramp.

Tech stack

Project structure

src/
├── relayer/
│   ├── runner.ts     # Entry point: bootstrap executor + notifier, start the poller
│   ├── poller.ts     # Polling loop: fetch, claim, execute, report
│   ├── executor.ts   # buyAndTransfer(): buy DPC on the Exchange, transfer to user
│   └── gas.ts        # ETH balance monitor (separate process)
├── api/client.ts     # HTTP client for the frontend's relayer endpoints
├── abi/              # ERC20, Exchange, DPCToken ABIs
├── config.ts         # Environment variable parsing
└── notification.ts   # Email + Telegram alerts

Payment flow

User pays via Stripe → Frontend records a pending payment

Payment relayer polls  GET  /api/relayer/pending

Claims the payment     POST /api/relayer/claim   (atomic, dedupes across instances)

Buys DPC on the Exchange with USDC (1% slippage), then transfers DPC to the user

Reports completion     POST /api/relayer/complete  { paymentIntentId, txHash }

buyAndTransfer() (executor.ts)

  1. Acquire DPC: check the relayer's DPC balance. If insufficient, verify gas is below MAX_FEE_GWEI, ensure (unlimited) USDC approval to the Exchange, then call Exchange.buyTokens(USDC_ADDRESS, usdcAmount, minOut) with 1% slippage tolerance and wait for 1 confirmation.
  2. Transfer DPC: call ERC20.transfer(toAddress, dpcAmount) on the DPC token and wait for 2 confirmations; return the transfer tx hash.

Both steps run inside a retry loop (MAX_RETRIES, RETRY_DELAY_MS). The buy step is idempotent: if the relayer already holds enough DPC from a prior failed attempt, it skips straight to the transfer. DPC has 18 decimals, USDC has 6; the USDC amount to spend is derived from the configured EXCHANGE_RATE (1 USDC → 1000 DPC by default).

Frontend endpoints consumed

The payment relayer is a client: it exposes no HTTP server. It calls three frontend endpoints, each with an x-relayer-secret: <RELAYER_SECRET> header:

EndpointPurpose
GET /api/relayer/pendingFetch pending payments awaiting processing.
POST /api/relayer/claimAtomically claim a payment ({ paymentIntentId }).
POST /api/relayer/completeReport success ({ paymentIntentId, txHash }).

Configuration

# Required
RELAYER_PRIVATE_KEY=""      # relayer wallet (needs MINTER_ROLE on DPC, holds USDC)
RELAYER_SECRET=""           # shared secret, must match the frontend
FRONTEND_URL="http://localhost:3000"
 
# Chain & RPC
CHAIN_ID="11155111"         # 11155111 = Sepolia, 1 = mainnet
RPC_URLS="https://rpc.sepolia.org"   # comma-separated, with fallback
 
# Contracts (Sepolia defaults)
DPC_TOKEN_ADDRESS="0x6d663c7c401a18208748dF6F909ffc0C68FA1B73"
USDC_ADDRESS="0xC6a054681bEBb1096BB03E3Fc433bD99BAe987d0"
EXCHANGE_ADDRESS="0x0Cc50006445C7E0e08Fb46Bf5d8b1bECf5275Ba1"
 
# Tuning
POLL_INTERVAL_MS="10000"
MAX_FEE_GWEI="100"
MAX_RETRIES="5"
RETRY_DELAY_MS="5000"
 
# Gas monitor
GAS_WARN_BALANCE_ETH="0.1"
GAS_POLL_INTERVAL_MS="180000"
 
# Notifications (optional)
SMTP_HOST="" SMTP_PORT="587" SMTP_USER="" SMTP_PASS="" SMTP_FROM="" SMTP_TO=""
TELEGRAM_BOT_TOKEN="" TELEGRAM_CHAT_ID=""

A .env.example template is provided.

Install, run, deploy

npm install      # Install dependencies
npm run build    # Compile to dist/
npm run dev      # Build + run runner.js
npm run deploy   # Build + start via PM2 (production)

PM2 (ecosystem.config.js) runs two processes: DataPrism Payment Relayer (runner.js) and DataPrism Gas Monitor (gas.js), each with their own logs under logs/.

Notes

  • The relayer wallet must have MINTER_ROLE on the DPC token and hold USDC (and ETH for gas).
  • Multiple RPCs are supported via viem's fallback() transport.
  • A failed payment stays unclaimed and can be retried by the same or another instance.
  • It grants the Exchange an unlimited USDC approval for efficiency, ensure the Exchange is trusted.
Copyright © 2026 DataPrism.