cashtab-connect
v1.1.0
Published
A developer-friendly API for integrating with the Cashtab browser extension
Maintainers
Readme
Cashtab Connect
A developer-friendly API for integrating with the Cashtab browser extension. This library provides a clean, TypeScript-first interface for requesting user addresses and creating transactions through the Cashtab wallet extension.
Installation
npm install cashtab-connectyarn add cashtab-connectQuick Start
import { CashtabConnect } from 'cashtab-connect';
// Create an instance
const cashtab = new CashtabConnect();
// Wait for the extension to become available
async function initializeCashtab() {
try {
await cashtab.waitForExtension();
console.log('Cashtab extension is available!');
// Now you can safely use the extension
const address = await cashtab.requestAddress();
console.log('User address:', address);
} catch (error) {
console.error('Extension not available:', error.message);
}
}
// Initialize when your app loads
await initializeCashtab();API Reference
CashtabConnect Class
The main class for interacting with the Cashtab extension.
Constructor
new CashtabConnect(options?: CashtabConnectOptions)Options:
timeout(number): Timeout in milliseconds for address requests (default: 30000)extensionNotAvailableMessage(string): Custom error message when extension is not availableaddressDeniedMessage(string): Custom error message when user denies address request
Methods
waitForExtension(timeout?: number): Promise<void>
Wait for the Cashtab extension to become available. This is the recommended way to check for extension availability.
Parameters:
timeout(number): Maximum time to wait in milliseconds (default: 3000). In practice this usually takes less than 1s.
Returns: Promise that resolves when extension is available or rejects on timeout.
Example:
try {
await cashtab.waitForExtension();
console.log('Extension is ready!');
} catch (error) {
console.log('Extension not available within timeout');
}isExtensionAvailable(): Promise<boolean>
Check if the extension is currently available without waiting.
Returns: Promise that resolves to true if extension is available, false otherwise.
Example:
const isAvailable = await cashtab.isExtensionAvailable();
if (isAvailable) {
// Extension is ready to use
} else {
// Extension is not available
}requestAddress(): Promise<string>
Request the user's eCash address from their Cashtab wallet.
Returns: Promise that resolves with the user's address or rejects with an error.
Throws:
ExtensionNotAvailableError: When the Cashtab extension is not availableAddressRequestDeniedError: When the user denies the address request (includes reason)AddressRequestTimeoutError: When the request times out
Example:
try {
const address = await cashtab.requestAddress();
console.log('User address:', address);
} catch (error) {
if (error instanceof CashtabExtensionUnavailableError) {
console.log('Please install the Cashtab extension');
} else if (error instanceof CashtabAddressDeniedError) {
console.log('User denied address request');
}
}sendXec(address: string, amount: string | number): Promise<void>
Send XEC to an address using Cashtab (dev-friendly).
Parameters:
address(string): Recipient's eCash addressamount(string | number): Amount to send in XEC
Throws:
CashtabExtensionUnavailableError: When the Cashtab extension is not available
Example:
cashtab.sendXec('ecash:qp3wj05au4l7q2m5ng4qg0vpeejl42lvl0nqj8q0q0', '1000.12');Error Classes
CashtabExtensionUnavailableError
Thrown when the Cashtab extension is not available.
CashtabAddressDeniedError
Thrown when the user denies an address request.
CashtabTimeoutError
Thrown when an address request times out.
Advanced Usage
Custom Instance
Create a custom instance with specific timeout:
import { CashtabConnect } from 'cashtab-connect';
const cashtab = new CashtabConnect(60000); // 60 second timeout for address requestsError Handling
Comprehensive error handling example:
import {
CashtabConnect,
CashtabExtensionUnavailableError,
CashtabAddressDeniedError,
CashtabTimeoutError,
} from 'cashtab-connect';
async function requestUserAddress() {
const cashtab = new CashtabConnect();
try {
const address = await cashtab.requestAddress();
return address;
} catch (error) {
if (error instanceof CashtabExtensionUnavailableError) {
// Show installation instructions
showInstallationInstructions();
} else if (error instanceof CashtabAddressDeniedError) {
// Show alternative payment methods
showAlternativePaymentMethods();
} else if (error instanceof CashtabTimeoutError) {
// Retry or show timeout message
showTimeoutMessage();
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
}
throw error;
}
}Browser Compatibility
This library works in all modern browsers that support:
- ES2020 features
- TypeScript
- Browser extensions (Chrome, Firefox, Edge)
Prerequisites
- The Cashtab browser extension must be installed and active
- The extension injects a global flag
window.bitcoinAbc = 'cashtab'when available
Security Considerations
- User Consent: All address requests require explicit user approval through a popup
- Transaction Review: Transaction creation opens Cashtab for user review before sending
- Origin Validation: The extension only accepts messages from the same window
Troubleshooting
Extension Not Detected
- Ensure the Cashtab extension is installed
- Check that the extension is enabled
- Verify the extension is compatible with your browser
- Use
waitForExtension()instead of checking availability immediately on page load
Address Request Fails
- Check that the user approves the request in the popup
- Verify the extension is available before making requests using
waitForExtension() - Handle timeout errors appropriately
Transaction Not Opening
- Check that the address and amount parameters are valid
- Ensure the extension is available using
waitForExtension() - Verify the address format is correct
Examples
React Component
import React, { useEffect, useState } from 'react';
import {
CashtabConnect,
CashtabExtensionUnavailableError,
CashtabAddressDeniedError,
CashtabTimeoutError,
} from 'cashtab-connect';
function CashtabIntegration() {
const [address, setAddress] = useState<string | null>(null);
const [isExtensionAvailable, setIsExtensionAvailable] = useState(false);
const [isCheckingExtension, setIsCheckingExtension] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const [addressResult, setAddressResult] = useState<{
message: string;
type: 'success' | 'error';
} | null>(null);
// Initialize CashtabConnect in state
const [cashtab] = useState(() => new CashtabConnect());
// Check extension availability on mount
useEffect(() => {
const checkAvailability = async () => {
try {
await cashtab.waitForExtension();
setIsExtensionAvailable(true);
setIsCheckingExtension(false);
} catch (error) {
console.log('Extension not available after waiting:', error);
setIsCheckingExtension(false);
}
};
checkAvailability();
}, [cashtab]);
const handleRequestAddress = async () => {
setIsLoading(true);
setAddressResult(null);
try {
const userAddress = await cashtab.requestAddress();
setAddress(userAddress);
setAddressResult({
message: `Address received: ${userAddress}`,
type: 'success',
});
} catch (error) {
let errorMessage = 'Unknown error occurred';
if (error instanceof CashtabExtensionUnavailableError) {
errorMessage = 'Extension is not available';
} else if (error instanceof CashtabAddressDeniedError) {
errorMessage = 'User denied the address request';
} else if (error instanceof CashtabTimeoutError) {
errorMessage = 'Address request timed out';
} else if (error instanceof Error) {
errorMessage = error.message;
}
setAddressResult({ message: errorMessage, type: 'error' });
} finally {
setIsLoading(false);
}
};
const handleSendXec = () => {
cashtab.sendXec(
'ecash:qp3wj05au4l7q2m5ng4qg0vpeejl42lvl0nqj8q0q0',
'1000.12',
);
};
if (isCheckingExtension) {
return <div>Checking for Cashtab extension...</div>;
}
return (
<div>
<p>
Cashtab Extension:{' '}
{isExtensionAvailable ? 'Available' : 'Not Available'}
</p>
{address && <p>User Address: {address}</p>}
{addressResult && (
<p
style={{
color:
addressResult.type === 'success' ? 'green' : 'red',
}}
>
{addressResult.message}
</p>
)}
<button
onClick={handleRequestAddress}
disabled={!isExtensionAvailable || isLoading}
>
{isLoading ? 'Requesting...' : 'Request Address'}
</button>
<button onClick={handleSendXec} disabled={!isExtensionAvailable}>
Send XEC
</button>
</div>
);
}Development
Running Tests
npm testRunning the Demo
The library includes a React demo application that showcases all features:
npm startThen open http://localhost:3000 in your browser. The demo requires the Cashtab browser extension to be installed.
The React demo demonstrates:
- Extension status detection
- Address requests with network selection
- Transaction creation with form validation
- Error handling for various scenarios
- Real-time event logging
- Both class-based and convenience function usage patterns
See the demo README for more details.
Building
npm run buildLinting
npm run lintChangelog
- 1.1.0 - Add transaction approval/rejection support for transactions. Extension transactions send responses back to the originating webpage. D18348
License
MIT License - see COPYING file at top level of the monorepo for details.
Support
For support, please visit the Cashtab documentation or GitHub repository.
