Skip to content

feat: Add OpenCryptoPay (OCP) payment standard support#14

Open
TaprootFreak wants to merge 1 commit into
tetherto:mainfrom
DFXswiss:feat/opencryptopay-standard
Open

feat: Add OpenCryptoPay (OCP) payment standard support#14
TaprootFreak wants to merge 1 commit into
tetherto:mainfrom
DFXswiss:feat/opencryptopay-standard

Conversation

@TaprootFreak
Copy link
Copy Markdown

OpenCryptoPay for WDK

OpenCryptoPay (OCP) is a permissionless, open payment standard that enables crypto payments in physical stores, web shops, and invoice payments. It extends LNURL with multi-chain, multi-asset support — allowing users to pay with USDT, BTC, XAUT across Ethereum, Polygon, Arbitrum, Bitcoin, Lightning and more, all from a single static QR code.

Why this matters for Tether

OCP is already in production. Major players have adopted the standard:

USDT is the most-used asset in OCP payments. Every OCP transaction with USDT strengthens Tether's core value proposition. Without this integration, the Tether Wallet is one of the few major wallets that cannot participate in OCP payments — even though USDT is the primary asset being used.

With this PR, a Tether Wallet user can walk into a SPAR store, scan the QR code, and pay with USDT. Without it, they can't.


Technical Overview

How OCP works

Every cash register has a static QR code. The QR contains an LNURL-encoded API URL. When scanned:

  1. Detect — Wallet decodes the LNURL (bech32) to get the API endpoint
  2. Fetch payment details — GET request returns recipient info, available payment methods/assets with amounts, and a time-limited quote
  3. User selects — Unlike traditional QR codes (one chain, one address), OCP returns an array of supported chains and assets. The user picks their preferred method (e.g., USDT on Polygon)
  4. Get transaction details — Wallet fetches the specific payment URI for the selected method
  5. Send & confirm — Wallet sends the transaction via WDK and submits the tx hash to the OCP API

What this PR adds

A new ocp service module and useOcp() React hook, alongside the existing wallet service:

src/
├── services/
│   ├── wdk-service/          # Existing — UNTOUCHED
│   └── ocp/                  # NEW — OpenCryptoPay
│       ├── index.ts          # OcpService (detect, fetch, submit)
│       ├── types.ts          # OCP type definitions
│       ├── lnurl-decode.ts   # Bech32 LNURL decoding (LUD-01)
│       └── uri-parser.ts     # QR/LNURL detection
├── contexts/
│   ├── wallet-context.tsx    # Existing — UNTOUCHED
│   └── ocp-context.tsx       # NEW — useOcp() hook + OcpProvider

Usage

import { WalletProvider, OcpProvider, useOcp } from '@tetherto/wdk-react-native-provider';

// Wrap app with both providers
<WalletProvider config={...}>
  <OcpProvider>
    {children}
  </OcpProvider>
</WalletProvider>

// In QR scanner callback
const { detect, fetchPaymentDetails, pay, paymentDetails, status } = useOcp();

const detection = detect(qrData);
if (detection) {
  // OCP payment detected — fetch details
  const details = await fetchPaymentDetails(detection.apiUrl);
  
  // details.transferAmounts contains available methods/assets
  // Show selection UI to user, then:
  await pay('Ethereum', 'USDT');
}

Why this is safe to merge

Concern Answer
Does it modify existing code? No. Zero changes to wdk-service/, wallet-context.tsx, worklets, or secret manager
New dependencies? @scure/base added as peer dep — already transitively available via bip39@scure/bip39
Bundle size impact ~636 lines of TypeScript. No native code, no worklet changes
Risk if something breaks? Delete src/services/ocp/ and src/contexts/ocp-context.tsx — everything reverts
Code style Follows existing patterns: singleton service, useReducer context, import type, same error handling
LNURL compliance LUD-01: bech32 decode, https/onion validation, HTTP status codes ignored per spec

Spec compliance details

  • LNURL bech32 decoding with @scure/base (same lib tree as bip39)
  • HTTPS and .onion URL validation per LUD-01
  • HTTP status codes ignored, response body always parsed as JSON per LUD-01
  • LNURL error responses ({ status: "ERROR", reason: "..." }) properly handled
  • OCP standard verified via standard: "OpenCryptoPay" field in response
  • TX submission URL correctly constructed using quote.payment as path ID
  • Quote expiration checked client-side before payment

Supported payment paths

OCP Method WDK Network Asset Support
Bitcoin bitcoin (SegWit) BTC
Ethereum ethereum USDT, XAUT
Arbitrum arbitrum USDT, XAUT
Polygon polygon USDT, XAUT
Lightning lightning BTC
Solana solana
Tron tron

As WDK adds support for more assets and chains, OCP coverage expands automatically through the mapping layer.


Links

Add OCP integration as a new service module alongside the existing
WDK wallet service. Enables wallets to process multi-chain payments
from static QR codes following the OpenCryptoPay standard.

New files:
- src/services/ocp/ — OCP service (detect, payment details, tx submit)
- src/contexts/ocp-context.tsx — useOcp() hook and OcpProvider

Flow: QR scan → LNURL decode → fetch payment details → user selects
method/asset → WDK sends transaction → submit tx hash to OCP API.

Supports Bitcoin, Ethereum, Arbitrum, Polygon, Lightning, Solana, Tron
with BTC, USDT, XAUT assets. LUD-01 compliant LNURL handling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant