One tap to pay with crypto. No wallet app. No chain switching. No friction.
TapPay brings tap-to-pay simplicity to crypto payments. Merchants create orders with a tap, customers pay with any stablecoin on any chain — no wallet installation, no ETH for gas, no network switching. Just tap your phone and pay.
The problem: Crypto payments are broken for real-world use. Users need wallets, gas tokens, chain awareness — friction that kills adoption.
The solution: TapPay makes crypto payments feel like Apple Pay. One tap, done. The complexity of cross-chain operations, gas abstraction, and wallet management stays invisible.
Pay with anything: Buyers can pay with any token on any supported chain — ETH on Ethereum, BNB on BSC, etc. The Universal Account SDK automatically converts and routes everything to USDC on Arbitrum for the merchant. Users don't need to know what chain they're on.
Supported chains: Ethereum, BNB Chain (BSC), X Layer, Base, Arbitrum, Solana. (View official list →)
- Login — Sign in with email or Google (no wallet needed)
- Create Order — Enter amount in USDC, get a payment link
- Share — Display QR code, copy link, or write to NFC tag
- Get Paid — Funds arrive directly in your account on Arbitrum
- Tap or Scan — Tap NFC tag or open payment link
- Login — Sign in with email or Google (first time only)
- Pay — Confirm payment with any token on any supported chain (ETH on Ethereum, BNB on BSC, SOL on Solana, etc.)
- Done — Particle UA automatically converts and routes funds; merchant receives USDC on Arbitrum
The magic: Buyers don't need to hold USDC or know about Arbitrum. The Universal Account SDK handles cross-chain routing and token conversion behind the scenes.
Supported chains: Ethereum, BNB Chain (BSC), X Layer, Base, Arbitrum, Solana. (View official list →)
sequenceDiagram
participant Buyer
participant Magic as Magic Wallet
participant UA as Particle Universal Account
participant Contract as TapPay Contract (Arbitrum)
participant Merchant
Merchant->>Contract: createOrder(amount)
Contract-->>Merchant: orderId + payment link
Buyer->>Magic: Login (Email/Google)
Magic-->>Buyer: Embedded Wallet (EOA)
Buyer->>UA: createUniversalTransaction()
Note over UA: User holds ETH on Ethereum,<br/>BNB on BSC, SOL on Solana, etc.
Note over UA: SDK auto-detects balances
Note over UA: Auto-converts to USDC
Note over UA: Routes cross-chain to Arbitrum
Note over UA: Pays gas from stablecoin
UA->>Contract: approve + pay(orderId)
Contract-->>Merchant: USDC on Arbitrum
Contract-->>Buyer: Payment confirmed
| Layer | Technology | Purpose |
|---|---|---|
| Smart Contract | Solidity + OpenZeppelin | TapPay payment protocol on Arbitrum |
| Chain Abstraction | Particle Universal Accounts SDK | Cross-chain transactions, unified balance |
| Embedded Wallet | Magic SDK | Email/Google social login, EIP-7702 signing |
| Frontend | Next.js 13 + TypeScript + Tailwind CSS | Responsive web app |
| Blockchain | Arbitrum One | Low-cost, high-speed settlement layer |
TapPay uses Particle Network's Universal Accounts SDK in EIP-7702 mode — the recommended approach for chain abstraction.
EIP-7702 allows any existing EOA (Externally Owned Account) to be upgraded in-place to a smart account. No new address, no asset migration. The user's existing wallet becomes chain-abstracted instantly.
// Initialize Universal Account with EIP-7702 mode
const ua = new UniversalAccount({
projectId: process.env.NEXT_PUBLIC_PROJECT_ID!,
projectClientKey: process.env.NEXT_PUBLIC_CLIENT_KEY!,
projectAppUuid: process.env.NEXT_PUBLIC_APP_ID!,
smartAccountOptions: {
useEIP7702: true, // Enable EIP-7702 mode
name: 'UNIVERSAL',
version: UNIVERSAL_ACCOUNT_VERSION,
ownerAddress: userAddress,
},
tradeConfig: {
slippageBps: 100,
universalGas: true, // Pay gas from stablecoin
},
});// Create cross-chain transaction
const tx = await ua.createUniversalTransaction({
chainId: CHAIN_ID.ARBITRUM_MAINNET_ONE,
expectTokens: [
{ type: SUPPORTED_TOKEN_TYPE.USDC, amount: '10.00' }
],
transactions: [
{ to: USDC_ADDRESS, data: encodeApprove(spender, amount) },
{ to: TAPAY_ADDRESS, data: encodePay(orderId) },
],
});// Sign EIP-7702 authorization with Magic wallet
const authorization = await magic.wallet.sign7702Authorization({
contractAddress: uaContractAddress,
chainId: ARB_CHAIN_ID,
nonce: authNonce + 1,
});
// Send Type-4 transaction for delegation
await magic.wallet.send7702Transaction({
to: userAddress,
data: '0x',
authorizationList: [authorization],
});Why this matters:
- No new address — User's existing EOA becomes the Universal Account
- No asset migration — Funds stay where they are
- No wallet switching — Works with embedded wallets (Magic, Privy, Dynamic)
- Cross-chain magic — User pays with USDC on Base/BSC/Solana, merchant receives on Arbitrum
TapPay uses Magic Labs for frictionless onboarding — no wallet installation required.
- Email Login — Enter email, receive OTP, done
- Google Login — One-click OAuth, instant access
- Invisible Wallet — Magic creates and manages the wallet behind the scenes
// Initialize Magic with OAuth support
const magic = new Magic(process.env.NEXT_PUBLIC_MAGIC_API_KEY!, {
network: { chainId: 42161, rpcUrl: 'https://arb1.arbitrum.io/rpc' },
extensions: [new OAuthExtension()],
});
// Email login
const idToken = await magic.auth.loginWithEmailOTP({ email });
// Google OAuth
await magic.oauth2.loginWithRedirect({
provider: 'google',
redirectURI: window.location.origin + '/login',
});
// EIP-7702 signing (critical for Universal Accounts)
const auth = await magic.wallet.sign7702Authorization({
contractAddress, chainId, nonce
});Why Magic?
- Zero friction — Users never see a wallet address or seed phrase
- EIP-7702 native — Built-in support for
sign7702Authorization - Consumer-ready — Feels like a Web2 login, powers Web3 transactions
TapPay runs primarily on Arbitrum — the settlement layer where all payments finalize.
- Low cost — Transactions cost cents, not dollars
- Fast finality — Payments settle in ~2 seconds
- Ecosystem fit — Arbitrum's vision of invisible blockchain aligns with TapPay's UX goals
- EIP-7702 support — Full compatibility with Particle's chain abstraction
Arbitrum powers the experience behind the scenes, but the user never has to think about:
- ❌ Which chain they're on
- ❌ How much gas to set
- ❌ Bridge mechanics
- ❌ Wallet addresses
They just tap and pay. Arbitrum handles the rest.
TapPay uses Arbitrum as the backend settlement layer:
- Buyer perspective — Pay with any token on any supported chain (ETH on Ethereum, BNB on BSC, SOL on Solana, etc.)
- Merchant perspective — Receive USDC on Arbitrum, always
- Behind the scenes — Particle UA handles cross-chain routing and token conversion
Supported chains: Ethereum, BNB Chain (BSC), X Layer, Base, Arbitrum, Solana. (View official list →)
This is the power of chain abstraction: users see simplicity, Arbitrum provides the infrastructure.
The TapPay.sol contract is deployed on Arbitrum One:
Contract Address: 0x9c043b4044386b8ccdab46870cacb86552baa579
contract TapPay {
// Create order (merchant only)
function createOrder(uint256 amount) external returns (uint256 orderId);
// Pay order (buyer)
function pay(uint256 orderId) external;
// Cancel order (merchant only, within 5 min)
function cancelOrder(uint256 orderId) external;
// Order expires after 5 minutes
uint64 public constant ORDER_LIFESPAN = 5 minutes;
}- 5-minute expiration — Prevents stale orders, forces quick checkout
- USDC only — Stable value, no volatility risk
- Merchant cancellation — Allows merchants to cancel unpaid orders
- Event-driven — All state changes emit events for easy indexing
# Clone the repository
git clone https://github.com/yourusername/tappay.git
cd tappay/app
# Install dependencies
npm install
# Start development server
npm run devOpen http://localhost:3000 in your browser.
Create .env.local in the app/ directory:
# Particle Network (Required)
NEXT_PUBLIC_PROJECT_ID=your_particle_project_id
NEXT_PUBLIC_CLIENT_KEY=your_particle_client_key
NEXT_PUBLIC_APP_ID=your_particle_app_id
# Magic Labs (Required)
NEXT_PUBLIC_MAGIC_API_KEY=your_magic_api_key
# Arbitrum (Optional - defaults provided)
NEXT_PUBLIC_ARB_RPC_URL=https://arb1.arbitrum.io/rpc
NEXT_PUBLIC_ARB_USDC=0xaf88d065e77c8cC2239327C5EDb3A432268e5831
NEXT_PUBLIC_TAPAY_CONTRACT=0x9c043b4044386b8ccdab46870cacb86552baa579
# Etherscan (Optional - for contract verification)
ETHERSCAN_API_KEY=your_etherscan_api_key-
Particle Network
- Go to dashboard.particle.network
- Create a new project
- Copy Project ID, Client Key, and App UUID
-
Magic Labs
- Go to dashboard.magic.link
- Create a new app
- Copy the Publishable API Key
app/
├── contracts/
│ └── TapPay.sol # Smart contract
├── public/
│ └── ... # Static assets
├── src/
│ ├── components/
│ │ ├── landing/ # Landing page sections
│ │ ├── AccountPage.tsx # User account & balance
│ │ ├── HistoryPage.tsx # Transaction history
│ │ ├── LoginPage.tsx # Auth (email/Google)
│ │ ├── MerchantDashboard.tsx # Merchant order management
│ │ ├── PayPage.tsx # Payment checkout
│ │ └── WithdrawModal.tsx # Withdrawal flow
│ ├── hooks/
│ │ ├── useAuth.ts # Authentication logic
│ │ ├── MagicProvider.tsx # Magic SDK context
│ │ └── UniversalAccountProvider.tsx # UA SDK context
│ ├── pages/
│ │ ├── index.tsx # Landing page
│ │ ├── login.tsx # Login page
│ │ ├── merchant.tsx # Merchant dashboard
│ │ ├── pay.tsx # Payment page
│ │ ├── account.tsx # Account page
│ │ └── history.tsx # History page
│ └── utils/
│ └── contracts.ts # Contract interactions
├── package.json
└── README.md
TapPay's killer feature: physical tap-to-pay using NFC tags.
- Merchant creates an order
- Merchant writes payment URL to NFC tag (Android Chrome)
- Customer taps their phone on the tag
- Payment page opens automatically
- Customer confirms payment
- Done!
const handleWriteNfc = async () => {
const NDEFClass = window.NDEFWriter || window.NDEFReader;
const ndef = new NDEFClass();
await ndef.write({
records: [{ recordType: 'url', data: paymentUrl }],
});
};Note: NFC writing requires Android Chrome. iOS Safari can read NFC tags but cannot write them.
We believe in transparency. Here's what TapPay can and can't do today:
| Feature | Status | Notes |
|---|---|---|
| Email/Google login | ✅ Working | Magic embedded wallet |
| Cross-chain payments | ✅ Working | Buyers can pay with any token on 6 supported chains (ETH, BNB, SOL, etc.) — UA auto-converts to Arbitrum USDC |
| NFC tag writing | iOS can read, not write | |
| Single chain settlement | Arbitrum only (by design) | |
| Mobile app | ❌ Not yet | Web-only, PWA possible |
| Multi-merchant dashboard | ❌ Not yet | Single merchant per account |
- ✅ Core payment flow
- ✅ EIP-7702 chain abstraction
- ✅ Magic social login
- ✅ NFC tap-to-pay
- 🔄 Support for USDT and other stablecoins
- 🔄 Merchant analytics dashboard
- 🔄 Payment notifications (WebSocket)
- 🔄 Mobile-optimized PWA
- 📋 Multi-chain settlement (Base, Polygon)
- 📋 Merchant settlement preferences
- 📋 Recurring payments / subscriptions
- 📋 POS integration — Provide NFC API/SDK for point-of-sale terminals to read/write payment tags
TapPay is built for three tracks in the UXMaxx Hackathon:
Requirement: Build with Particle Network's Universal Accounts SDK in EIP-7702 mode.
How TapPay qualifies:
- ✅ Uses
@particle-network/universal-account-sdkwithuseEIP7702: true - ✅ Cross-chain operation: User pays with USDC on any chain, merchant receives on Arbitrum
- ✅ EIP-7702 authorization signing via Magic's
sign7702Authorization - ✅ No new address, no asset migration — user's EOA becomes chain-abstracted in place
Key code: See Particle Universal Accounts + EIP-7702 section.
Requirement: Build a consumer app where Arbitrum powers the experience behind the scenes.
How TapPay qualifies:
- ✅ Smart contract deployed on Arbitrum One
- ✅ All payments settle on Arbitrum as USDC
- ✅ Buyers can pay with any token on 6 supported chains (Ethereum, BSC, X Layer, Base, Arbitrum, Solana)
- ✅ Consumer-focused UX — users never think about chains or gas
- ✅ Chain-abstracted pattern with embedded wallet
- ✅ Arbitrum acts as backend settlement layer (cross-chain apps pattern)
Judging criteria alignment:
- UX Excellence (30%) — Tap-to-pay, social login, zero friction
- Creativity (30%) — NFC + crypto payments, physical-digital bridge
- Adoption Potential (20%) — Solves real payment friction
- Execution Quality (20%) — Working demo, clean code, deployed contract
Requirement: Integrate Magic's embedded wallet for seamless onboarding.
How TapPay qualifies:
- ✅ Email login with OTP
- ✅ Google OAuth login
- ✅ No wallet installation required
- ✅ EIP-7702 signing via
magic.wallet.sign7702Authorization() - ✅ Invisible wallet management
Key code: See Magic Embedded Wallet section.
This project is licensed under the MIT License — see the LICENSE file for details.
- Particle Network — Universal Accounts & chain abstraction
- Magic Labs — Embedded wallet infrastructure
- Arbitrum — Low-cost, high-speed settlement layer
- UXMaxx Hackathon — The competition that made this possible
Built with ❤️ for the UXMaxx Hackathon



