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
Copy
npm install @axonvault/embedded-wallet-sdk
Step 1: Configure Your Project
- Create a project in the AxonVault Dashboard
- Enable social login providers (Google, Apple)
- Configure allowed origins for your app
- Copy your Project ID
Step 2: Initialize the SDK
Copy
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
Copy
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
Copy
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
Copy
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
Copy
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
Copy
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
Copy
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
Security
Security
- SDK handles token storage securely
- Always use HTTPS in production
- Don’t log sensitive data
- Clear state on logout
UX
UX
- Show loading states during operations
- Handle errors gracefully
- Use event listeners for real-time updates
- Provide clear feedback for transactions
Performance
Performance
- SDK caches data automatically
- Use event listeners instead of polling
- Refresh balances only when needed