Skip to main content

Embedded Wallets Integration

This guide walks you through integrating AxonVault embedded wallets into your web or mobile application using the SDK.

Overview

The AxonVault Embedded Wallet SDK provides a seamless way to add wallet functionality to your app:
  • Social Login: Users authenticate with Google, Apple, or Email
  • Automatic Wallet Creation: Wallets are created automatically for new users
  • Multi-Chain Support: EVM and Solana chains out of the box
  • Simple API: SDK handles all complexity

Installation

npm install @axonvault/embedded-wallet-sdk

Step 1: Configure Your Project

  1. Create a project in the AxonVault Dashboard
  2. Enable social login providers (Google, Apple)
  3. Configure allowed origins for your app
  4. Copy your Project ID

Step 2: Initialize the SDK

import { AxonVaultEmbedded } from '@axonvault/embedded-wallet-sdk';

// Initialize SDK
const axonVault = new AxonVaultEmbedded({
  projectId: 'proj_abc123',
  environment: 'production' // or 'development'
});

Step 3: Implement Authentication

Google Sign-In

import { GoogleLogin } from '@react-oauth/google';

function LoginButton() {
  const handleGoogleLogin = async (credentialResponse) => {
    try {
      // SDK handles authentication automatically
      const user = await axonVault.authenticate({
        provider: 'google',
        idToken: credentialResponse.credential
      });
      
      console.log('User authenticated:', user.userId);
      
      // SDK automatically creates wallet for new users
      const wallet = await axonVault.getOrCreateWallet({
        walletName: 'My Wallet'
      });
      
      console.log('Wallet ready:', wallet.walletId);
    } catch (error) {
      console.error('Authentication failed:', error);
    }
  };
  
  return (
    <GoogleLogin
      onSuccess={handleGoogleLogin}
      onError={() => console.log('Login Failed')}
    />
  );
}

Apple Sign-In

import AppleSignin from 'react-apple-signin-auth';

function AppleLoginButton() {
  const handleAppleLogin = async (response) => {
    try {
      const user = await axonVault.authenticate({
        provider: 'apple',
        idToken: response.authorization.id_token
      });
      
      // Get or create wallet
      const wallet = await axonVault.getOrCreateWallet();
      console.log('Wallet ready:', wallet.walletId);
    } catch (error) {
      console.error('Authentication failed:', error);
    }
  };
  
  return (
    <AppleSignin
      authOptions={{
        clientId: 'your.client.id',
        scope: 'email name',
        redirectURI: 'https://yourapp.com/callback',
        usePopup: true
      }}
      onSuccess={handleAppleLogin}
    />
  );
}

Step 4: Display Wallet

import { useState, useEffect } from 'react';

function WalletDisplay() {
  const [wallet, setWallet] = useState(null);
  const [addresses, setAddresses] = useState([]);
  const [balances, setBalances] = useState([]);
  
  useEffect(() => {
    async function loadWallet() {
      // Check if user is authenticated
      if (!await axonVault.isAuthenticated()) {
        return;
      }
      
      // Get default wallet
      const defaultWallet = await axonVault.getDefaultWallet();
      if (!defaultWallet) {
        // Create wallet if none exists
        const newWallet = await axonVault.getOrCreateWallet({
          walletName: 'My Wallet'
        });
        setWallet(newWallet);
      } else {
        setWallet(defaultWallet);
      }
      
      // Get addresses
      const walletAddresses = await wallet.getAddresses();
      setAddresses(walletAddresses);
      
      // Get balances
      const walletBalances = await wallet.getBalances();
      setBalances(walletBalances);
    }
    
    loadWallet();
  }, []);
  
  return (
    <div>
      <h2>Your Wallet</h2>
      {wallet && (
        <>
          <p>Wallet: {wallet.walletName}</p>
          <h3>Addresses</h3>
          {addresses.map(addr => (
            <p key={addr.addressId}>
              {addr.chainId}: {addr.address}
            </p>
          ))}
          <h3>Balances</h3>
          {balances.map(balance => (
            <p key={balance.assetId}>
              {balance.symbol}: {balance.formattedBalance} (${balance.usdValue})
            </p>
          ))}
        </>
      )}
    </div>
  );
}

Step 5: Send Transactions

async function SendTransactionButton({ wallet, recipient, amount }) {
  const [loading, setLoading] = useState(false);
  const [txHash, setTxHash] = useState(null);
  
  const handleSend = async () => {
    try {
      setLoading(true);
      
      // SDK handles building, signing, and submitting
      const hash = await wallet.sendTransaction({
        to: recipient,
        amount: amount, // Amount in wei as string
        chainId: 'eip155:8453' // Base
      });
      
      setTxHash(hash);
      console.log('Transaction sent:', hash);
    } catch (error) {
      console.error('Transaction failed:', error);
      alert(`Transaction failed: ${error.message}`);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <button onClick={handleSend} disabled={loading}>
      {loading ? 'Sending...' : 'Send Transaction'}
    </button>
  );
}

Step 6: Listen for Events

useEffect(() => {
  // Authentication events
  axonVault.on('auth:authenticated', (user) => {
    console.log('User authenticated:', user);
  });
  
  axonVault.on('auth:signedOut', () => {
    console.log('User signed out');
  });
  
  // Wallet events
  axonVault.on('wallet:created', (wallet) => {
    console.log('New wallet created:', wallet);
  });
  
  // Transaction events (if wallet is available)
  if (wallet) {
    wallet.on('transaction:pending', (tx) => {
      console.log('Transaction pending:', tx.txHash);
    });
    
    wallet.on('transaction:confirmed', (tx) => {
      console.log('Transaction confirmed:', tx.txHash);
      // Refresh balances
      wallet.refreshBalances();
    });
    
    wallet.on('transaction:failed', (tx) => {
      console.log('Transaction failed:', tx.error);
    });
    
    // Balance updates
    wallet.on('balance:updated', (balances) => {
      console.log('Balances updated:', balances);
      // Update UI
    });
  }
  
  return () => {
    // Cleanup listeners
    axonVault.removeAllListeners();
    if (wallet) {
      wallet.removeAllListeners();
    }
  };
}, [wallet]);

Complete Example

import { AxonVaultEmbedded } from '@axonvault/embedded-wallet-sdk';
import { GoogleLogin } from '@react-oauth/google';
import { useState, useEffect } from 'react';

const axonVault = new AxonVaultEmbedded({
  projectId: 'proj_abc123',
  environment: 'production'
});

function App() {
  const [user, setUser] = useState(null);
  const [wallet, setWallet] = useState(null);
  const [balances, setBalances] = useState([]);
  
  useEffect(() => {
    checkAuth();
  }, []);
  
  async function checkAuth() {
    const isAuth = await axonVault.isAuthenticated();
    if (isAuth) {
      const currentUser = await axonVault.getCurrentUser();
      setUser(currentUser);
      
      const defaultWallet = await axonVault.getDefaultWallet();
      if (defaultWallet) {
        setWallet(defaultWallet);
        loadBalances(defaultWallet);
      }
    }
  }
  
  async function loadBalances(w) {
    const bals = await w.getBalances();
    setBalances(bals);
  }
  
  async function handleLogin(credentialResponse) {
    try {
      const authenticatedUser = await axonVault.authenticate({
        provider: 'google',
        idToken: credentialResponse.credential
      });
      
      setUser(authenticatedUser);
      
      const newWallet = await axonVault.getOrCreateWallet({
        walletName: 'My Wallet'
      });
      
      setWallet(newWallet);
      loadBalances(newWallet);
    } catch (error) {
      console.error('Login failed:', error);
    }
  }
  
  async function handleSend(to, amount) {
    try {
      const txHash = await wallet.sendTransaction({
        to,
        amount,
        chainId: 'eip155:8453'
      });
      
      console.log('Transaction sent:', txHash);
      // Balances will update automatically via event listener
    } catch (error) {
      console.error('Send failed:', error);
    }
  }
  
  if (!user) {
    return <GoogleLogin onSuccess={handleLogin} />;
  }
  
  return (
    <div>
      <h1>Welcome, {user.email}</h1>
      {wallet && (
        <>
          <h2>Balances</h2>
          {balances.map(b => (
            <p key={b.assetId}>
              {b.symbol}: {b.formattedBalance}
            </p>
          ))}
          <button onClick={() => handleSend('0x...', '1000000000000000000')}>
            Send 1 ETH
          </button>
        </>
      )}
    </div>
  );
}

Best Practices

  • SDK handles token storage securely
  • Always use HTTPS in production
  • Don’t log sensitive data
  • Clear state on logout
  • Show loading states during operations
  • Handle errors gracefully
  • Use event listeners for real-time updates
  • Provide clear feedback for transactions
  • SDK caches data automatically
  • Use event listeners instead of polling
  • Refresh balances only when needed