@bitxpay/wallet-sdk
v0.2.1
Published
EIP-1193 provider SDK for integrating the BITXpay gasless wallet into any dApp. The wallet runs as an iframe overlay — your users authenticate with passkeys or passwords, and transactions are signed in an SGX enclave and relayed gaslessly.
Readme
@bitxpay/wallet-sdk
EIP-1193 provider SDK for integrating the BITXpay gasless wallet into any dApp. The wallet runs as an iframe overlay — your users authenticate with passkeys or passwords, and transactions are signed in an SGX enclave and relayed gaslessly.
Installation
npm install @bitxpay/wallet-sdk
# or
pnpm add @bitxpay/wallet-sdk
# or
yarn add @bitxpay/wallet-sdkPeer dependencies (optional):
npm install viem # Required only if using viem/wagmi directlyQuick Start
import { BITXpayProvider } from "@bitxpay/wallet-sdk";
const provider = new BITXpayProvider();
// Connect — opens wallet modal for authentication
const accounts = await provider.request({ method: "eth_requestAccounts" });
console.log("Connected:", accounts[0]);
// Sign a message
const signature = await provider.request({
method: "personal_sign",
params: ["0x48656c6c6f", accounts[0]],
});
// Send a gasless transaction
const txHash = await provider.request({
method: "eth_sendTransaction",
params: [{ to: "0xRecipient...", value: "0xde0b6b3a7640000", data: "0x" }],
});Configuration
const provider = new BITXpayProvider({
walletUrl: "https://wallet.bitxpay.com",
defaultChainId: 1,
displayMode: "modal",
rpcUrls: { 1: "https://my-rpc.example.com" },
onAccountId: () => "user-account-id",
});| Option | Type | Default | Description |
|--------|------|---------|-------------|
| walletUrl | string | "https://wallet.bitxpay.com" | URL of the wallet app iframe |
| defaultChainId | number | 1 | Initial chain ID |
| displayMode | "modal" \| "sidepanel" | "modal" | UI mode. Mobile always uses fullscreen modal |
| rpcUrls | Record<number, string> | Built-in defaults | Custom RPC URLs per chain (overrides defaults) |
| onAccountId | () => string \| Promise<string> | undefined | Callback to auto-fill account ID on connect |
Usage with Wagmi / RainbowKit
import { BITXpayProvider } from "@bitxpay/wallet-sdk";
import { createConnector } from "wagmi";
const bitxpayConnector = createConnector((config) => {
const provider = new BITXpayProvider({ displayMode: "sidepanel" });
return {
id: "bitxpay",
name: "BITXpay Wallet",
type: "injected",
async connect() {
const accounts = await provider.request({ method: "eth_requestAccounts" });
const chainId = await provider.request({ method: "eth_chainId" });
return { accounts, chainId: Number(chainId) };
},
async disconnect() {
await provider.disconnect();
},
async getAccounts() {
return provider.request({ method: "eth_accounts" }) as Promise<string[]>;
},
async getChainId() {
const hex = await provider.request({ method: "eth_chainId" }) as string;
return Number(hex);
},
async getProvider() {
return provider;
},
async isAuthorized() {
const accounts = await provider.request({ method: "eth_accounts" }) as string[];
return accounts.length > 0;
},
onAccountsChanged(callback) {
provider.on("accountsChanged", callback);
},
onChainChanged(callback) {
provider.on("chainChanged", (chainId) => callback(Number(chainId)));
},
onDisconnect(callback) {
provider.on("disconnect", callback);
},
};
});Supported RPC Methods
Standard EIP-1193
| Method | Description |
|--------|-------------|
| eth_requestAccounts | Connect wallet, returns string[] of addresses |
| eth_accounts | Get connected accounts (no prompt) |
| eth_chainId | Get current chain ID as hex |
| personal_sign | Sign a message, returns hex signature |
| eth_sign | Sign a message (params reversed from personal_sign) |
| eth_signTypedData_v4 | Sign EIP-712 typed data |
| eth_sendTransaction | Send gasless transaction via relayer, returns tx hash |
| eth_signTransaction | Sign transaction without broadcasting, returns signed tx |
EIP-5792 (Batch Calls)
| Method | Description |
|--------|-------------|
| wallet_sendCalls | Send atomic batch of calls, returns callsId |
| wallet_getCallsStatus | Get status of a batch by callsId |
| wallet_showCallsStatus | No-op (no status UI) |
| wallet_getCapabilities | Returns supported capabilities per chain |
Chain Management
| Method | Description |
|--------|-------------|
| wallet_switchEthereumChain | Switch active chain |
| wallet_addEthereumChain | Register a custom chain with RPC URL |
Permissions
| Method | Description |
|--------|-------------|
| wallet_getPermissions | Get granted permissions |
| wallet_requestPermissions | Request permissions (triggers connect if needed) |
| wallet_revokePermissions | Revoke permissions (disconnects) |
BITXpay Custom Methods
| Method | Description |
|--------|-------------|
| bitxpay_getSignedIntent | Sign an execution intent without relaying |
| bitxpay_getSignedBatchIntent | Sign a batch of execution intents without relaying |
| bitxpay_batchRequests | Execute multiple RPC requests in a single call |
Read Methods (proxied to RPC nodes)
eth_call, eth_estimateGas, eth_getBalance, eth_getBlockByHash, eth_getBlockByNumber, eth_getCode, eth_getTransactionByHash, eth_getTransactionCount, eth_getTransactionReceipt, eth_blockNumber, eth_gasPrice, eth_getStorageAt, eth_getLogs, eth_feeHistory, eth_maxPriorityFeePerGas, net_version, web3_clientVersion
Custom Methods API Reference
bitxpay_getSignedIntent
Signs a single execution intent and returns it without relaying. The dApp receives the signed intent and optional EIP-7702 authorization to relay independently.
Params:
[{
to: string; // Target address
value?: string; // ETH value in hex
data?: string; // Calldata hex
chainId?: string; // Chain ID hex (defaults to current chain)
}]Returns:
{
signedIntent: {
intent: {
nonce: string; // hex bigint
deadline: string; // hex bigint — expiration (unix seconds)
target: string; // address
value: string; // hex bigint
data: string; // hex calldata
};
signature: string; // EIP-712 hex signature
};
authorization?: { // Present if account needs EIP-7702 delegation
chainId: number;
contractAddress: string;
nonce: string; // hex bigint
yParity: number;
r: string;
s: string;
};
}Example:
const result = await provider.request({
method: "bitxpay_getSignedIntent",
params: [{
to: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
data: "0xa9059cbb000000000000000000000000...",
chainId: "0x1",
}],
});
// result.signedIntent → pass to RelayerClient.relay()
// result.authorization → pass to RelayerClient.relay() if presentbitxpay_getSignedBatchIntent
Signs multiple execution intents atomically and returns them without relaying. Each intent gets an incrementing nonce.
Params:
[{
calls: Array<{
to: string;
value?: string;
data?: string;
}>;
chainId?: string; // Chain ID hex (defaults to current chain)
}]Returns:
{
signedIntents: Array<{
intent: {
nonce: string;
deadline: string;
target: string;
value: string;
data: string;
};
signature: string;
}>;
authorization?: {
chainId: number;
contractAddress: string;
nonce: string;
yParity: number;
r: string;
s: string;
};
}Example:
const result = await provider.request({
method: "bitxpay_getSignedBatchIntent",
params: [{
calls: [
{ to: "0xA0b8...", data: "0xa9059cbb..." },
{ to: "0xB4e1...", data: "0x095ea7b3..." },
],
chainId: "0x2105", // Base
}],
});
// result.signedIntents → pass to RelayerClient.relayBatch()
// result.authorization → pass to RelayerClient.relayBatch() if presentbitxpay_batchRequests
Executes multiple RPC requests in a single call. Read methods are resolved via RPC in parallel. Signing methods go through the wallet approval UI.
Params:
[{
requests: Array<{
method: string;
params: unknown[];
}>;
}]Returns:
Array<{
success: boolean;
result?: unknown;
error?: { code: number; message: string };
}>Example:
const results = await provider.request({
method: "bitxpay_batchRequests",
params: [{
requests: [
{ method: "eth_getBalance", params: ["0xabc...", "latest"] },
{ method: "personal_sign", params: ["0x48656c6c6f", "0xabc..."] },
{ method: "eth_sendTransaction", params: [{ to: "0x...", value: "0x1" }] },
],
}],
});
// results[0] — balance (RPC proxy, no approval)
// results[1] — signature (required approval)
// results[2] — txHash (required approval)Events
provider.on("connect", (detail: { chainId: string }) => {
console.log("Connected to chain:", detail.chainId);
});
provider.on("accountsChanged", (accounts: string[]) => {
console.log("Accounts:", accounts);
});
provider.on("chainChanged", (chainId: string) => {
console.log("Chain changed:", chainId);
});
provider.on("disconnect", (error: ProviderRpcError) => {
console.log("Disconnected:", error.message);
});
// Remove a listener
provider.removeListener("accountsChanged", handler);Display Modes
| Mode | Desktop | Mobile (<480px) |
|------|---------|-----------------|
| "modal" | Centered overlay with backdrop blur | Fullscreen |
| "sidepanel" | 400px right-side panel with slide-in animation | Fullscreen (falls back) |
Both modes support Escape key to dismiss.
const provider = new BITXpayProvider({ displayMode: "sidepanel" });Script Tag / IIFE Usage
For apps that don't use a bundler, include the SDK as a script tag:
<script
src="https://cdn.bitxpay.io/sdk.js"
data-wallet-url="https://wallet.bitxpay.com"
data-chain-id="1"
data-display-mode="sidepanel"
data-account-id="user123"
></script>This auto-initializes the provider, sets window.ethereum, and announces via EIP-6963.
| Attribute | Description |
|-----------|-------------|
| data-wallet-url | Wallet iframe URL |
| data-chain-id | Default chain ID (decimal string) |
| data-display-mode | "modal" or "sidepanel" |
| data-account-id | Static account ID to auto-fill |
Browser extension usage:
// Content script sets config before injecting
window.__BITXPAY_CONFIG = {
walletUrl: "https://wallet.bitxpay.com",
defaultChainId: 1,
displayMode: "sidepanel",
};EIP-6963 Provider Discovery
import { initBITXpay, announceProvider, BITXpayProvider } from "@bitxpay/wallet-sdk";
// Option 1: All-in-one (creates provider, sets window.ethereum, announces)
const provider = initBITXpay({ displayMode: "sidepanel" });
// Option 2: Manual
const provider = new BITXpayProvider();
announceProvider(provider);Provider info announced:
- Name: BITXpay Wallet
- RDNS:
com.bitxpay.wallet
Supported Chains
| Chain | ID | Explorer | |-------|----|----------| | Ethereum | 1 | etherscan.io | | Optimism | 10 | optimistic.etherscan.io | | BNB Chain | 56 | bscscan.com | | Base | 8453 | basescan.org | | Arbitrum | 42161 | arbiscan.io |
Custom chains can be added at runtime:
await provider.request({
method: "wallet_addEthereumChain",
params: [{
chainId: "0x89",
chainName: "Polygon",
rpcUrls: ["https://polygon-rpc.com"],
}],
});Error Handling
import { ProviderRpcError, EIP1193_ERRORS, BITXPAY_ERRORS } from "@bitxpay/wallet-sdk";
try {
await provider.request({ method: "eth_sendTransaction", params: [tx] });
} catch (err) {
if (err instanceof ProviderRpcError) {
switch (err.code) {
case EIP1193_ERRORS.USER_REJECTED: // 4001
console.log("User rejected");
break;
case BITXPAY_ERRORS.SESSION_EXPIRED: // 5001
console.log("Session expired, reconnect");
break;
case BITXPAY_ERRORS.WALLET_TIMEOUT: // 5007
console.log("Wallet timed out");
break;
}
}
}EIP-1193 Error Codes
| Code | Constant | Description |
|------|----------|-------------|
| 4001 | USER_REJECTED | User rejected the request |
| 4100 | UNAUTHORIZED | Not connected |
| 4200 | UNSUPPORTED_METHOD | Method not supported |
| 4900 | DISCONNECTED | Provider disconnected |
| 4901 | CHAIN_DISCONNECTED | Chain disconnected |
| 4902 | UNRECOGNIZED_CHAIN | Chain not supported |
BITXpay Custom Error Codes
| Code | Constant | Description |
|------|----------|-------------|
| 5001 | SESSION_EXPIRED | JWT expired, reconnect required |
| 5002 | EPHEMERAL_KEY_MISSING | Ephemeral key unavailable |
| 5003 | SIGNING_FAILED | SGX signing operation failed |
| 5004 | RELAY_FAILED | Relayer rejected the transaction |
| 5005 | DELEGATION_FAILED | EIP-7702 delegation failed |
| 5006 | INVALID_ACCOUNT | Account ID not found |
| 5007 | WALLET_TIMEOUT | Wallet did not respond in time |
| 5008 | IFRAME_BLOCKED | Browser blocked the iframe |
| 5009 | WEBAUTHN_FAILED | Passkey authentication failed |
| 5010 | REAUTH_REQUIRED | Re-authentication needed |
| 5011 | CHAIN_NOT_SUPPORTED | Chain not in supported list |
| 5012 | INTERNAL_ERROR | Unexpected internal error |
Advanced APIs
These are exported for advanced use cases. Most dApps only need BITXpayProvider.
SessionManager
import { SessionManager } from "@bitxpay/wallet-sdk";
const session = new SessionManager();
session.isConnected(); // boolean
session.getAddress(); // string | null
session.getJwt(); // string | null
session.getAccountId(); // string | null
session.getChainId(); // number | null
session.clear(); // disconnectPersists to localStorage under the key "bitxpay:session".
RpcProxy
import { RpcProxy } from "@bitxpay/wallet-sdk";
const rpc = new RpcProxy({ 1: "https://my-rpc.example.com" });
const balance = await rpc.request(1, "eth_getBalance", ["0x...", "latest"]);
rpc.setRpcUrl(137, "https://polygon-rpc.com");ModalManager
import { ModalManager } from "@bitxpay/wallet-sdk";
const modal = new ModalManager("https://wallet.bitxpay.com", "sidepanel");
modal.open("/approve", () => console.log("dismissed"));
modal.isOpen; // boolean
modal.contentWindow; // WindowProxy | null
modal.close();TypeScript
All types are exported. Key types for consumers:
import type {
BITXpayConfig,
EIP1193RequestArgs,
DisplayMode,
SessionData,
// Message types
ConnectResponse,
SignatureResponse,
TransactionResponse,
SignIntentResponse,
SignBatchIntentResponse,
ErrorResponse,
// Serialization types
SerializedSignedIntent,
SerializedExecutionIntent,
SerializedAuthorization7702,
} from "@bitxpay/wallet-sdk";License
MIT
