Toto Wallet System Integration Guide
This guide explains how to integrate the Toto Wallet System into your Next.js application.
Installationβ
npm install @toto/wallet-system
Basic Setupβ
Wrap your application with the WalletProvider component to provide wallet functionality throughout your app:
// In your _app.tsx or similar root component:
import { WalletProvider } from '@toto/wallet-system';
function MyApp({ Component, pageProps }) {
// Handle wallet events (optional)
const handleWalletEvent = (event) => {
console.log('Wallet event:', event.type, event.data);
// Perform actions based on event type
if (event.type === 'wallet-created') {
// Store the public key in your database
}
};
return (
<WalletProvider
moonPayApiKey="your_moonpay_public_api_key"
stellarNetwork="testnet" // or 'public' for production
onWalletEvent={handleWalletEvent}
>
<Component {...pageProps} />
</WalletProvider>
);
}
export default MyApp;
Wallet Creationβ
The Toto Wallet System provides a functional approach to wallet creation that allows for automatic wallet creation during transaction flows.
Functional Wallet Creation APIβ
Use the useAutoWalletCreation hook to ensure a wallet exists before proceeding with operations:
import { useAutoWalletCreation } from '@toto/wallet-system';
function DonationComponent() {
const { ensureWalletExists, hasWallet, isCreatingWallet } = useAutoWalletCreation();
const handleDonation = async () => {
try {
// This will create a wallet if one doesn't exist
const wallet = await ensureWalletExists((newWallet) => {
// This callback is only called if a new wallet was created
// Store the mnemonic securely or display it to the user
console.log('New wallet created with key:', newWallet.publicKey);
console.log('Mnemonic phrase:', newWallet.mnemonic);
});
// At this point we have a wallet (either pre-existing or newly created)
console.log('Using wallet with public key:', wallet.publicKey);
// Now proceed with the donation or other operation
} catch (error) {
console.error('Error during wallet creation:', error);
}
};
return (
<div>
<button
onClick={handleDonation}
disabled={isCreatingWallet}
>
{isCreatingWallet ? 'Creating Wallet...' : 'Donate Now'}
</button>
</div>
);
}
Checking Account Balanceβ
Use the useAccountBalance hook to display a user's XLM balance:
import { useAccountBalance } from '@toto/wallet-system';
function BalanceDisplay({ publicKey }) {
const { balance, isLoading, error, refetch } = useAccountBalance(publicKey);
if (isLoading) {
return <div>Loading balance...</div>;
}
if (error) {
return (
<div>
Error loading balance: {error.message}
<button onClick={() => refetch()}>Retry</button>
</div>
);
}
if (!balance) {
return <div>No balance information available</div>;
}
return (
<div>
<h2>Your Balance</h2>
<p>{balance.xlm} XLM</p>
<p>Account status: {balance.isActivated ? 'Active' : 'Not activated'}</p>
<button onClick={() => refetch()}>Refresh</button>
</div>
);
}
Adding Funds with MoonPayβ
Use the MoonPayLoader component to allow users to add funds to their wallet:
import { MoonPayLoader } from '@toto/wallet-system';
function AddFundsPage({ publicKey }) {
const handleMoonPaySuccess = (data) => {
console.log('MoonPay transaction completed:', data);
// Update your UI or redirect the user
};
const handleMoonPayError = (error) => {
console.error('MoonPay error:', error);
// Show error message to user
};
return (
<div>
<h1>Add Funds to Your Wallet</h1>
<MoonPayLoader
publicKey={publicKey}
onSuccess={handleMoonPaySuccess}
onError={handleMoonPayError}
defaultFiatCurrency="USD"
defaultFiatAmount="50"
className="moonpay-container"
/>
</div>
);
}
Making Donationsβ
Use the DonationModal component and the useSubmitDonation hook to facilitate donations:
import { DonationModal, useSubmitDonation } from '@toto/wallet-system';
import { useState } from 'react';
function DonationPage({ userPublicKey, guardianPublicKey, campaignId }) {
const [showModal, setShowModal] = useState(false);
const { submitDonation, isLoading, error } = useSubmitDonation();
const handleDonation = async (amount, secretKey) => {
try {
const transactionId = await submitDonation({
amount,
recipientPublicKey: guardianPublicKey,
memo: `Campaign-${campaignId}`
}, secretKey);
console.log('Donation sent! Transaction ID:', transactionId);
setShowModal(false);
// Show success message or redirect
} catch (err) {
console.error('Donation failed:', err);
// Error is already handled by the hook
}
};
return (
<div>
<h1>Support This Campaign</h1>
<button onClick={() => setShowModal(true)}>Donate XLM</button>
{showModal && (
<DonationModal
recipientPublicKey={guardianPublicKey}
onSubmit={handleDonation}
onCancel={() => setShowModal(false)}
memo={`Campaign-${campaignId}`}
/>
)}
</div>
);
}
Transaction Historyβ
Use the useTransactionHistory hook to display a user's transaction history:
import { useTransactionHistory } from '@toto/wallet-system';
function TransactionHistoryPage({ publicKey }) {
const { transactions, isLoading, error, refetch } = useTransactionHistory(publicKey);
if (isLoading) {
return <div>Loading transactions...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<div>
<h1>Transaction History</h1>
<button onClick={refetch}>Refresh</button>
{transactions.length === 0 ? (
<p>No transactions found.</p>
) : (
<ul>
{transactions.map(tx => (
<li key={tx.id}>
<strong>{tx.type}</strong>: {tx.amount} {tx.assetCode}
<div>Date: {tx.timestamp.toLocaleDateString()}</div>
<div>To: {tx.to}</div>
{tx.memo && <div>Memo: {tx.memo}</div>}
</li>
))}
</ul>
)}
</div>
);
}
Advanced Usageβ
Direct Context Accessβ
For more advanced use cases, you can access the wallet context directly using the useStellarWallet hook:
import { useStellarWallet } from '@toto/wallet-system';
function AdvancedWalletComponent() {
const {
stellarNetwork,
publicKey,
balance,
transactions,
loading,
errors,
createWallet,
checkBalance,
submitDonation,
fetchTransactions,
clearError
} = useStellarWallet();
// Now you have access to all wallet functions and state
// ...
}
Customizing Stylesβ
All components accept a className prop that you can use to apply your own styling:
<CreateWalletButton className="my-custom-button" />
To comprehensively style the components, you can also override the default classes in your CSS:
/* Override default styles */
.toto-wallet-button {
/* Your custom button styles */
}
.toto-wallet-error-message {
/* Your custom error message styles */
}
/* And so on for other components */
Error Handlingβ
The wallet system provides a centralized error handling mechanism. Errors are stored in the context and can be accessed via the errors object:
const { errors, clearError } = useStellarWallet();
// Check for specific errors
if (errors.createWallet) {
// Handle wallet creation error
console.error(errors.createWallet);
// Clear the error when no longer needed
clearError('createWallet');
}
Best Practicesβ
-
Security: Never store or transmit users' private keys or mnemonic phrases to your server. These should remain exclusively on the client side.
-
User Education: Clearly instruct users to securely back up their mnemonic phrases. Emphasize that if they lose their mnemonic, their funds cannot be recovered.
-
Network Selection: Use the
stellarNetwork="testnet"setting during development and testing. Switch tostellarNetwork="public"for production. -
Error Handling: Always implement proper error handling for wallet operations to provide clear feedback to users.
-
Recovery Flow: Implement a recovery flow that allows users to restore their wallet using their mnemonic phrase.
Automatic Wallet Creation During Transactionsβ
For applications where wallet creation should occur automatically as part of another transaction flow (like donations or top-ups), you can use the functional approach instead of the button component.
Using with MoonPay Top-Upβ
For MoonPay top-up integration, ensure a wallet exists before loading the MoonPay widget:
import { useAutoWalletCreation, MoonPayLoader } from '@toto/wallet-system';
function TopUpComponent() {
const [showMoonPay, setShowMoonPay] = useState(false);
const { publicKey } = useStellarWallet();
const { ensureWalletExists, isCreatingWallet } = useAutoWalletCreation();
const handleTopUp = async () => {
try {
// Ensure wallet exists before proceeding to MoonPay
await ensureWalletExists();
setShowMoonPay(true);
} catch (error) {
console.error('Error preparing for top-up:', error);
}
};
return (
<div>
<button
onClick={handleTopUp}
disabled={isCreatingWallet}
>
{isCreatingWallet ? 'Creating Wallet...' : 'Top Up with MoonPay'}
</button>
{showMoonPay && publicKey && (
<MoonPayLoader
publicKey={publicKey}
onSuccess={(event) => console.log('MoonPay success:', event)}
onError={(error) => console.error('MoonPay error:', error)}
/>
)}
</div>
);
}
Advantages of the Functional Approachβ
The functional approach offers several advantages over the component-based approach:
- Seamless integration with existing flows: Wallet creation becomes part of your application's existing flows rather than a separate action.
- Reduced UI complexity: No need for a dedicated wallet creation button or screen.
- Improved user experience: Users don't need to explicitly create a wallet before using your application.
- More control over the wallet creation process: You decide exactly when and how wallet creation happens.
Functional Wallet Creation APIβ
Use the useAutoWalletCreation hook to ensure a wallet exists before proceeding with operations:
import { useAutoWalletCreation } from '@toto/wallet-system';
function DonationComponent() {
const { ensureWalletExists, hasWallet, isCreatingWallet } = useAutoWalletCreation();
const handleDonation = async () => {
try {
// This will create a wallet if one doesn't exist
const wallet = await ensureWalletExists((newWallet) => {
// This callback is only called if a new wallet was created
// Store the mnemonic securely or display it to the user
console.log('New wallet created with key:', newWallet.publicKey);
console.log('Mnemonic phrase:', newWallet.mnemonic);
});
// At this point we have a wallet (either pre-existing or newly created)
console.log('Using wallet with public key:', wallet.publicKey);
// Now proceed with the donation or other operation
} catch (error) {
console.error('Error during wallet creation:', error);
}
};
return (
<div>
<button
onClick={handleDonation}
disabled={isCreatingWallet}
>
{isCreatingWallet ? 'Creating Wallet...' : 'Donate Now'}
</button>
</div>
);
}
Checking Account Balanceβ
Use the useAccountBalance hook to display a user's XLM balance:
import { useAccountBalance } from '@toto/wallet-system';
function BalanceDisplay({ publicKey }) {
const { balance, isLoading, error, refetch } = useAccountBalance(publicKey);
if (isLoading) {
return <div>Loading balance...</div>;
}
if (error) {
return <div>Error loading balance: {error.message}</div>;
}
return (
<div>
<p>Balance: {balance} XLM</p>
<button onClick={refetch}>Refresh Balance</button>
</div>
);
}
Making Transactionsβ
Basic Transactionβ
import { useTransaction } from '@toto/wallet-system';
function SendTransaction({ recipient, amount }) {
const { sendTransaction, isProcessing, error } = useTransaction();
const handleSend = async () => {
try {
const result = await sendTransaction({
destination: recipient,
amount: amount,
memo: 'Donation for pet rescue'
});
console.log('Transaction successful:', result.hash);
} catch (error) {
console.error('Transaction failed:', error);
}
};
return (
<button onClick={handleSend} disabled={isProcessing}>
{isProcessing ? 'Processing...' : 'Send Transaction'}
</button>
);
}
Payment with MoonPayβ
import { useMoonPay } from '@toto/wallet-system';
function BuyXLM({ publicKey }) {
const { openMoonPay, isProcessing } = useMoonPay();
const handleBuy = () => {
openMoonPay({
walletAddress: publicKey,
currencyCode: 'XLM',
baseCurrencyAmount: '100', // USD amount
baseCurrencyCode: 'USD'
});
};
return (
<button onClick={handleBuy} disabled={isProcessing}>
Buy XLM with MoonPay
</button>
);
}
Advanced Featuresβ
Custom Transaction Builderβ
import { useTransactionBuilder } from '@toto/wallet-system';
function CustomTransaction() {
const { buildTransaction, signTransaction, submitTransaction } = useTransactionBuilder();
const handleCustomTransaction = async () => {
try {
// Build a custom transaction
const transaction = await buildTransaction({
operations: [
{
type: 'payment',
destination: 'RECIPIENT_ADDRESS',
asset: 'XLM',
amount: '10'
}
],
memo: 'Custom donation'
});
// Sign the transaction
const signedTransaction = await signTransaction(transaction);
// Submit the transaction
const result = await submitTransaction(signedTransaction);
console.log('Custom transaction successful:', result.hash);
} catch (error) {
console.error('Custom transaction failed:', error);
}
};
return (
<button onClick={handleCustomTransaction}>
Send Custom Transaction
</button>
);
}
Error Handlingβ
import { useWalletError } from '@toto/wallet-system';
function ErrorHandler() {
const { handleError, clearError, lastError } = useWalletError();
const handleTransactionError = (error) => {
handleError(error);
// Custom error handling logic
if (error.code === 'INSUFFICIENT_BALANCE') {
// Show buy XLM option
} else if (error.code === 'NETWORK_ERROR') {
// Show retry option
}
};
return (
<div>
{lastError && (
<div className="error-message">
<p>Error: {lastError.message}</p>
<button onClick={clearError}>Dismiss</button>
</div>
)}
</div>
);
}
Best Practicesβ
Securityβ
- Always store mnemonics securely
- Use environment variables for API keys
- Implement proper error handling
- Validate all user inputs
Performanceβ
- Cache account balances when possible
- Use optimistic updates for better UX
- Implement proper loading states
- Handle network connectivity issues
User Experienceβ
- Provide clear feedback for all actions
- Show transaction progress
- Implement retry mechanisms
- Use consistent error messaging
Configuration Optionsβ
Environment Variablesβ
NEXT_PUBLIC_MOONPAY_API_KEY=your_moonpay_public_key
NEXT_PUBLIC_STELLAR_NETWORK=testnet
NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org
Provider Configurationβ
<WalletProvider
moonPayApiKey={process.env.NEXT_PUBLIC_MOONPAY_API_KEY}
stellarNetwork={process.env.NEXT_PUBLIC_STELLAR_NETWORK}
horizonUrl={process.env.NEXT_PUBLIC_HORIZON_URL}
onWalletEvent={handleWalletEvent}
onError={handleError}
autoConnect={true}
enableLogging={process.env.NODE_ENV === 'development'}
>
{children}
</WalletProvider>
Troubleshootingβ
Common Issuesβ
-
Network Connection Errors
- Check internet connectivity
- Verify Horizon URL configuration
- Ensure proper network selection
-
MoonPay Integration Issues
- Verify API key configuration
- Check domain whitelist settings
- Ensure proper currency codes
-
Transaction Failures
- Check account balance
- Verify recipient address
- Ensure proper memo format
Debug Modeβ
Enable debug logging in development:
<WalletProvider
enableLogging={true}
debugMode={true}
>
{children}
</WalletProvider>
Supportβ
For additional support:
- Documentation: API Reference
- GitHub: Issues
- Community: Discussions
- Email: wallet-support@toto.com