Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ coverage
pnpm-lock.yaml
.nuxt
.svelte-kit
bundle-analysis.html
bundle-analysis.html
.open-next
/apps/pay-test-exchange/**.d.ts
43 changes: 43 additions & 0 deletions apps/pay-test-exchange/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# OpenNext
/.open-next

# wrangler files
.wrangler
.dev.vars*
5 changes: 5 additions & 0 deletions apps/pay-test-exchange/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"wrangler.json": "jsonc"
}
}
243 changes: 243 additions & 0 deletions apps/pay-test-exchange/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# AppKit Pay Test Exchange

A testing environment for simulating payment exchange interactions with **Reown AppKit Pay**. This application provides a controlled environment to test payment flows, session management, and various payment scenarios during development.

## 🎯 Purpose

The Pay Test Exchange simulates a merchant/exchange interface that receives payment requests from AppKit Pay and allows developers to:

- Test payment session flows (pending → success/error states)
- Validate payment parameters (asset, amount, recipient)
- Simulate both successful and failed payment scenarios
- Debug payment integration issues in a controlled environment

## ✨ Features

### 🔄 Session Management

- **Automatic session creation** with pending status
- **Status transitions**: pending → success or error
- **Session validation** via URL parameters

### 💳 Payment Information Display

- **Asset parsing**: Displays chain ID and token standard
- **Amount visualization**: Shows payment amounts clearly
- **Recipient validation**: Displays destination addresses

### 🧪 Testing Controls

- **Success simulation**: Mark payments as successful
- **Error simulation**: Trigger payment failures
- **Real-time updates**: Immediate session status changes
- **Navigation handling**: Automatic redirects to result pages

## 🚀 Getting Started

### Prerequisites

- Node.js 18+
- npm, yarn, pnpm, or bun
- Access to the Reown AppKit ecosystem

### Installation

1. **Install dependencies**:
```bash
npm install
# or
yarn install
# or
pnpm install
# or
bun install
```

### Development

2. **Start the development server**:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

3. **Open the application**:
Visit [http://localhost:4001](http://localhost:4001) in your browser

### Usage

#### Basic Payment Test

1. **Navigate with session parameters**:

```
http://localhost:4001?sessionId=your-session-id&asset=eip155:1/erc20:0x123&amount=100&recipient=0xabc123
```

2. **Required parameters**:

- `sessionId`: Unique identifier for the payment session

3. **Optional parameters**:
- `asset`: Asset identifier (format: `namespace:chainId/standard:address`)
- `amount`: Payment amount (in token units)
- `recipient`: Destination wallet address

#### Testing Payment Flows

1. **Success Scenario**:

- Click "Complete Successfully" button
- Session status updates to `success`
- Redirected to success page

2. **Error Scenario**:
- Click "Trigger Error" button
- Session status updates to `error`
- Redirected to error page

## 🏗️ Architecture

### Project Structure

```
apps/pay-test-exchange/
├── app/
│ ├── api/ # API routes for session management
│ ├── error/ # Error result page
│ ├── success/ # Success result page
│ └── page.tsx # Main exchange interface
├── components/
│ ├── ui/ # Reusable UI components
│ ├── exchange-actions.tsx # Main control interface
│ ├── payment-info.tsx # Payment details display
│ └── error-screen.tsx # Error state component
├── lib/
│ ├── session-actions.ts # Session management logic
│ └── types.ts # TypeScript definitions
└── public/
└── reown-logo.png # Branding assets
```

### API Endpoints

- **POST** `/api/update` - Update session status
- **GET** `/api/status` - Get session status

## 🔧 Configuration

### Environment Setup

The application supports multiple deployment environments:

- **Development**: `npm run dev` (port 4001)
- **Production**: `npm run build && npm run start`
- **Cloudflare**: `npm run deploy`

### Amount Validation

Test various amount formats:

```
- 1000000000000000000 # 1 ETH (18 decimals)
- 1000000 # 1 USDC (6 decimals)
- 500000000 # 0.5 SOL (9 decimals)
```

### Error Conditions

Test error scenarios:

```
- Missing sessionId # Triggers error screen
- Invalid parameters # Tests parameter validation
- Network failures # Simulates API issues
```

## 🚀 Deployment

### Cloudflare Deployment

1. **Build for Cloudflare**:

```bash
npm run deploy
```

2. **Preview deployment**:

```bash
npm run preview
```

3. **Generate Cloudflare types**:
```bash
npm run cf-typegen
```

## 🤝 Integration with AppKit Pay

This test exchange works in conjunction with:

- **AppKit Pay SDK**: For payment initiation
- **Payment Controllers**: For transaction handling
- **Wallet Adapters**: For multi-chain support
- **Session Management**: For state synchronization

## 📋 API Reference

### Session Status Updates

```typescript
// Update session status
POST /api/update?sessionId={id}
{
"status": "success" | "error" | "pending"
}

// Get session status
GET /api/status?sessionId={id}
```

### Payment Parameters

```typescript
interface PaymentParams {
sessionId: string // Required: Unique session identifier
asset?: string // Optional: Asset identifier
amount?: string // Optional: Payment amount
recipient?: string // Optional: Destination address
}
```

## 🔍 Troubleshooting

### Common Issues

1. **Missing sessionId**: Ensure URL includes valid `sessionId` parameter
2. **Session not found**: Check session creation in network tab
3. **Payment display issues**: Verify asset format and parameters
4. **Navigation errors**: Check success/error page routing

### Debug Mode

Enable detailed logging by checking browser console and network requests.

## 📄 License

This project is part of the Reown AppKit ecosystem. See the main repository for license details.

## 🆘 Support

For issues and questions:

- Check the main AppKit repository
- Review integration documentation
- Test with different parameter combinations
- Verify session management flow
20 changes: 20 additions & 0 deletions apps/pay-test-exchange/app/api/status/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { getCloudflareContext } from '@opennextjs/cloudflare'
import type { NextRequest } from 'next/server'

export async function GET(request: NextRequest) {
const { env } = getCloudflareContext()

const sessionId = request.nextUrl.searchParams.get('sessionId')

if (!sessionId) {
return new Response('No sessionId provided', { status: 400 })
}

const session = await env.SESSIONID_STORAGE.get(sessionId)

if (!session) {
return new Response('Session not found', { status: 404 })
}

return new Response(session)
}
51 changes: 51 additions & 0 deletions apps/pay-test-exchange/app/api/update/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { getCloudflareContext } from '@opennextjs/cloudflare'
import { NextRequest } from 'next/server'

import { Session } from '@/lib/types'

interface UpdateSessionRequest {
status: Session['status']
}

export async function POST(request: NextRequest) {
const { env } = getCloudflareContext()

const sessionId = request.nextUrl.searchParams.get('sessionId')

if (!sessionId) {
return new Response('No sessionId provided', { status: 400 })
}

const sessionData = await env.SESSIONID_STORAGE.get(sessionId)

if (!sessionData) {
await env.SESSIONID_STORAGE.put(
sessionId,
JSON.stringify({
status: 'pending',
createdAt: new Date().toISOString()
} as Session)
)

return new Response('Session created', { status: 200 })
}

const session = JSON.parse(sessionData) as Session

// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const { status } = (await request.json()) as UpdateSessionRequest

if (status !== 'success' && status !== 'error') {
return new Response('Invalid status provided', { status: 400 })
}

session.status = status
if (status === 'success') {
// Mock txid
session.txid = '0x9b629147b75dc0b275d478fa34d97c5d4a26926457540b15a5ce871df36c23fd'
}

await env.SESSIONID_STORAGE.put(sessionId, JSON.stringify(session))

return new Response('Session updated', { status: 200 })
}
22 changes: 22 additions & 0 deletions apps/pay-test-exchange/app/error/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { XCircle } from 'lucide-react'

import ActionResult from '@/components/action-result'

export default function ErrorActionPage() {
const description = (
<>
<p>The session has been updated to reflect the error state.</p>
<br />
<p>This test exchange has simulated a payment failure.</p>
</>
)

return (
<ActionResult
icon={<XCircle className="w-full h-full" />}
title="Payment Failed"
description={description}
iconClassName="text-red-500"
/>
)
}
Binary file added apps/pay-test-exchange/app/favicon.ico
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading