xiaohongshu
xiaohongshu
Enabling direct peer-to-peer cryptocurrency transactions without intermediaries, including direct wallet payments, payment processors, transaction monitoring, and blockchain confirmation.
Full skill instructions
Current Level: Advanced
Domain: Blockchain / Payments
Cryptocurrency payments enable direct peer-to-peer transactions without intermediaries. This guide covers direct wallet payments, payment processors, and transaction monitoring for accepting crypto payments in applications.
Customer → Payment Request → Wallet → Blockchain → Confirmation → Order Complete
Payment Methods:
// services/crypto-payment.service.ts
import { ethers } from 'ethers';
export class CryptoPaymentService {
constructor(
private provider: ethers.providers.Provider,
private merchantAddress: string
) {}
async createPaymentRequest(
amount: string,
currency: 'ETH' | 'USDC' | 'DAI'
): Promise<PaymentRequest> {
const paymentId = this.generatePaymentId();
const expiresAt = Date.now() + 15 * 60 * 1000; // 15 minutes
return {
paymentId,
merchantAddress: this.merchantAddress,
amount,
currency,
expiresAt,
status: 'pending'
};
}
async monitorPayment(
paymentId: string,
expectedAmount: string
): Promise<PaymentStatus> {
const filter = {
address: this.merchantAddress,
topics: []
};
return new Promise((resolve) => {
this.provider.on(filter, async (log) => {
const tx = await this.provider.getTransaction(log.transactionHash);
if (tx.to === this.merchantAddress) {
const receivedAmount = ethers.utils.formatEther(tx.value);
if (receivedAmount === expectedAmount) {
resolve({
paymentId,
status: 'confirmed',
transactionHash: tx.hash,
amount: receivedAmount
});
}
}
});
});
}
async verifyPayment(
transactionHash: string,
expectedAmount: string
): Promise<boolean> {
const receipt = await this.provider.getTransactionReceipt(transactionHash);
if (!receipt || receipt.status !== 1) {
return false;
}
const tx = await this.provider.getTransaction(transactionHash);
const receivedAmount = ethers.utils.formatEther(tx.value);
return (
tx.to === this.merchantAddress &&
receivedAmount === expectedAmount &&
receipt.confirmations >= 3
);
}
private generatePaymentId(): string {
return `pay_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}
interface PaymentRequest {
paymentId: string;
merchantAddress: string;
amount: string;
currency: string;
expiresAt: number;
status: 'pending' | 'confirmed' | 'expired';
}
interface PaymentStatus {
paymentId: string;
status: string;
transactionHash: string;
amount: string;
}
// services/coinbase-commerce.service.ts
import axios from 'axios';
export class CoinbaseCommerceService {
private apiKey = process.env.COINBASE_COMMERCE_API_KEY!;
private baseUrl = 'https://api.commerce.coinbase.com';
async createCharge(data: CreateChargeDto): Promise<Charge> {
const response = await axios.post(
`${this.baseUrl}/charges`,
{
name: data.name,
description: data.description,
pricing_type: 'fixed_price',
local_price: {
amount: data.amount,
currency: data.currency
},
metadata: data.metadata
},
{
headers: {
'X-CC-Api-Key': this.apiKey,
'X-CC-Version': '2018-03-22'
}
}
);
return response.data.data;
}
async getCharge(chargeId: string): Promise<Charge> {
const response = await axios.get(
`${this.baseUrl}/charges/${chargeId}`,
{
headers: {
'X-CC-Api-Key': this.apiKey,
'X-CC-Version': '2018-03-22'
}
}
);
return response.data.data;
}
async listCharges(): Promise<Charge[]> {
const response = await axios.get(
`${this.baseUrl}/charges`,
{
headers: {
'X-CC-Api-Key': this.apiKey,
'X-CC-Version': '2018-03-22'
}
}
);
return response.data.data;
}
verifyWebhook(signature: string, payload: string): boolean {
const crypto = require('crypto');
const webhookSecret = process.env.COINBASE_WEBHOOK_SECRET!;
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('hex');
return signature === expectedSignature;
}
}
interface CreateChargeDto {
name: string;
description: string;
amount: string;
currency: string;
metadata?: Record<string, any>;
}
interface Charge {
id: string;
code: string;
name: string;
description: string;
hosted_url: string;
pricing: {
local: { amount: string; currency: string };
bitcoin?: { amount: string; currency: string };
ethereum?: { amount: string; currency: string };
};
payments: Payment[];
timeline: TimelineEvent[];
}
interface Payment {
network: string;
transaction_id: string;
status: string;
value: {
local: { amount: string; currency: string };
crypto: { amount: string; currency: string };
};
}
interface TimelineEvent {
time: string;
status: string;
}
// services/nowpayments.service.ts
export class NOWPaymentsService {
private apiKey = process.env.NOWPAYMENTS_API_KEY!;
private baseUrl = 'https://api.nowpayments.io/v1';
async createPayment(data: CreatePaymentDto): Promise<Payment> {
const response = await axios.post(
`${this.baseUrl}/payment`,
{
price_amount: data.amount,
price_currency: data.currency,
pay_currency: data.payCurrency,
order_id: data.orderId,
order_description: data.description,
ipn_callback_url: data.callbackUrl
},
{
headers: {
'x-api-key': this.apiKey
}
}
);
return response.data;
}
async getPaymentStatus(paymentId: string): Promise<PaymentStatus> {
const response = await axios.get(
`${this.baseUrl}/payment/${paymentId}`,
{
headers: {
'x-api-key': this.apiKey
}
}
);
return response.data;
}
async getAvailableCurrencies(): Promise<string[]> {
const response = await axios.get(
`${this.baseUrl}/currencies`,
{
headers: {
'x-api-key': this.apiKey
}
}
);
return response.data.currencies;
}
async getEstimatedPrice(
amount: number,
fromCurrency: string,
toCurrency: string
): Promise<EstimatedPrice> {
const response = await axios.get(
`${this.baseUrl}/estimate`,
{
params: {
amount,
currency_from: fromCurrency,
currency_to: toCurrency
},
headers: {
'x-api-key': this.apiKey
}
}
);
return response.data;
}
}
interface CreatePaymentDto {
amount: number;
currency: string;
payCurrency: string;
orderId: string;
description: string;
callbackUrl: string;
}
interface EstimatedPrice {
currency_from: string;
currency_to: string;
estimated_amount: string;
}
// services/transaction-monitor.service.ts
export class TransactionMonitorService {
private provider: ethers.providers.Provider;
constructor(provider: ethers.providers.Provider) {
this.provider = provider;
}
async waitForConfirmations(
txHash: string,
confirmations: number = 3
): Promise<ethers.providers.TransactionReceipt> {
const receipt = await this.provider.waitForTransaction(txHash, confirmations);
return receipt;
}
async getTransactionStatus(txHash: string): Promise<TransactionStatus> {
const [tx, receipt] = await Promise.all([
this.provider.getTransaction(txHash),
this.provider.getTransactionReceipt(txHash)
]);
if (!receipt) {
return {
status: 'pending',
confirmations: 0
};
}
const currentBlock = await this.provider.getBlockNumber();
const confirmations = currentBlock - receipt.blockNumber + 1;
return {
status: receipt.status === 1 ? 'confirmed' : 'failed',
confirmations,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
}
monitorAddress(
address: string,
callback: (tx: ethers.providers.TransactionResponse) => void
): () => void {
const filter = {
address,
topics: []
};
const listener = async (log: ethers.providers.Log) => {
const tx = await this.provider.getTransaction(log.transactionHash);
if (tx.to === address) {
callback(tx);
}
};
this.provider.on(filter, listener);
return () => {
this.provider.off(filter, listener);
};
}
}
interface TransactionStatus {
status: 'pending' | 'confirmed' | 'failed';
confirmations: number;
blockNumber?: number;
gasUsed?: string;
}
// services/payment-confirmation.service.ts
export class PaymentConfirmationService {
async confirmPayment(
transactionHash: string,
expectedAmount: string,
expectedRecipient: string
): Promise<ConfirmationResult> {
const provider = new ethers.providers.InfuraProvider('mainnet');
// Wait for confirmations
const receipt = await provider.waitForTransaction(transactionHash, 3);
if (receipt.status !== 1) {
return {
confirmed: false,
reason: 'Transaction failed'
};
}
// Verify transaction details
const tx = await provider.getTransaction(transactionHash);
if (tx.to?.toLowerCase() !== expectedRecipient.toLowerCase()) {
return {
confirmed: false,
reason: 'Incorrect recipient'
};
}
const receivedAmount = ethers.utils.formatEther(tx.value);
if (receivedAmount !== expectedAmount) {
return {
confirmed: false,
reason: 'Incorrect amount'
};
}
return {
confirmed: true,
transactionHash,
amount: receivedAmount,
confirmations: receipt.confirmations
};
}
}
interface ConfirmationResult {
confirmed: boolean;
reason?: string;
transactionHash?: string;
amount?: string;
confirmations?: number;
}
// services/multi-currency.service.ts
export class MultiCurrencyService {
private supportedCurrencies = ['ETH', 'BTC', 'USDC', 'USDT', 'DAI'];
async getExchangeRate(from: string, to: string): Promise<number> {
// Use CoinGecko API
const response = await fetch(
`https://api.coingecko.com/api/v3/simple/price?ids=${from}&vs_currencies=${to}`
);
const data = await response.json();
return data[from.toLowerCase()][to.toLowerCase()];
}
async convertAmount(
amount: number,
from: string,
to: string
): Promise<number> {
const rate = await this.getExchangeRate(from, to);
return amount * rate;
}
async getPriceInCrypto(
usdAmount: number,
cryptocurrency: string
): Promise<string> {
const cryptoAmount = await this.convertAmount(usdAmount, 'usd', cryptocurrency);
return cryptoAmount.toFixed(8);
}
}
// pages/api/webhooks/coinbase.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import crypto from 'crypto';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Verify webhook signature
const signature = req.headers['x-cc-webhook-signature'] as string;
const payload = JSON.stringify(req.body);
if (!verifySignature(signature, payload)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.body;
// Handle different event types
switch (event.type) {
case 'charge:confirmed':
await handleChargeConfirmed(event.data);
break;
case 'charge:failed':
await handleChargeFailed(event.data);
break;
case 'charge:pending':
await handleChargePending(event.data);
break;
}
res.json({ success: true });
}
function verifySignature(signature: string, payload: string): boolean {
const webhookSecret = process.env.COINBASE_WEBHOOK_SECRET!;
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('hex');
return signature === expectedSignature;
}
async function handleChargeConfirmed(data: any): Promise<void> {
// Update order status
await db.order.update({
where: { id: data.metadata.order_id },
data: {
status: 'paid',
transactionHash: data.payments[0].transaction_id
}
});
// Send confirmation email
await emailService.sendOrderConfirmation(data.metadata.order_id);
}
async function handleChargeFailed(data: any): Promise<void> {
await db.order.update({
where: { id: data.metadata.order_id },
data: { status: 'payment_failed' }
});
}
async function handleChargePending(data: any): Promise<void> {
await db.order.update({
where: { id: data.metadata.order_id },
data: { status: 'payment_pending' }
});
}
interface PaymentRequest {
orderId: string
amount: number // in crypto (e.g., 0.01 ETH)
currency: 'ETH' | 'BTC' | 'USDT'
recipientAddress: string
}
async function createPaymentRequest(request: PaymentRequest) {
const payment = await db.payments.create({
data: {
orderId: request.orderId,
amount: request.amount,
currency: request.currency,
recipientAddress: request.recipientAddress,
status: 'pending',
expiresAt: addMinutes(new Date(), 15) // 15 min expiry
}
})
return {
address: request.recipientAddress,
amount: request.amount,
currency: request.currency,
qrCode: generateQRCode(`${request.currency}:${request.recipientAddress}?amount=${request.amount}`)
}
}
async function monitorTransaction(txHash: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL)
// Wait for confirmations
const receipt = await provider.waitForTransaction(txHash, 3) // 3 confirmations
if (receipt.status === 1) {
await updatePaymentStatus(txHash, 'confirmed')
} else {
await updatePaymentStatus(txHash, 'failed')
}
}
// ❌ Bad - Accept after 1 confirmation
const receipt = await provider.waitForTransaction(txHash, 1)
await completeOrder(orderId) // Too risky!
// ✅ Good - Wait for multiple confirmations
const receipt = await provider.waitForTransaction(txHash, 3) // 3 confirmations
await completeOrder(orderId) // Safer
// ❌ Bad - Store private keys
const wallet = new ethers.Wallet('0x...private-key...') // Exposed!
// ✅ Good - Use payment processor
// Or hardware wallet
// Never store private keys in code
35-blockchain-web3/wallet-connection/) - User wallets35-blockchain-web3/smart-contracts/) - Contract payments30-ecommerce/payment-gateways/) - Payment patternsxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience