repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | # Crypto Payments |
| #2 | |
| #3 | Accept cryptocurrency payments in your applications. |
| #4 | |
| #5 | ## Simple SOL Payment |
| #6 | |
| #7 | ```tsx |
| #8 | import { useSolana, useAccounts } from "@phantom/react-sdk"; |
| #9 | import { Connection, PublicKey, SystemProgram, VersionedTransaction, TransactionMessage } from "@solana/web3.js"; |
| #10 | |
| #11 | function PayButton({ recipient, amountSol }: { recipient: string; amountSol: number }) { |
| #12 | const { solana } = useSolana(); |
| #13 | const { isConnected } = useAccounts(); |
| #14 | const [status, setStatus] = useState<"idle" | "paying" | "success" | "error">("idle"); |
| #15 | |
| #16 | async function handlePay() { |
| #17 | setStatus("paying"); |
| #18 | try { |
| #19 | const connection = new Connection("https://api.mainnet-beta.solana.com"); |
| #20 | const { blockhash } = await connection.getLatestBlockhash(); |
| #21 | const wallet = await solana.getPublicKey(); |
| #22 | |
| #23 | const message = new TransactionMessage({ |
| #24 | payerKey: new PublicKey(wallet), |
| #25 | recentBlockhash: blockhash, |
| #26 | instructions: [ |
| #27 | SystemProgram.transfer({ |
| #28 | fromPubkey: new PublicKey(wallet), |
| #29 | toPubkey: new PublicKey(recipient), |
| #30 | lamports: Math.floor(amountSol * 1e9), |
| #31 | }), |
| #32 | ], |
| #33 | }).compileToV0Message(); |
| #34 | |
| #35 | const tx = new VersionedTransaction(message); |
| #36 | await solana.signAndSendTransaction(tx); |
| #37 | setStatus("success"); |
| #38 | } catch { |
| #39 | setStatus("error"); |
| #40 | } |
| #41 | } |
| #42 | |
| #43 | return ( |
| #44 | <button onClick={handlePay} disabled={!isConnected || status === "paying"}> |
| #45 | {status === "paying" ? "Processing..." : `Pay ${amountSol} SOL`} |
| #46 | </button> |
| #47 | ); |
| #48 | } |
| #49 | ``` |
| #50 | |
| #51 | ## SPL Token Payment (USDC) |
| #52 | |
| #53 | ```tsx |
| #54 | import { getAssociatedTokenAddress, createTransferInstruction, createAssociatedTokenAccountInstruction, getAccount } from "@solana/spl-token"; |
| #55 | |
| #56 | const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; |
| #57 | |
| #58 | async function payWithUSDC(solana: any, recipient: string, amount: number) { |
| #59 | const connection = new Connection("https://api.mainnet-beta.solana.com"); |
| #60 | const { blockhash } = await connection.getLatestBlockhash(); |
| #61 | const wallet = await solana.getPublicKey(); |
| #62 | |
| #63 | const mint = new PublicKey(USDC_MINT); |
| #64 | const from = new PublicKey(wallet); |
| #65 | const to = new PublicKey(recipient); |
| #66 | |
| #67 | const fromAta = await getAssociatedTokenAddress(mint, from); |
| #68 | const toAta = await getAssociatedTokenAddress(mint, to); |
| #69 | |
| #70 | const instructions = []; |
| #71 | |
| #72 | // Create recipient's token account if needed |
| #73 | try { |
| #74 | await getAccount(connection, toAta); |
| #75 | } catch { |
| #76 | instructions.push(createAssociatedTokenAccountInstruction(from, toAta, to, mint)); |
| #77 | } |
| #78 | |
| #79 | // Transfer (USDC has 6 decimals) |
| #80 | instructions.push(createTransferInstruction(fromAta, toAta, from, amount * 1e6)); |
| #81 | |
| #82 | const message = new TransactionMessage({ |
| #83 | payerKey: from, |
| #84 | recentBlockhash: blockhash, |
| #85 | instructions, |
| #86 | }).compileToV0Message(); |
| #87 | |
| #88 | return await solana.signAndSendTransaction(new VersionedTransaction(message)); |
| #89 | } |
| #90 | ``` |
| #91 | |
| #92 | ## Checkout with Backend Verification |
| #93 | |
| #94 | ### Client |
| #95 | |
| #96 | ```tsx |
| #97 | async function checkout(orderId: string, solana: any) { |
| #98 | // 1. Create payment on backend |
| #99 | const { paymentId, transaction } = await fetch("/api/payments/create", { |
| #100 | method: "POST", |
| #101 | body: JSON.stringify({ orderId }), |
| #102 | }).then(r => r.json()); |
| #103 | |
| #104 | // 2. Sign and send |
| #105 | const { hash } = await solana.signAndSendTransaction( |
| #106 | Buffer.from(transaction, "base64") |
| #107 | ); |
| #108 | |
| #109 | // 3. Confirm with backend |
| #110 | const { success } = await fetch("/api/payments/confirm", { |
| #111 | method: "POST", |
| #112 | body: JSON.stringify({ paymentId, txHash: hash }), |
| #113 | }).then(r => r.json()); |
| #114 | |
| #115 | return success; |
| #116 | } |
| #117 | ``` |
| #118 | |
| #119 | ### Server |
| #120 | |
| #121 | ```ts |
| #122 | // /api/payments/create.ts |
| #123 | export async function POST(req: Request) { |
| #124 | const { orderId } = await req.json(); |
| #125 | |
| #126 | // Get order, calculate amount |
| #127 | const order = await db.orders.findUnique({ where: { id: orderId } }); |
| #128 | const solAmount = order.total / await getSolPrice(); |
| #129 | |
| #130 | // Create payment record |
| #131 | const payment = await db.payments.create({ |
| #132 | data: { orderId, solAmount, status: "pending" } |
| #133 | }); |
| #134 | |
| #135 | // Build transaction (partial - user will sign) |
| #136 | // Return serialized transaction |
| #137 | |
| #138 | return Response.json({ paymentId: payment.id, transaction: "..." }); |
| #139 | } |
| #140 | |
| #141 | // /api/payments/confirm.ts |
| #142 | export async function POST(req: Request) { |
| #143 | const { paymentId, txHash } = await req.json(); |
| #144 | |
| #145 | // Verify transaction on-chain |
| #146 | const connection = new Connection("https://api.mainnet-beta.solana.com"); |
| #147 | const tx = await connection.getTransaction(txHash, { commitment: "confirmed" }); |
| #148 | |
| #149 | if (!tx) return Response.json({ success: false }); |
| #150 | |
| #151 | // Verify amount and recipient match |
| #152 | // Update payment status |
| #153 | // Fulfill order |
| #154 | |
| #155 | return Response.json({ success: true }); |
| #156 | } |
| #157 | ``` |
| #158 | |
| #159 | ## Price Display with Live Rates |
| #160 | |
| #161 | ```tsx |
| #162 | function PriceDisplay({ usdAmount }: { usdAmount: number }) { |
| #163 | const [solPrice, setSolPrice] = useState(0); |
| #164 | |
| #165 | useEffect(() => { |
| #166 | async function fetchPrice() { |
| #167 | const res = await fetch("https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd"); |
| #168 | const data = await res.json(); |
| #169 | setSolPrice(data.solana.usd); |
| #170 | } |
| #171 | fetchPrice(); |
| #172 | const interval = setInterval(fetchPrice, 60000); |
| #173 | return () => clearInterval(interval); |
| #174 | }, []); |
| #175 | |
| #176 | const solAmount = solPrice ? (usdAmount / solPrice).toFixed(4) : "..."; |
| #177 | |
| #178 | return ( |
| #179 | <div> |
| #180 | <p>${usdAmount} USD</p> |
| #181 | <p>≈ {solAmount} SOL</p> |
| #182 | </div> |
| #183 | ); |
| #184 | } |
| #185 | ``` |
| #186 | |
| #187 | ## Best Practices |
| #188 | |
| #189 | 1. **Always verify on-chain** - Don't trust client-side alone |
| #190 | 2. **Use unique payment IDs** - Track each payment |
| #191 | 3. **Handle price volatility** - Lock prices or use stablecoins |
| #192 | 4. **Set expiration** - Payment requests should expire |
| #193 | 5. **Wait for confirmations** - Confirm before fulfilling |
| #194 |