
Connectorkit
- 8 installs
- 66 repo stars
- Updated July 9, 2026
- solana-foundation/connectorkit
Helps with ai & agent building tasks during AI-assisted development.
About
connectorkit is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- connectorkit
- AI & Agent Building
- AI-coding skill
Connectorkit by the numbers
- 8 all-time installs (skills.sh)
- Ranked #12,339 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/solana-foundation/connectorkit --skill connectorkitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 66 |
| Last updated | July 9, 2026 |
| Repository | solana-foundation/connectorkit ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
ConnectorKit
@solana/connector — Headless wallet connection library for Solana.
- GitHub: https://github.com/solana-foundation/connectorkit
- NPM:
npm i @solana/connector
Entry Points
| Import | Purpose |
|---|---|
@solana/connector | Full library (React + headless) |
@solana/connector/headless | Framework-agnostic core (Vue, Svelte, vanilla JS) |
@solana/connector/react | React hooks + element components |
@solana/connector/compat | Bridge for existing @solana/wallet-adapter code |
@solana/connector/remote | Browser-side remote wallet adapter |
@solana/connector/server | Server-side route handlers for remote signing |
React hooks and elements are only available via @solana/connector or @solana/connector/react. For non-React frameworks, use ConnectorClient from @solana/connector/headless and subscribe to state changes directly.
Recommended Imports
- Prefer explicit entry points for clarity:
- React:
@solana/connector/react - Headless/core:
@solana/connector/headless - Use
@solana/connectoras a convenience re-export (it re-exports both./reactand./headless).
Next.js (App Router) Setup
Put providers in a single client boundary (typically app/providers.tsx) and keep the rest of your app as Server Components.
// app/providers.tsx
'use client';
import type { ReactNode } from 'react';
import { useMemo } from 'react';
import { AppProvider } from '@solana/connector/react';
import { getDefaultConfig, getDefaultMobileConfig } from '@solana/connector/headless';
function getOrigin() {
if (typeof window === 'undefined') return 'http://localhost:3000';
return window.location.origin;
}
export function Providers({ children }: { children: ReactNode }) {
const connectorConfig = useMemo(
() =>
getDefaultConfig({
appName: 'My App',
appUrl: getOrigin(),
network: 'devnet',
autoConnect: true,
enableMobile: true,
walletConnect: true, // reads NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
}),
[],
);
const mobile = useMemo(
() =>
getDefaultMobileConfig({
appName: 'My App',
appUrl: getOrigin(),
}),
[],
);
return (
<AppProvider connectorConfig={connectorConfig} mobile={mobile}>
{children}
</AppProvider>
);
}// app/layout.tsx
import type { ReactNode } from 'react';
import { Providers } from './providers';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Quick Start (React)
import { AppProvider } from '@solana/connector/react';
import { getDefaultConfig } from '@solana/connector/headless';
const config = getDefaultConfig({
appName: 'My App',
network: 'devnet',
autoConnect: true,
enableMobile: true,
walletConnect: true, // optional; reads NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
});
function App() {
return (
<AppProvider connectorConfig={config}>
<WalletUI />
</AppProvider>
);
}Common Patterns
Connect a Wallet
import { useConnectWallet, useWalletConnectors, useWallet } from '@solana/connector/react';
function ConnectButton() {
const { status, account } = useWallet();
const { connect, isConnecting } = useConnectWallet();
const connectors = useWalletConnectors();
if (status === 'connected') return <div>{account}</div>;
return connectors.map(w => (
<button key={w.id} onClick={() => connect(w.id)} disabled={isConnecting}>
{w.name}
</button>
));
}Sign & Send a Transaction
import { useTransactionSigner } from '@solana/connector/react';
const { signer, ready } = useTransactionSigner();
const sig = await signer.signAndSendTransaction(transaction);For @solana/kit compatible signer: useKitTransactionSigner().
Elements with Render Props
All elements accept a render prop for full UI customization:
import { WalletListElement, AccountElement, BalanceElement } from '@solana/connector/react'
// Default rendering
<WalletListElement />
<AccountElement showAvatar showCopy />
<BalanceElement showTokens />
// Custom via render prop
<AccountElement render={({ address, formatted, copy, copied }) => (
<div onClick={copy}>{copied ? 'Copied!' : formatted}</div>
)} />
<WalletListElement render={({ wallets, connectById, connecting }) => (
wallets.map(w => (
<button key={w.id} onClick={() => connectById(w.id)}>{w.name}</button>
))
)} />All elements: WalletListElement, AccountElement, ClusterElement, DisconnectElement, BalanceElement, TransactionHistoryElement, TokenListElement, SkeletonShine
Switch Networks
import { useCluster } from '@solana/connector/react';
const { cluster, clusters, setCluster, isMainnet, isDevnet } = useCluster();
await setCluster('devnet');Wallet Filtering & Ordering
Improve UX for users with lots of installed wallets by filtering and/or featuring wallets at the config level:
import { getDefaultConfig } from '@solana/connector/headless';
const config = getDefaultConfig({
appName: 'My App',
wallets: {
allowList: ['Phantom', 'Solflare', 'Backpack'],
denyList: ['MetaMask'],
featured: ['Phantom', 'Solflare'],
},
});WalletConnect (QR / Deep Link)
- Install the WalletConnect peer dependency:
npm i @walletconnect/universal-provider - Set
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=... - Enable in config:
walletConnect: true
When a pairing URI is available, render a QR/deep link UI (e.g. a dialog). The provider exposes walletConnectUri and clearWalletConnectUri.
'use client';
import { useConnector } from '@solana/connector/react';
export function WalletConnectQrModal() {
const { walletConnectUri, clearWalletConnectUri } = useConnector();
if (!walletConnectUri) return null;
return (
<div>
<div>WalletConnect URI: {walletConnectUri}</div>
<button onClick={clearWalletConnectUri}>Close</button>
</div>
);
}For a full QR example, see packages/connector/README.md (WalletConnect section).
Remote Signer (Server-backed Signing)
Remote signing is a two-part setup:
1) Browser: create a Wallet Standard wallet that delegates signing to your API.
import { createRemoteSignerWallet } from '@solana/connector/remote';
import { getDefaultConfig } from '@solana/connector/headless';
const remoteWallet = createRemoteSignerWallet({
endpoint: '/api/connector-signer',
name: 'Treasury',
// getAuthHeaders: () => ({ Authorization: `Bearer ${token}` }),
});
const config = getDefaultConfig({
appName: 'My App',
additionalWallets: [remoteWallet],
});2) Server: implement the Next.js route handler to actually sign.
// app/api/connector-signer/route.ts
import { createRemoteSignerRouteHandlers } from '@solana/connector/server';
const { GET, POST } = createRemoteSignerRouteHandlers({
provider: { type: 'custom', signer: myRemoteSigner }, // implements RemoteSigner (see references/remote-signer.md)
authorize: async request => true,
policy: {
validateTransaction: async bytes => true,
validateMessage: async bytes => true,
},
rpc: { endpoint: process.env.RPC_URL },
chains: ['solana:mainnet'],
name: 'Treasury',
});
export { GET, POST };Details (provider configs + protocol types + security) live in references/remote-signer.md.
Devtools (Development Only)
ConnectorKit also ships devtools (@solana/connector-debugger) that can be dynamically mounted in development.
'use client';
import { useEffect } from 'react';
export function DevtoolsLoader() {
useEffect(() => {
if (process.env.NODE_ENV !== 'development') return;
let devtools: { mount: (el: HTMLElement) => void; unmount: () => void } | undefined;
let container: HTMLDivElement | undefined;
import('@solana/connector-debugger').then(({ ConnectorDevtools }) => {
container = document.createElement('div');
document.body.appendChild(container);
devtools = new ConnectorDevtools({ config: { position: 'bottom-right', theme: 'dark' } });
devtools.mount(container);
});
return () => {
devtools?.unmount();
container?.remove();
};
}, []);
return null;
}Security & Production Checklist
- RPC API keys: don’t expose paid RPC URLs as
NEXT_PUBLIC_*; use a Next.js RPC proxy route and point your cluster URL at the proxy (seepackages/connector/README.md). - Token logo privacy: set
imageProxyif you render token images to avoid leaking user IPs to arbitrary token metadata hosts (seepackages/connector/README.md). - CoinGecko rate limits: if you use token prices heavily, configure
coingecko.apiKey. - Remote signer: always implement
authorize+policy.validateTransaction, use HTTPS, and rate limit the signer endpoint.
Headless (Non-React)
import { ConnectorClient } from '@solana/connector/headless';
const client = new ConnectorClient({
autoConnect: true,
cluster: { initialCluster: 'devnet' },
});
client.subscribe(state => {
/* react to changes */
});
await client.connectWallet('wallet-standard:phantom');
const snapshot = client.getSnapshot();Wallet Adapter Compat Bridge
import { useWalletAdapterCompat } from '@solana/connector/compat';
const compat = useWalletAdapterCompat(signer, disconnect);
compat.publicKey; // string | null
compat.connected; // boolean
compat.signTransaction(tx);
compat.sendTransaction(tx, connection);Key Concepts
Connector IDs
Wallets use stable branded WalletConnectorId strings:
'wallet-standard:phantom','wallet-standard:solflare', etc.'walletconnect''mwa:phantom'(Mobile Wallet Adapter on iOS/Android)
Wallet Status State Machine
useWallet() returns a discriminated union:
status: 'disconnected' | 'connecting' | 'connected' | 'error';When status === 'connected', session contains accounts, selectedAccount, selectAccount().
Type guards: isDisconnected(), isConnecting(), isConnected(), isStatusError()
Providers
- `<AppProvider>` — Convenience wrapper (recommended). Auto-wires ConnectorProvider, WalletConnect, error boundaries.
- `<ConnectorProvider>` — Lower-level, accepts
configandmobileprops. - `<ConnectorErrorBoundary>` — Catches errors in connector tree.
Reference Files
- [Hooks & Elements API](references/api.md) — All hooks with return types, all elements with props
- [Connector Package README](../packages/connector/README.md) — WalletConnect QR, RPC proxy pattern,
imageProxy, CoinGecko config, headless examples - [Next.js Example Providers](../examples/next-js/app/providers.tsx) — End-to-end Next.js provider wiring (clusters, WalletConnect, remote signer, devtools)
- [Remote & Server Signing](references/remote-signer.md) — Remote wallet adapter, server route handlers, Fireblocks/Privy/custom provider setup
- [Migration Guide](references/migration.md) — Compat bridge details, wallet-adapter to connector migration steps
Hooks & Elements API Reference
Table of Contents
Wallet Hooks
useWallet()
Primary wallet status hook.
const {
status, // 'disconnected' | 'connecting' | 'connected' | 'error'
isConnected, // boolean
isConnecting, // boolean
isError, // boolean
error, // Error | null
connectorId, // WalletConnectorId | null
account, // Address | null (selected account)
accounts, // SessionAccount[]
session, // WalletSession | null
} = useWallet();useConnectWallet()
const {
connect, // (connectorId: WalletConnectorId, options?: ConnectOptions) => Promise<void>
isConnecting, // boolean
error, // Error | null
resetError, // () => void
} = useConnectWallet();
// ConnectOptions:
// { silent?: boolean, allowInteractiveFallback?: boolean, preferredAccount?: Address }useDisconnectWallet()
const { disconnect, isDisconnecting } = useDisconnectWallet();useWalletConnectors()
Returns available wallets for connection.
const connectors: WalletConnectorMetadata[] = useWalletConnectors();
// Each: { id, name, icon, ready, chains, features }useWalletInfo()
const {
name, // string | null
icon, // string | null
installed, // boolean
connectable, // boolean
connected, // boolean
connecting, // boolean
wallets, // WalletDisplayInfo[]
} = useWalletInfo();useAccount()
const { account, address, label, isLoading, error } = useAccount();Data Hooks
useBalance(options?)
const {
solBalance, // number
lamports, // bigint
formattedSol, // string
tokens, // TokenBalance[]
isLoading, // boolean
isError, // boolean
error, // Error | null
refetch, // () => Promise<void>
} = useBalance();useTransactions(options?)
const { transactions, isLoading, isError, error, refetch } = useTransactions();
// Each tx: { signature, timestamp, status, method, metadata }useTokens(options?)
const { tokens, isLoading, isError, error } = useTokens();
// Each: { mint, symbol, decimals, balance, price, ... }useCluster()
const {
cluster, // SolanaCluster | null
clusters, // SolanaCluster[]
setCluster, // (id: SolanaClusterId) => Promise<void>
isMainnet, // boolean
isDevnet, // boolean
isTestnet, // boolean
isLocal, // boolean
explorerUrl, // string
} = useCluster();Transaction Hooks
useTransactionSigner()
Legacy web3.js compatible signer.
const { signer, ready, address, capabilities } = useTransactionSigner()
// signer methods:
signer.signTransaction(tx)
signer.signAllTransactions(txs)
signer.signAndSendTransaction(tx, options?)
signer.signAndSendTransactions(txs, options?)
signer.signMessage?(msg) // optional capability
signer.getCapabilities() // { canSign, canSend, canSignMessage, supportsBatchSigning }useKitTransactionSigner()
@solana/kit / @solana/signers compatible signer.
const { signer, ready } = useKitTransactionSigner();
// signer is TransactionModifyingSigner — compatible with @solana/kit pipelinesuseTransactionPreparer()
Add blockhash + compute units to a transaction message.
const { prepare, ready } = useTransactionPreparer()
const prepared = await prepare(transactionMessage, options?)
// Returns tx with BlockhashLifetime attacheduseSolanaClient() / useKitSolanaClient()
Get a @solana/kit SolanaClient instance.
const { client, ready, clusterType } = useSolanaClient();
// client.rpc — RPC methods
// client.rpcSubscriptions — subscription methodsUtility Hooks
useConnector()
Access full provider snapshot.
const snapshot: ConnectorSnapshot = useConnector();useConnectorClient()
Get raw ConnectorClient instance.
const client: ConnectorClient | null = useConnectorClient();Query Cache Helpers
getBalanceQueryKey(rpcUrl, address);
getTransactionsQueryKey(options);
getWalletAssetsQueryKey(rpcUrl, address);
invalidateSharedQuery(key);
clearSharedQueryCache();Element Components
All elements support default rendering and custom render props.
WalletListElement
<WalletListElement
installedOnly? // boolean — only show installed wallets
variant? // string
className? // string
showStatus? // boolean
onConnect? // (connectorId) => void
render? // ({ wallets, installedWallets, connectById, connecting }) => ReactNode
renderWallet? // (wallet) => ReactNode
/>AccountElement
<AccountElement
showAvatar? // boolean
showCopy? // boolean
showFullAddress? // boolean
avatarSize? // number
variant? // string
className? // string
render? // ({ address, formatted, walletName, walletIcon, copy, copied }) => ReactNode
/>ClusterElement
<ClusterElement
variant? // string
className? // string
onClusterChange? // (cluster) => void
render? // ({ cluster, clusters, setCluster, explorerUrl }) => ReactNode
/>DisconnectElement
<DisconnectElement
variant? // string
className? // string
onDisconnect? // () => void
render? // ({ disconnect, disconnecting }) => ReactNode
/>BalanceElement
<BalanceElement
showTokens? // boolean
variant? // string
className? // string
enabled? // boolean
render? // ({ solBalance, tokens, isLoading, refetch }) => ReactNode
/>TransactionHistoryElement
<TransactionHistoryElement
limit? // number
variant? // string
className? // string
render? // ({ transactions, isLoading, explorerUrl }) => ReactNode
/>TokenListElement
<TokenListElement
variant? // string
className? // string
filter? // (token) => boolean
render? // ({ tokens, isLoading, selected, setSelected }) => ReactNode
/>SkeletonShine
Loading placeholder component.
Configuration
getDefaultConfig(options)
getDefaultConfig({
appName: string, // required
appUrl?: string,
autoConnect?: boolean,
debug?: boolean,
network?: 'mainnet' | 'devnet' | 'testnet' | 'localnet',
enableMobile?: boolean,
clusters?: SolanaCluster[],
customClusters?: SolanaCluster[],
persistClusterSelection?: boolean,
enableErrorBoundary?: boolean, // default: true
walletConnect?: boolean | { projectId },
additionalWallets?: Wallet[],
wallets?: WalletDisplayConfig, // { allow?, deny?, featured? }
coingecko?: CoinGeckoConfig,
imageProxy?: string,
programLabels?: Record<string, string>,
storage?: { account, cluster, wallet },
onError?: (error, errorInfo) => void,
})ConnectorConfig (low-level)
new ConnectorClient({
autoConnect?: boolean,
debug?: boolean,
wallets?: WalletDisplayConfig,
storage?: { account, cluster, wallet },
cluster?: { clusters, initialCluster, persistSelection },
imageProxy?: string,
programLabels?: Record<string, string>,
coingecko?: CoinGeckoConfig,
walletConnect?: WalletConnectConfig,
additionalWallets?: Wallet[],
})ConnectorClient Methods
client.connectWallet(connectorId, options?)
client.disconnectWallet()
client.getConnector(connectorId)
client.setCluster(clusterId)
client.getCluster()
client.getClusters()
client.getRpcUrl()
client.subscribe(listener) // returns unsubscribe fn
client.getSnapshot()
client.resetStorage()
client.emitEvent(event)Migration from @solana/wallet-adapter
Table of Contents
Overview
ConnectorKit provides two migration paths from @solana/wallet-adapter:
1. Compat bridge — Drop-in compatibility layer. Keep existing wallet-adapter code working while adopting ConnectorKit incrementally. 2. Full migration — Replace wallet-adapter hooks and components entirely.
Compat Bridge (Incremental)
Import from @solana/connector/compat:
import { useTransactionSigner, useDisconnectWallet } from '@solana/connector'
import { useWalletAdapterCompat } from '@solana/connector/compat'
function LegacyComponent() {
const { signer } = useTransactionSigner()
const { disconnect } = useDisconnectWallet()
// Creates a wallet-adapter compatible object
const wallet = useWalletAdapterCompat(signer, disconnect)
// Use with existing wallet-adapter code:
wallet.publicKey // string | null
wallet.connected // boolean
wallet.connecting // boolean
wallet.disconnecting // boolean
wallet.signTransaction(tx)
wallet.signAllTransactions(txs)
wallet.sendTransaction(tx, connection, options?)
wallet.signMessage?(msg)
wallet.connect()
wallet.disconnect()
}Factory function (non-React)
import { createWalletAdapterCompat } from '@solana/connector/compat';
const compat = createWalletAdapterCompat(signer, {
disconnect: () => client.disconnectWallet(),
transformTransaction: tx => tx, // optional transform
onError: (error, operation) => {}, // optional error handler
});Type guard
import { isWalletAdapterCompatible } from '@solana/connector/compat';
if (isWalletAdapterCompatible(obj)) {
obj.signTransaction(tx);
}Full Migration
1. Replace providers
- import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'
- import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'
+ import { AppProvider, getDefaultConfig } from '@solana/connector'
- <ConnectionProvider endpoint={rpcUrl}>
- <WalletProvider wallets={wallets} autoConnect>
- <WalletModalProvider>
- <App />
- </WalletModalProvider>
- </WalletProvider>
- </ConnectionProvider>
+ <AppProvider connectorConfig={getDefaultConfig({ appName: 'My App', autoConnect: true })}>
+ <App />
+ </AppProvider>2. Replace hooks
- import { useWallet, useConnection } from '@solana/wallet-adapter-react'
+ import { useWallet, useConnectWallet, useDisconnectWallet, useTransactionSigner } from '@solana/connector'
- const { publicKey, connected, signTransaction, sendTransaction } = useWallet()
+ const { status, account } = useWallet()
+ const { signer } = useTransactionSigner()
- if (connected && publicKey) { ... }
+ if (status === 'connected' && account) { ... }
- await signTransaction(tx)
+ await signer.signTransaction(tx)
- await sendTransaction(tx, connection)
+ await signer.signAndSendTransaction(tx)3. Replace wallet button
- import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'
- <WalletMultiButton />
+ import { WalletListElement, AccountElement, DisconnectElement } from '@solana/connector'
+ <WalletListElement />
+ <AccountElement showAvatar showCopy />
+ <DisconnectElement />API Mapping
| wallet-adapter | ConnectorKit |
|---|---|
useWallet() | useWallet() + useTransactionSigner() |
useConnection() | useSolanaClient() |
wallet.publicKey | useWallet().account |
wallet.connected | useWallet().status === 'connected' |
wallet.signTransaction | useTransactionSigner().signer.signTransaction |
wallet.sendTransaction | useTransactionSigner().signer.signAndSendTransaction |
wallet.signMessage | useTransactionSigner().signer.signMessage |
wallet.select(name) | useConnectWallet().connect(connectorId) |
wallet.disconnect() | useDisconnectWallet().disconnect() |
WalletMultiButton | WalletListElement + AccountElement |
WalletModalProvider | AppProvider (built-in) |
ConnectionProvider | AppProvider with getDefaultConfig({ network }) |
Remote & Server Signing
Table of Contents
- Overview
- Browser-Side Remote Wallet
- Server-Side Route Handlers
- Provider Configurations
- Custom Provider
- Protocol Types
- Security
Overview
ConnectorKit supports remote signing where the private key lives on a server (custodial wallet, MPC, HSM). Two entry points work together:
@solana/connector/remote— Creates a Wallet Standard wallet in the browser that delegates signing to an API@solana/connector/server— Provides Next.js-compatible route handlers that perform the actual signing
Browser-Side Remote Wallet
import { createRemoteSignerWallet } from '@solana/connector/remote';
const remoteWallet = createRemoteSignerWallet({
endpoint: '/api/signer', // API route URL
name: 'Treasury Wallet', // Display name in wallet list
icon: 'https://...', // Optional icon URL
chains: ['solana:mainnet'], // Optional chain filter
getAuthHeaders: () => ({
// Optional auth
Authorization: `Bearer ${token}`,
}),
});
// Add to connector config
const config = getDefaultConfig({
appName: 'My App',
additionalWallets: [remoteWallet],
});The remote wallet appears in useWalletConnectors() like any other wallet. Users connect to it the same way.
Server-Side Route Handlers
// app/api/signer/route.ts (Next.js App Router)
import { createRemoteSignerRouteHandlers } from '@solana/connector/server';
const { GET, POST } = createRemoteSignerRouteHandlers({
provider: {
/* Fireblocks, Privy, or custom */
},
authorize: async request => {
// Validate the request (check JWT, session, etc.)
return true;
},
policy: {
validateTransaction: async (bytes, request) => {
// Inspect transaction before signing
return true;
},
validateMessage: async (bytes, request) => true,
},
rpc: {
endpoint: process.env.RPC_URL, // Required for signAndSend
},
chains: ['solana:mainnet'],
name: 'Treasury Wallet',
});
export { GET, POST };GET returns wallet metadata (address, capabilities). POST handles sign operations.
Provider Configurations
Fireblocks
provider: {
type: 'fireblocks',
apiKey: process.env.FIREBLOCKS_API_KEY,
privateKeyPem: process.env.FIREBLOCKS_PRIVATE_KEY, // RSA key for JWT auth
vaultAccountId: process.env.FIREBLOCKS_VAULT_ID,
assetId: 'SOL', // default
apiBaseUrl: '...', // optional, for sandbox
}Privy
provider: {
type: 'privy',
appId: process.env.PRIVY_APP_ID,
appSecret: process.env.PRIVY_APP_SECRET,
walletId: process.env.PRIVY_WALLET_ID,
apiBaseUrl: '...', // optional
}Custom Provider
Implement the RemoteSigner interface:
interface RemoteSigner {
address: string
signTransaction(bytes: Uint8Array): Promise<Uint8Array>
signAllTransactions(txs: Uint8Array[]): Promise<Uint8Array[]>
signMessage(msg: Uint8Array): Promise<Uint8Array> // 64-byte ed25519 sig
isAvailable(): Promise<boolean>
}
provider: {
type: 'custom',
signer: myRemoteSigner,
}Protocol Types
The remote signer uses a JSON protocol over HTTP.
Request operations:
signTransaction—{ operation, transaction: base64 }signAllTransactions—{ operation, transactions: base64[] }signMessage—{ operation, message: base64 }signAndSendTransaction—{ operation, transaction: base64, options? }
Success responses:
{ signedTransaction: base64 }{ signedTransactions: base64[] }{ signature: base64 }
Error response:
{ error: RemoteSignerErrorCode, message: string }
Utilities (from @solana/connector/remote):
encodeBase64(data): stringdecodeBase64(encoded): Uint8ArrayisErrorResponse(response): boolean
Security
- Always implement
authorizeto validate requests (JWT, session, API key) - Use
policy.validateTransactionto inspect transactions before signing (whitelist programs, check amounts) - The server handler never exposes private keys to the browser
- Use HTTPS in production
- Consider rate limiting the signing endpoint