@chainrails/react-native
v0.0.68
Published
Chainrails React Native SDK
Readme
@chainrails/react-native
React Native SDK for Chainrails payment integration.
Installation
npm install @chainrails/react-native react-native-webview
# or
yarn add @chainrails/react-native react-native-webview
# or
pnpm add @chainrails/react-native react-native-webviewPeer Dependencies
Required for all integrations:
react>= 16.8.0react-native>= 0.64.0react-native-webview>= 11.0.0
Solana Mobile Wallet Adapter (Android only)
MWA packages (@solana/web3.js, @solana-mobile/*, react-native-quick-base64, @react-native-async-storage/async-storage) ship as SDK dependencies — you do not install them separately.
MWA is Android-only. On iOS, wallet adapter code is excluded from the app bundle and isMwaAvailable() is always false.
MWA requires a custom native build (not Expo Go). Native modules ship as SDK dependencies but must be autolinked into your app. Add this file next to your package.json:
// react-native.config.js
module.exports = require('@chainrails/react-native/react-native.config.js');After installing or upgrading the SDK, regenerate native projects:
npx expo prebuild --clean
npx expo run:androidSee docs/MWA.md.
Buffer and crypto.getRandomValues polyfills are applied automatically when MWA code loads — you do not need a custom app entrypoint for polyfills.
For direct MWA APIs (standalone connect testing), import from the optional subpath:
import { performMwaConnect, createMwaTestContext } from '@chainrails/react-native/mwa';Usage
Basic Setup
import { usePaymentModal, Chainrails } from '@chainrails/react-native';
function App() {
const { isOpen, open, close, sessionToken, amount } = usePaymentModal({
sessionToken: 'your-session-token',
amount: '100',
onSuccess: (result) => {
console.log('Payment successful!', result?.transactionHash);
},
onCancel: () => {
console.log('Payment cancelled');
},
});
return (
<View>
<Button title="Open Payment" onPress={open} />
<PaymentModal
isOpen={isOpen}
sessionToken={sessionToken}
amount={amount}
open={open}
close={close}
onSuccess={(result) => console.log(result?.transactionHash)}
onCancel={() => console.log('cancelled')}
/>
</View>
);
}Using usePaymentSession
For server-side session management:
import { usePaymentSession } from '@chainrails/react-native';
function App() {
const { isOpen, open, close, sessionToken, amount, isPending, error } = usePaymentSession({
session_url: 'https://your-api.com/payment-session',
onSuccess: () => console.log('Payment completed'),
onCancel: () => console.log('Payment cancelled'),
});
if (error) {
return <Text>Error: {error}</Text>;
}
return (
<View>
<Button title="Pay" onPress={open} disabled={isPending} />
<PaymentModal
isOpen={isOpen}
sessionToken={sessionToken}
amount={amount}
open={open}
close={close}
onSuccess={() => {}}
onCancel={() => {}}
/>
</View>
);
}API Reference
PaymentModal
The main payment modal component.
import { PaymentModal } from "@chainrails/react-native";
<PaymentModal
isOpen={boolean}
sessionToken={string | null | undefined}
amount={string | undefined}
open={() => void}
close={() => void}
onSuccess?: (result?: { transactionHash?: string }) => void
onCancel?: () => void
isPending?: boolean
styles?: {
accentColor?: string;
theme?: string;
}
css?: string;
excludeChains?: Chain[];
env?: "production" | "internal";
client?: ClientInfo;
session_url?: string;
/>Props
| Prop | Type | Description |
| ----------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------- |
| isOpen | boolean | Controls modal visibility |
| sessionToken | string \| null \| undefined | Authentication session token |
| amount | string \| undefined | Payment amount |
| open | () => void | Function to open the modal |
| close | () => void | Function to close the modal |
| onSuccess | (result?: { transactionHash?: string }) => void | Called when payment succeeds |
| onCancel | () => void | Called when payment is cancelled |
| isPending | boolean | Shows pending state |
| styles | { accentColor?: string; theme?: string } | Visual customization |
| disableSeekerThemeAutoApply | boolean | Disables auto-application of the Seeker theme on Seeker devices (default: false) |
| css | string | Custom CSS to inject into the payment modal |
| excludeChains | Chain[] | Chains to exclude from the payment modal |
| env | "production" \| "internal" | Environment to use |
| client | ClientInfo | Client information for paymaster |
| session_url | string | Session URL for server-side management |
usePaymentModal
Hook for managing payment modal state.
const {
isOpen,
open,
close,
sessionToken,
amount,
client,
updateSession,
onSuccess,
onCancel,
} = usePaymentModal({
sessionToken: string | null;
amount?: string;
onCancel?: () => void;
onSuccess?: (result?: { transactionHash?: string }) => void;
client?: ClientInfo;
});Returns
| Property | Type | Description |
| --------------- | ------------------------- | ---------------------------------- |
| isOpen | boolean | Whether the modal is open |
| open | () => void | Open the payment modal |
| close | () => void | Close the payment modal |
| sessionToken | string \| null | Current session token |
| amount | string \| undefined | Current payment amount |
| client | ClientInfo \| undefined | Current client info |
| updateSession | (params) => void | Update session, amount, and client |
| onSuccess | () => void | Success callback |
| onCancel | () => void | Cancel callback |
usePaymentSession
Hook for server-side session management with automatic token fetching.
const {
isOpen,
open,
close,
sessionToken,
amount,
isPending,
error,
refetch,
onSuccess,
onCancel,
} = usePaymentSession({
session_url: string;
onCancel?: () => void;
onSuccess?: (result?: { transactionHash?: string }) => void;
});Returns
| Property | Type | Description |
| -------------- | --------------------- | ------------------------------ |
| isOpen | boolean | Whether the modal is open |
| open | () => void | Open the payment modal |
| close | () => void | Close the payment modal |
| sessionToken | string \| null | Session token from the server |
| amount | string \| undefined | Payment amount from the server |
| isPending | boolean | Whether the session is loading |
| error | string \| null | Error message if fetch failed |
| refetch | () => void | Manually refetch the session |
| onSuccess | () => void | Success callback |
| onCancel | () => void | Cancel callback |
Custom CSS
You can pass custom CSS to style the payment modal:
<PaymentModal
isOpen={isOpen}
sessionToken={token}
amount="100"
css={`
.payment-modal {
background: #ffffff;
border-radius: 16px;
}
.payment-header {
font-family: 'Inter', sans-serif;
}
`}
// ...other props
/>Theme Support
Built-in themes: "light", "dark", "system"
<PaymentModal
// ...props
styles={{
theme: 'dark', // or "light" or "system"
accentColor: '#6366f1',
}}
/>You can also use a custom theme by passing a theme ID that exists on your server:
<PaymentModal
// ...props
styles={{
theme: 'my-custom-theme', // Server fetches the theme CSS
}}
/>Solana Seeker auto-theme
When the SDK detects a Solana Seeker device and the caller has not passed an
explicit styles.theme, the modal automatically applies the Seeker theme
(SOLANA_SEEKER_THEME, ID seeker-098a1d68). On every other device the modal
falls back to the default behaviour — nothing about the existing API changes.
Detection reads Platform.constants (Brand, Manufacturer, Model, Product,
Fingerprint, etc.) from React Native core — no extra dependencies are required
and there's nothing to install.
<PaymentModal
// ...props
// styles omitted — Seeker theme will be auto-applied on a Seeker device
/>If you need to detect a Seeker yourself, the SDK exports the helper:
import { isSolanaSeeker, getDeviceFamily, SOLANA_SEEKER_THEME } from '@chainrails/react-native';
if (isSolanaSeeker()) {
// device is a Seeker
}
const family = getDeviceFamily();
// 'ios' | 'android' | 'solana-seeker' | 'unknown'To opt out of the auto-theme while keeping detection available, set
disableSeekerThemeAutoApply on the modal:
<PaymentModal
// ...props
disableSeekerThemeAutoApply
/>Exclude Chains
Filter out specific chains from the payment modal:
import { Chains } from '@chainrails/sdk';
<PaymentModal
// ...props
excludeChains={[Chains.ETHEREUM, Chains.BASE]}
/>;Client Info
Pass client information for paymaster support:
<PaymentModal
// ...props
client={{
name: 'My App',
logoUrl: 'https://example.com/logo.png',
paymasterEnabled: true,
}}
/>Environment
Switch between production and internal environments:
<PaymentModal
// ...props
env="production" // or "internal"
/>Supported External Wallets
The SDK automatically handles deep linking for the following wallets:
- Phantom
- MetaMask
- Coinbase Wallet
- Binance
- Trust Wallet
- SafePal
- Rainbow
- Zerion
- BitKeep
- Coin98
- Ledger
- Rabby
- Frame
- Keystone
- OneKey
- TokenPocket
- MathWallet
- AlphaWallet
- Frontier
- OKX
- Bybit
- Uniswap
- ParaSwap
- Yearn
- Exodus
- Atomic
- Crypto.com
- Huobi
- Bitget
- Gate
- MEXC
- Bitrue
- Woo
Exports
export { PaymentModal } from './PaymentModal';
export { PaymentModalLoader } from './components/PaymentModalLoader';
export { usePaymentSession } from './hooks/usePaymentSession';
export { usePaymentModal } from './hooks/usePaymentModal';
export { isSolanaSeeker, getDeviceFamily } from './utils/device';
export { SOLANA_SEEKER_THEME } from './constants/constants';
export { crapi, Chains, AmountSymbols, Chainrails } from '@chainrails/sdk';
export type { AmountSymbol, Chain, DeviceFamily } from '@chainrails/react-native';
// MWA connect/send helpers — optional subpath `@chainrails/react-native/mwa`License
MIT
