JSPM

  • Created
  • Published
  • Downloads 14
  • Score
    100M100P100Q54153F
  • License MIT

A comprehensive wallet SDK for React Native (pwc), supporting multi-chain and multi-account features.

Package Exports

  • p-sdk-wallet
  • p-sdk-wallet/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (p-sdk-wallet) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

PWC Wallet SDK

A comprehensive, secure, and user-friendly wallet SDK for React Native applications. This SDK provides a complete solution for managing cryptocurrency wallets with support for multiple blockchains, HD wallet generation, vanity addresses, and advanced features like multi-transfer operations.

πŸ“‹ Table of Contents

πŸš€ Quick Start

πŸ“± React Native Usage

βš™οΈ Configuration

πŸ’° Core Wallet Functions

πŸ”„ Multi-Transfer Operations

πŸ–ΌοΈ NFT Functionality

β›½ Advanced Features

πŸ”’ Security & Error Handling

πŸ› οΈ Development


Features

  • πŸ” Secure HD Wallet Management: BIP-44 compliant hierarchical deterministic wallets
  • 🎯 Vanity Address Generation: Generate wallets with custom address prefixes
  • πŸ”— Multi-Chain Support: Ethereum, BSC, Polygon, Arbitrum, Optimism, Base, and Solana
  • πŸš€ Multi-Transfer Operations: Batch send tokens to multiple recipients
  • πŸ”§ Custom Chain Support: Add custom chains and override built-in configurations
  • πŸ“± React Native Optimized: Designed specifically for mobile applications
  • πŸ”’ Encryption: AES-256 encryption for secure vault storage
  • 🎨 TypeScript: Full TypeScript support with comprehensive type definitions
  • πŸ–ΌοΈ NFT Support: Core NFT functionality for individual tokens and collections

Installation

npm install pwc-wallet-sdk

Quick Start

1. Basic Wallet Creation

import { Vault } from 'pwc-wallet-sdk';

// Create a new wallet
const { vault, encryptedVault } = await Vault.createNew('your-secure-password');

// Get wallet accounts
const accounts = vault.getAccounts();
console.log('Wallet addresses:', accounts.map(acc => acc.address));

2. Vanity Wallet Generation

// Generate wallet with custom address prefix
const { vault, encryptedVault, attempts, foundAddress } = 
  await Vault.generateVanityHDWallet('your-password', (attempts, currentAddress) => {
    console.log(`Attempt ${attempts}: ${currentAddress}`);
  });

console.log(`Found address with prefix after ${attempts} attempts: ${foundAddress}`);

3. Custom Chain Configuration

import { setupChainConfigs, registerCustomChain, overrideChain } from 'pwc-wallet-sdk';

// Setup custom chains and overrides (call once when app starts)
setupChainConfigs({
  // Override built-in chains
  overrides: {
    '1': { rpcUrl: 'https://my-eth-rpc.com' }, // Use custom Ethereum RPC
    '56': { rpcUrl: 'https://my-bsc-rpc.com' }, // Use custom BSC RPC
  },
  // Add custom chains
  customChains: {
    'custom-1': {
      name: 'My Custom Chain',
      rpcUrl: 'https://my-custom-rpc.com',
      explorerUrl: 'https://my-explorer.com',
      nativeCurrency: { name: 'Token', symbol: 'TKN', decimals: 18 },
      type: 'evm'
    },
    'custom-solana': {
      name: 'My Solana Chain',
      rpcUrl: 'https://my-solana-rpc.com',
      explorerUrl: 'https://my-solana-explorer.com',
      nativeCurrency: { name: 'SOL', symbol: 'SOL', decimals: 9 },
      type: 'solana'
    }
  }
});

// Load vault
const vault = await Vault.load(password, encryptedVault);

// Use custom chains normally
await vault.sendToken(from, to, amount, tokenAddress, 'custom-1');
await vault.getNativeBalance(address, 'custom-solana');

React Native Usage

Simple Wallet Component

import React, { useState, useEffect } from 'react';
import { Vault, setupChainConfigs } from 'pwc-wallet-sdk';

const WalletComponent = () => {
  const [vault, setVault] = useState(null);
  const [balance, setBalance] = useState('0');

  useEffect(() => {
    // Setup custom chains when component mounts
    setupChainConfigs({
      overrides: {
        '1': { rpcUrl: 'https://my-eth-rpc.com' }
      },
      customChains: {
        'custom-1': {
          name: 'My Chain',
          rpcUrl: 'https://my-rpc.com',
          type: 'evm'
        }
      }
    });

    loadWallet();
  }, []);

  const loadWallet = async () => {
    try {
      const loadedVault = await Vault.load(password, encryptedVault);
      setVault(loadedVault);
      
      // Get balance using custom chain
      const balance = await loadedVault.getNativeBalance(address, 'custom-1');
      setBalance(ethers.formatEther(balance));
    } catch (error) {
      console.error('Failed to load wallet:', error);
    }
  };

  const sendTransaction = async () => {
    if (!vault) return;
    
    try {
      // Send using custom chain
      const tx = await vault.sendToken(from, to, amount, tokenAddress, 'custom-1');
      console.log('Transaction sent:', tx.hash);
    } catch (error) {
      console.error('Transaction failed:', error);
    }
  };

  return (
    <View>
      <Text>Balance: {balance}</Text>
      <Button title="Send Transaction" onPress={sendTransaction} />
    </View>
  );
};

Custom Hook for Wallet Management

import { useState, useEffect } from 'react';
import { Vault, setupChainConfigs } from 'pwc-wallet-sdk';

export const useWallet = (password: string, encryptedVault: EncryptedData) => {
  const [vault, setVault] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    initializeWallet();
  }, []);

  const initializeWallet = async () => {
    try {
      setLoading(true);
      
      // Setup chains
      setupChainConfigs({
        overrides: {
          '1': { rpcUrl: 'https://my-eth-rpc.com' }
        }
      });

      const loadedVault = await Vault.load(password, encryptedVault);
      setVault(loadedVault);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const sendToken = async (from: string, to: string, amount: string, tokenAddress: string, chainId: string) => {
    if (!vault) throw new Error('Wallet not loaded');
    return vault.sendToken(from, to, amount, tokenAddress, chainId);
  };

  const getBalance = async (address: string, chainId: string) => {
    if (!vault) throw new Error('Wallet not loaded');
    return vault.getNativeBalance(address, chainId);
  };

  return {
    vault,
    loading,
    error,
    sendToken,
    getBalance
  };
};

Account Management

Add New HD Account

// Add a new account derived from the HD keyring
const newAccount = await vault.addNewHDAccount();
console.log('New account:', newAccount.address);

Add New Solana Account

// Add a new Solana account
const newSolanaAccount = await vault.addNewSolanaAccount();
console.log('New Solana account:', newSolanaAccount.address);

Import Account

// Import an account from private key
const importedAccount = await vault.importAccount('your-private-key');
console.log('Imported account:', importedAccount.address);

Get Accounts

// Get all accounts in the vault
const accounts = vault.getAccounts();
accounts.forEach(account => {
  console.log(`${account.name}: ${account.address} (${account.type})`);
});

Balance & Token Functions

Get Native Balance

// Get native token balance (ETH, BNB, etc.)
const balance = await vault.getNativeBalance(address, '1'); // Ethereum
console.log('Balance:', ethers.formatEther(balance), 'ETH');

Get Token Balance

// Get ERC-20 token balance
const tokenBalance = await vault.getTokenBalance(address, tokenAddress, '1');
const tokenInfo = await vault.getTokenInfo(tokenAddress, '1');
console.log('Token balance:', ethers.formatUnits(tokenBalance, tokenInfo.decimals), tokenInfo.symbol);

Get Token Info

// Get token metadata
const tokenInfo = await vault.getTokenInfo(tokenAddress, '1');
console.log(`Token: ${tokenInfo.name} (${tokenInfo.symbol})`);
console.log(`Decimals: ${tokenInfo.decimals}`);

Transaction Functions

Send Native Token

// Send native tokens (ETH, BNB, etc.)
const tx = await vault.sendNativeToken(
  fromAddress,
  toAddress,
  '0.1', // amount
  '1' // Ethereum chainId
);
console.log('Transaction hash:', tx.hash);

Send Token

// Send ERC-20 tokens
const tx = await vault.sendToken(
  fromAddress,
  toAddress,
  '100', // amount
  tokenAddress,
  '1' // Ethereum chainId
);
console.log('Transaction hash:', tx.hash);

Export Mnemonic

// Export the mnemonic phrase (requires password)
const mnemonic = await vault.exportMnemonic(password);
console.log('Mnemonic:', mnemonic);

Chain Configuration

Built-in Chains

The SDK supports these chains out of the box:

  • Ethereum (1): Mainnet
  • BNB Smart Chain (56): Mainnet
  • Polygon (137): Mainnet
  • Arbitrum One (42161): Mainnet
  • OP Mainnet (10): Mainnet
  • Base (8453): Mainnet
  • Solana: Mainnet and Devnet
  • BSC Testnet (97): Testnet

Custom Chain Management

Override Built-in Chains

import { overrideChain, overrideChains } from 'pwc-wallet-sdk';

// Override single chain
overrideChain('1', { rpcUrl: 'https://my-eth-rpc.com' });

// Override multiple chains
overrideChains({
  '1': { rpcUrl: 'https://my-eth-rpc.com' },
  '56': { rpcUrl: 'https://my-bsc-rpc.com' }
});

Add Custom Chains

import { registerCustomChain } from 'pwc-wallet-sdk';

// Add EVM chain
registerCustomChain('custom-evm', {
  name: 'My EVM Chain',
  rpcUrl: 'https://my-evm-rpc.com',
  explorerUrl: 'https://my-explorer.com',
  nativeCurrency: { name: 'Token', symbol: 'TKN', decimals: 18 },
  type: 'evm'
});

// Add Solana chain
registerCustomChain('custom-solana', {
  name: 'My Solana Chain',
  rpcUrl: 'https://my-solana-rpc.com',
  explorerUrl: 'https://my-solana-explorer.com',
  nativeCurrency: { name: 'SOL', symbol: 'SOL', decimals: 9 },
  type: 'solana'
});

Setup All Chains at Once

import { setupChainConfigs } from 'pwc-wallet-sdk';

// Setup everything in one call
setupChainConfigs({
  overrides: {
    '1': { rpcUrl: 'https://my-eth-rpc.com' },
    '56': { rpcUrl: 'https://my-bsc-rpc.com' }
  },
  customChains: {
    'custom-1': {
      name: 'My Custom Chain',
      rpcUrl: 'https://my-custom-rpc.com',
      type: 'evm'
    }
  }
});

Chain Configuration Priority

The SDK uses this priority order when resolving chain configurations:

  1. Custom Chains (highest priority)
  2. Built-in Chains + Overrides (merged)
  3. Built-in Chains (original, if no override)
  4. Error (if not found)

Utility Functions

import { 
  getAllAvailableChains,
  getCustomChains,
  getOverrides,
  clearCustomChains,
  clearOverrides
} from 'pwc-wallet-sdk';

// Get all available chains
const allChains = getAllAvailableChains();

// Get only custom chains
const customChains = getCustomChains();

// Get only overrides
const overrides = getOverrides();

// Clear all custom chains
clearCustomChains();

// Clear all overrides
clearOverrides();

Multi-Transfer Operations

Batch Send Native Tokens

const recipients = [
  { address: '0x123...', amount: '0.1' },
  { address: '0x456...', amount: '0.2' },
  { address: '0x789...', amount: '0.3' }
];

const result = await vault.multiTransferNativeTokens(
  fromAddress,
  recipients,
  '1', // chainId
  (completed, total, txHash) => {
    console.log(`Completed ${completed}/${total}: ${txHash}`);
  }
);

console.log(`Successfully sent ${result.successful} transactions`);
console.log(`Failed: ${result.failed.length}`);

Batch Send ERC-20 Tokens

const result = await vault.multiTransferTokens(
  fromAddress,
  tokenAddress,
  recipients,
  '1', // chainId
  (completed, total, txHash) => {
    console.log(`Completed ${completed}/${total}: ${txHash}`);
  }
);

NFT Functionality

The SDK provides core NFT functionality focused on individual NFT details and collection information. For NFT discovery and listing, use your backend API.

Get NFT Details

// Get detailed information about a specific NFT
const nftDetail = await vault.getNFTDetail(
  '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // BAYC contract
  '1234', // Token ID
  '1', // Ethereum
  { includeMetadata: true },
  'your-api-key'
);

console.log(`Name: ${nftDetail.name}`);
console.log(`Description: ${nftDetail.description}`);
console.log(`Image: ${nftDetail.image}`);

Get Collection Information

// Get information about an NFT collection
const collection = await vault.getCollectionInfo(
  '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // BAYC contract
  '1', // Ethereum
  'your-api-key'
);

console.log(`Collection: ${collection.name}`);
console.log(`Total Supply: ${collection.totalSupply}`);

Validate NFT Contract Address

// Validate if an address is a valid NFT contract
const isValid = vault.isValidNFTContractAddress(
  '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
  '1' // Ethereum
);

console.log('Address is valid:', isValid);

NFT Discovery (Backend API)

For getting lists of NFTs, use your backend API:

// Get owned NFTs from your backend
const nfts = await apiClient.get('/nfts/owned', {
  address: '0x1234...',
  chainId: '1',
  limit: 50
});

// Get popular collections
const collections = await apiClient.get('/nfts/collections/popular');

// Search NFTs
const searchResults = await apiClient.get('/nfts/search', {
  query: 'Bored Ape',
  chainId: '1'
});

Supported APIs

The SDK integrates with multiple NFT APIs for enhanced data:

  • Ethereum: Alchemy API (recommended)
  • Multi-chain: Covalent API
  • Solana: Helius API

API Key Setup

// For Ethereum (Alchemy)
const nftDetail = await vault.getNFTDetail(
  contractAddress,
  tokenId,
  '1', // Ethereum
  { includeMetadata: true },
  'your-alchemy-api-key'
);

// For multi-chain (Covalent)
const nftDetail = await vault.getNFTDetail(
  contractAddress,
  tokenId,
  '137', // Polygon
  { includeMetadata: true },
  'your-covalent-api-key'
);

// For Solana (Helius)
const nftDetail = await vault.getNFTDetail(
  contractAddress,
  tokenId,
  'solana', // Solana
  { includeMetadata: true },
  'your-helius-api-key'
);

NFT Types and Interfaces

import { 
  NFTDetail, 
  NFTDetailExtended, 
  CollectionInfo, 
  NFTOptions 
} from 'pwc-wallet-sdk';

// Basic NFT information
interface NFTDetail {
  contractAddress: string;
  contractName: string;
  tokenId: string;
  name: string;
  description: string;
  image: string;
  owner: string;
  // ... more properties
}

// Extended NFT information with metadata
interface NFTDetailExtended extends NFTDetail {
  attributes?: Array<{ trait_type: string; value: string; display_type?: string }>;
  // ... more properties
}

// Collection information
interface CollectionInfo {
  name: string;
  description: string;
  image: string;
  banner: string;
  verified: boolean;
  totalSupply: number;
}

React Native NFT Component Example

import React, { useState, useEffect } from 'react';
import { View, Text, Image } from 'react-native';
import { Vault, NFTDetailExtended } from 'pwc-wallet-sdk';

const NFTDetailView = ({ vault, contractAddress, tokenId, chainId, apiKey }) => {
  const [nft, setNft] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    loadNFTDetail();
  }, [contractAddress, tokenId]);

  const loadNFTDetail = async () => {
    try {
      setLoading(true);
      const nftDetail = await vault.getNFTDetail(
        contractAddress,
        tokenId,
        chainId,
        { includeMetadata: true },
        apiKey
      );
      setNft(nftDetail);
    } catch (error) {
      console.error('Failed to load NFT:', error);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return <Text>Loading NFT...</Text>;
  }

  if (!nft) {
    return <Text>NFT not found</Text>;
  }

  return (
    <View style={{ padding: 20 }}>
      <Image 
        source={{ uri: nft.image }} 
        style={{ width: 300, height: 300 }}
        resizeMode="cover"
      />
      <Text style={{ fontSize: 24, fontWeight: 'bold', marginTop: 10 }}>
        {nft.name}
      </Text>
      <Text style={{ marginTop: 5 }}>{nft.description}</Text>
      <Text style={{ marginTop: 10 }}>
        Collection: {nft.contractName}
      </Text>
      <Text>Token ID: {nft.tokenId}</Text>
    </View>
  );
};

Advanced Features

Gas Estimation

Estimate Native Transfer Gas

// Estimate gas for native token transfer
const gasEstimate = await vault.estimateNativeTransferGas(
  fromAddress,
  toAddress,
  amount,
  '1'
);

console.log('Estimated gas:', gasEstimate.toString());
console.log('Estimated cost (in ETH):', ethers.formatEther(gasEstimate * gasPrice));

Estimate Token Transfer Gas

// Estimate gas for ERC-20 token transfer
const gasEstimate = await vault.estimateTokenTransferGas(
  fromAddress,
  tokenAddress,
  toAddress,
  amount,
  '1'
);

console.log('Estimated gas for token transfer:', gasEstimate.toString());

Estimate Multi-Transfer Gas

// Estimate gas for multi-transfer operations
const recipients = [
  { address: '0x1111...', amount: '0.01' },
  { address: '0x2222...', amount: '0.02' },
  { address: '0x3333...', amount: '0.005' }
];

// Estimate for native token multi-transfer
const nativeGasEstimate = await vault.estimateMultiTransferGas(
  fromAddress,
  recipients,
  '1', // Ethereum
  true // Native tokens
);

// Estimate for token multi-transfer
const tokenGasEstimate = await vault.estimateMultiTransferGas(
  fromAddress,
  recipients,
  '1', // Ethereum
  false, // ERC-20 tokens
  tokenAddress // USDC
);

console.log('Native multi-transfer gas:', nativeGasEstimate.toString());
console.log('Token multi-transfer gas:', tokenGasEstimate.toString());

Token Information

// Get token metadata
const tokenInfo = await vault.getTokenInfo(tokenAddress, '1');
console.log(`Token: ${tokenInfo.name} (${tokenInfo.symbol})`);

// Get token balance
const balance = await vault.getTokenBalance(address, tokenAddress, '1');
console.log(`Balance: ${ethers.formatUnits(balance, tokenInfo.decimals)}`);

Configuration

Vanity Wallet Settings

import { VANITY_WALLET_CONFIG } from 'pwc-wallet-sdk';

// Default settings
console.log(VANITY_WALLET_CONFIG.DEFAULT_PREFIX); // 'aaa'
console.log(VANITY_WALLET_CONFIG.DEFAULT_MAX_ATTEMPTS); // 1000000
console.log(VANITY_WALLET_CONFIG.DEFAULT_CASE_SENSITIVE); // false

Supported Chains

import { SUPPORTED_CHAINS } from 'pwc-wallet-sdk';

// View all supported chains
Object.entries(SUPPORTED_CHAINS).forEach(([chainId, config]) => {
  console.log(`${chainId}: ${config.name} (${config.type})`);
});

Security Considerations

  • Password Strength: Use strong passwords for vault encryption
  • Private Key Storage: Private keys are never stored in plain text
  • Memory Safety: Sensitive data is cleared from memory when possible
  • Encryption: All vault data is encrypted using AES-256
  • Validation: Input validation prevents common attack vectors

Error Handling

try {
  const vault = await Vault.load(password, encryptedVault);
  await vault.sendToken(from, to, amount, tokenAddress, '1');
} catch (error) {
  if (error.message.includes('incorrect password')) {
    // Handle password error
  } else if (error.message.includes('insufficient balance')) {
    // Handle balance error
  } else {
    // Handle other errors
  }
}

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

MIT License - see LICENSE file for details.