JSPM

  • Created
  • Published
  • Downloads 8298
  • Score
    100M100P100Q131136F
  • License MIT

Platform-agnostic embedded provider core logic for Phantom Wallet SDK

Package Exports

  • @phantom/embedded-provider-core

Readme

@phantom/embedded-provider-core

Platform-agnostic embedded provider core logic for Phantom Wallet SDK.

Overview

This package contains the core business logic for Phantom's embedded wallet provider, designed to be shared across different platforms (browser, React Native, etc.). It provides a unified interface for wallet operations while allowing platform-specific implementations through adapters.

Architecture

The embedded provider core follows a platform adapter pattern:

┌─────────────────────────────────────┐
│         Platform SDK                │
│    (browser-sdk, react-native)      │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│      EmbeddedProvider (Core)        │
│  - Authentication flows             │
│  - Session management               │
│  - Wallet operations                │
│  - Business logic                   │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│       Platform Adapters             │
│  - Storage (IndexedDB/AsyncStorage) │
│  - Auth (redirects/deep links)      │
│  - URL params (window/linking)      │
│  - Logger (debug/console)           │
└─────────────────────────────────────┘

Key Features

  • Cross-platform compatibility: Share 90%+ of wallet logic across platforms
  • Clean separation of concerns: Platform-specific code isolated in adapters
  • Multiple auth flows: JWT, Google OAuth, Apple OAuth, app-wallet creation
  • Session management: Persistent sessions with validation and recovery
  • Retry logic: Built-in retry with exponential backoff for network operations
  • Type safety: Full TypeScript support with comprehensive interfaces

Usage

Basic Setup

import {
  EmbeddedProvider,
  EmbeddedProviderConfig,
  PlatformAdapter,
  DebugLogger,
} from "@phantom/embedded-provider-core";

// 1. Define your configuration
const config: EmbeddedProviderConfig = {
  apiBaseUrl: "https://api.phantom.app",
  appId: "your-app-id",
  embeddedWalletType: "user-wallet", // or 'app-wallet'
  addressTypes: ["solana", "ethereum"],
  authOptions: {
    authUrl: "https://auth.phantom.app",
    redirectUrl: "https://your-app.com/callback",
  },
};

// 2. Implement platform adapters (see examples below)
const platform: PlatformAdapter = {
  storage: new YourStorageAdapter(),
  authProvider: new YourAuthProvider(),
  urlParamsAccessor: new YourURLParamsAccessor(),
};

// 3. Implement logger
const logger: DebugLogger = new YourLogger();

// 4. Create provider instance
const provider = new EmbeddedProvider(config, platform, logger);

// 5. Use the provider
const result = await provider.connect();
console.log("Connected addresses:", result.addresses);

Platform Adapter Interfaces

Storage Adapter

Handles persistent session storage:

import { EmbeddedStorage, Session } from "@phantom/embedded-provider-core";

export class YourStorageAdapter implements EmbeddedStorage {
  async getSession(): Promise<Session | null> {
    // Platform-specific session retrieval
    // Browser: IndexedDB, React Native: AsyncStorage
  }

  async saveSession(session: Session): Promise<void> {
    // Platform-specific session storage
  }

  async clearSession(): Promise<void> {
    // Platform-specific session cleanup
  }
}

Auth Provider

Handles authentication flows:

import { AuthProvider, AuthResult, PhantomConnectOptions, JWTAuthOptions } from "@phantom/embedded-provider-core";

export class YourAuthProvider implements AuthProvider {
  async authenticate(options: PhantomConnectOptions | JWTAuthOptions): Promise<void | AuthResult> {
    // Platform-specific authentication
    // Browser: window redirects, React Native: deep links
  }

  resumeAuthFromRedirect?(): AuthResult | null {
    // Resume authentication after redirect/deep link
  }
}

URL Params Accessor

Handles URL parameter access:

import { URLParamsAccessor } from "@phantom/embedded-provider-core";

export class YourURLParamsAccessor implements URLParamsAccessor {
  getParam(key: string): string | null {
    // Platform-specific URL parameter access
    // Browser: window.location.search, React Native: Linking.getInitialURL()
  }
}

Debug Logger

Handles logging:

import { DebugLogger } from "@phantom/embedded-provider-core";

export class YourLogger implements DebugLogger {
  info(category: string, message: string, data?: any): void {
    // Platform-specific logging
  }

  warn(category: string, message: string, data?: any): void {
    // Platform-specific warning
  }

  error(category: string, message: string, data?: any): void {
    // Platform-specific error logging
  }

  log(category: string, message: string, data?: any): void {
    // Platform-specific debug logging
  }
}

Authentication Flows

JWT Authentication

For server-side authenticated users:

const authOptions = {
  provider: "jwt",
  jwtToken: "your-jwt-token",
  customAuthData: { userId: "user123" },
};

const result = await provider.connect(authOptions);

OAuth Authentication

For social login flows:

// Google OAuth
const authOptions = {
  provider: "google",
  customAuthData: { referrer: "landing-page" },
};

await provider.connect(authOptions); // Will redirect/deep link

// Apple OAuth
const authOptions = {
  provider: "apple",
};

await provider.connect(authOptions); // Will redirect/deep link

App Wallet

For application-controlled wallets:

const config = {
  // ... other config
  embeddedWalletType: "app-wallet",
};

const result = await provider.connect(); // No auth needed

Session Management

Sessions are automatically managed by the core provider:

// Check connection status
if (provider.isConnected()) {
  const addresses = provider.getAddresses();
  console.log("Available addresses:", addresses);
}

// Sign a message
const signature = await provider.signMessage({
  message: "Hello, world!",
  networkId: "solana:mainnet",
});

// Sign and send transaction
const result = await provider.signAndSendTransaction({
  transaction: transactionBytes,
  networkId: "solana:mainnet",
});

// Disconnect
await provider.disconnect();

Error Handling

The core provider provides detailed error messages:

try {
  await provider.connect();
} catch (error) {
  if (error.message.includes("JWT")) {
    // Handle JWT authentication errors
  } else if (error.message.includes("Storage")) {
    // Handle storage errors
  } else if (error.message.includes("Network")) {
    // Handle network errors
  }
}

Configuration Options

interface EmbeddedProviderConfig {
  // Required
  apiBaseUrl: string; // Phantom API base URL
  appId: string;
  embeddedWalletType: "app-wallet" | "user-wallet";
  addressTypes: [AddressType, ...AddressType[]]; // Supported blockchain addresses

  // Optional
  authOptions?: {
    authUrl?: string; // Custom auth URL
    redirectUrl?: string; // OAuth redirect URL
  };
}

Session Object

interface Session {
  sessionId: string; // Unique session identifier
  walletId: string; // Phantom wallet ID
  keypair: {
    // Cryptographic keypair
    publicKey: string;
    secretKey: string;
  };
  authProvider: string; // Auth method used
  userInfo: Record<string, any>; // User information
  status: "pending" | "completed"; // Session status
  createdAt: number; // Creation timestamp
  lastUsed: number; // Last access timestamp
}

Best Practices

  1. Platform Adapters: Keep platform-specific code in adapters only
  2. Error Handling: Always handle authentication and network errors
  3. Session Validation: The core automatically validates sessions
  4. Logging: Use structured logging with categories for debugging
  5. Security: Never log sensitive data like private keys

Examples

See the @phantom/browser-sdk package for a complete implementation example using this core package with browser-specific adapters.

Development

# Install dependencies
yarn install

# Build the package
yarn build

# Run tests
yarn test

# Run linting
yarn lint

# Format code
yarn prettier

Contributing

This package is designed to be extended for new platforms. When adding support for a new platform:

  1. Implement all required platform adapter interfaces
  2. Add comprehensive tests for your adapters
  3. Update documentation with platform-specific examples
  4. Ensure error handling covers platform-specific edge cases

License

MIT