Skip to main content

Best practices

Wallet connection​

Do: await the SDK and connect on load.

const crackpay = await connectCrackPay();

Don't: show a connect button.

// Never do this in a Mini App
<button onClick={connect}>Connect wallet</button>

Don't: ask the user to sign a message. Message signing is not available, and the account address already identifies them.

Handle every connection state​

Connecting, connected, opened outside CrackPay, and failed. See Setting up a React app.

Error handling​

Match on error codes, never on message text.

import { ErrorCode, errorCode, isUserRejection } from "@crackpay/miniapp-sdk";

try {
await walletClient.writeContract(request);
} catch (error) {
if (isUserRejection(error)) return show("Cancelled.");
if (errorCode(error) === ErrorCode.Unauthorized) console.error("Not allowed for this app", error);
console.error(error);
show("The payment didn't go through. Please try again.");
}
  • Treat a cancel as a cancel, not an error.
  • Always log the original error.
  • If a message says an operation was "submitted but never confirmed", ask the user to check their balance before retrying, and never retry automatically.

Money​

  • Keep amounts as bigint; format only when rendering.
  • 6 decimals for tokens, 18 for a native value. See Arc network.
  • Show dollars with two decimals.
  • Approve exact amounts, never unlimited.

Transactions​

  • Show a waiting state only while the call is pending. It resolves when the payment is final; there are no confirmations to count.
  • Disable the button while a transaction is in flight, so a double tap cannot pay twice.
  • One call per transaction.

Contracts​

Security​

  • Validate every address and amount before sending.
  • Never put secrets in VITE_ or NEXT_PUBLIC_ variables.
  • Pin exact dependency versions and commit your lockfile.
  • Only list hosts you control in hostOrigins.

Performance​

  • Keep the first load light: CrackPay users are often on mobile data.
  • Lazy-load below-the-fold content.