The Base Account SDK provides several core utility functions for managing cryptographic keys and accessing account information. These functions are essential for advanced integrations and Sub Account management.

generateKeyPair

Generates a new P256 key pair for use with Base Account.

import { generateKeyPair } from '@base-org/account';

const keyPair = await generateKeyPair();
console.log('New key pair generated:', keyPair);

Returns

Promise<P256KeyPair>

A P256 key pair object containing:

  • publicKey: The public key for the generated pair
  • privateKey: The private key (handle with care)

Usage Example

async function createNewKeyPair() {
  try {
    const keyPair = await generateKeyPair();
    
    // Use the public key for account creation
    console.log('Public key:', keyPair.publicKey);
    
    // Store private key securely (if needed)
    // Note: Handle private keys with extreme care
    
    return keyPair;
  } catch (error) {
    console.error('Failed to generate key pair:', error);
    throw error;
  }
}

Private Key Security

Never expose private keys in client-side code or transmit them over insecure channels. Store them securely using appropriate key management systems.

getKeypair

Retrieves an existing P256 key pair if one has been previously generated and stored.

import { getKeypair } from '@base-org/account';

const existingKeyPair = await getKeypair();
if (existingKeyPair) {
  console.log('Found existing key pair');
} else {
  console.log('No existing key pair found');
}

Returns

Promise<P256KeyPair | null>

Returns the stored P256 key pair or null if no key pair exists.

Usage Example

async function getOrCreateKeyPair() {
  // Try to get existing key pair first
  let keyPair = await getKeypair();
  
  if (!keyPair) {
    // Generate new key pair if none exists
    console.log('No existing key pair, generating new one...');
    keyPair = await generateKeyPair();
  } else {
    console.log('Using existing key pair');
  }
  
  return keyPair;
}

getCryptoKeyAccount

Retrieves the current crypto account associated with the user’s session. This is the primary function for accessing account information.

import { getCryptoKeyAccount } from '@base-org/account';

const cryptoAccount = await getCryptoKeyAccount();
if (cryptoAccount?.account) {
  console.log('Account address:', cryptoAccount.account.address);
  console.log('Public key:', cryptoAccount.account.publicKey);
}

Returns

Promise<{
  account: OneOf<WebAuthnAccount | LocalAccount> | null;
}>

Returns an object containing:

  • account: The user’s account (WebAuthn-based or local), or null if no account exists

Account Types

The returned account can be one of two types:

WebAuthnAccount

For accounts using WebAuthn (passkeys):

interface WebAuthnAccount {
  address: string;
  publicKey: string;
  type: 'webauthn';
  // Additional WebAuthn-specific properties
}

LocalAccount

For local development accounts:

interface LocalAccount {
  address: string;
  publicKey: string;
  type: 'local';
  // Additional local account properties
}

Usage Example

async function getCurrentAccount() {
  try {
    const cryptoAccount = await getCryptoKeyAccount();
    
    if (!cryptoAccount?.account) {
      console.log('No account found - user needs to sign in');
      return null;
    }
    
    const { account } = cryptoAccount;
    
    console.log('Account found:');
    console.log('- Address:', account.address);
    console.log('- Type:', account.type);
    console.log('- Public Key:', account.publicKey);
    
    return account;
  } catch (error) {
    console.error('Failed to get crypto account:', error);
    throw error;
  }
}

Complete Integration Example

Here’s how these utilities work together in a typical application:

import { 
  generateKeyPair, 
  getKeypair, 
  getCryptoKeyAccount,
  createBaseAccountSDK 
} from '@base-org/account';

class AccountManager {
  private sdk: any;
  
  constructor() {
    this.sdk = createBaseAccountSDK({
      appName: 'My App',
      appLogoUrl: 'https://example.com/logo.png',
      appChainIds: [8453], // Base mainnet
    });
  }
  
  // Initialize account management
  async initialize() {
    const account = await this.getCurrentAccount();
    
    if (!account) {
      console.log('No account found, user needs to connect');
      return null;
    }
    
    return account;
  }
  
  // Get current account or prompt connection
  async getCurrentAccount() {
    const cryptoAccount = await getCryptoKeyAccount();
    return cryptoAccount?.account || null;
  }
  
  // Get or generate key pair for advanced operations
  async getKeyPair() {
    let keyPair = await getKeypair();
    
    if (!keyPair) {
      console.log('Generating new key pair...');
      keyPair = await generateKeyPair();
    }
    
    return keyPair;
  }
  
  // Example: Use account for Sub Account creation
  async createSubAccount() {
    const account = await this.getCurrentAccount();
    const keyPair = await this.getKeyPair();
    
    if (!account || !keyPair) {
      throw new Error('Account and key pair required');
    }
    
    // Use the SDK to create sub account
    const subAccount = await this.sdk.subAccount.create({
      type: 'create',
      keys: [{
        type: 'webauthn-p256',
        publicKey: keyPair.publicKey,
      }],
    });
    
    return subAccount;
  }
  
  // Get account address for transactions
  getAccountAddress(): string | null {
    // This would be called after initialization
    const account = this.getCurrentAccount();
    return account?.address || null;
  }
}

// Usage
const accountManager = new AccountManager();

// Initialize and get account
const account = await accountManager.initialize();

if (account) {
  console.log('User is connected:', account.address);
  
  // Create sub account if needed
  const subAccount = await accountManager.createSubAccount();
  console.log('Sub account created:', subAccount.address);
} else {
  console.log('User needs to connect their account');
}

Error Handling

Handle common errors when using these utilities:

async function safeGetAccount() {
  try {
    const cryptoAccount = await getCryptoKeyAccount();
    return cryptoAccount?.account;
  } catch (error) {
    console.error('Error getting crypto account:', error);
    
    if (error.message.includes('not initialized')) {
      // SDK not properly initialized
      throw new Error('Base Account SDK not initialized');
    } else if (error.message.includes('permission denied')) {
      // User denied access
      throw new Error('User denied account access');
    } else {
      // Unknown error
      throw new Error('Failed to access account');
    }
  }
}

Best Practices

  1. Check for existing accounts: Always use getCryptoKeyAccount() first to check if a user is already connected

  2. Handle null returns: These functions can return null - always check before using the results

  3. Secure key management: If using generateKeyPair() or getKeypair(), handle private keys securely

  4. Error handling: Wrap calls in try-catch blocks to handle authentication and network errors

  5. User experience: Provide clear feedback when accounts aren’t found or need to be created

These utilities provide the foundation for advanced Base Account integrations, particularly when working with Sub Accounts and custom authentication flows.