Skip to main content

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​

  1. Security: Never store or transmit users' private keys or mnemonic phrases to your server. These should remain exclusively on the client side.

  2. User Education: Clearly instruct users to securely back up their mnemonic phrases. Emphasize that if they lose their mnemonic, their funds cannot be recovered.

  3. Network Selection: Use the stellarNetwork="testnet" setting during development and testing. Switch to stellarNetwork="public" for production.

  4. Error Handling: Always implement proper error handling for wallet operations to provide clear feedback to users.

  5. 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:

  1. Seamless integration with existing flows: Wallet creation becomes part of your application's existing flows rather than a separate action.
  2. Reduced UI complexity: No need for a dedicated wallet creation button or screen.
  3. Improved user experience: Users don't need to explicitly create a wallet before using your application.
  4. 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​

  1. Network Connection Errors

    • Check internet connectivity
    • Verify Horizon URL configuration
    • Ensure proper network selection
  2. MoonPay Integration Issues

    • Verify API key configuration
    • Check domain whitelist settings
    • Ensure proper currency codes
  3. 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: