# @tiwiflix/wallet-connector

A comprehensive multi-chain wallet connector for Tiwiflix, supporting EVM, Solana, TON, and Tron wallets with a unified API.

## Features

- 🌐 **Multi-Chain Support**: EVM, Solana, TON, and Tron
- 🔌 **16 Wallet Integrations**: MetaMask, Trust Wallet, Bitget, Base, Phantom, Solflare, Tonkeeper, TronLink, and more
- 🎯 **Unified API**: Single interface for all wallet interactions
- 🔄 **Auto-Connect**: Automatically reconnect to previously used wallet
- 📦 **TypeScript**: Full TypeScript support with type definitions
- 🎨 **Flexible**: Easy to add custom wallet adapters
- ⚡ **Lightweight**: Optional peer dependencies for unused chains
- 🖼️ **NFT Checking**: Verify NFT ownership for TON wallets

## Supported Wallets

### EVM Wallets
- MetaMask
- Trust Wallet
- Bitget Wallet
- Base Wallet (formerly Coinbase Wallet)
- Atomic Wallet
- SafePal
- Rabby
- Exodus
- WalletConnect

### Solana Wallets
- Solflare
- Phantom

### TON Wallets
- Tonkeeper
- Ton Hub
- MyTonWallet

### Tron Wallets
- TronLink
- Klever

## Installation

```bash
npm install @tiwiflix/wallet-connector
```

### Peer Dependencies

Install only the dependencies for the chains you need:

```bash
# For EVM wallets
npm install ethers

# For WalletConnect
npm install @walletconnect/ethereum-provider

# For Solana wallets
npm install @solana/web3.js @solana/wallet-adapter-base

# For TON wallets
npm install @tonconnect/ui

# All chains
npm install ethers @walletconnect/ethereum-provider @solana/web3.js @solana/wallet-adapter-base @tonconnect/ui
```

## Quick Start

### Basic Usage

```typescript
import { 
  WalletConnector, 
  MetamaskAdapter, 
  TrustWalletAdapter,
  PhantomAdapter,
  TonkeeperAdapter,
  WalletType 
} from '@tiwiflix/wallet-connector';

// Initialize connector with desired wallets
const connector = new WalletConnector({
  adapters: [
    new MetamaskAdapter(),
    new TrustWalletAdapter(),
    new PhantomAdapter(),
    new TonkeeperAdapter(),
  ],
  autoConnect: true, // Auto-connect to previously connected wallet
  storageKey: 'tiwiflix_wallet', // Custom storage key
});

// Get available wallets (installed)
const availableWallets = connector.getAvailableWallets();
console.log('Available wallets:', availableWallets);

// Connect to a wallet
try {
  await connector.connect(WalletType.METAMASK);
  console.log('Connected!');
} catch (error) {
  console.error('Connection failed:', error);
}

// Get current account
const account = await connector.getAccount();
console.log('Account:', account);

// Sign a message
const signature = await connector.signMessage('Hello, Tiwiflix!');
console.log('Signature:', signature);

// Disconnect
await connector.disconnect();
```

### React Example

```typescript
import { useState, useEffect } from 'react';
import { 
  WalletConnector, 
  MetamaskAdapter,
  PhantomAdapter,
  TonkeeperAdapter,
  WalletType,
  WalletEvent,
  Account 
} from '@tiwiflix/wallet-connector';

// Initialize connector once
const connector = new WalletConnector({
  adapters: [
    new MetamaskAdapter(),
    new PhantomAdapter(),
    new TonkeeperAdapter(),
  ],
  autoConnect: true,
});

function WalletButton() {
  const [account, setAccount] = useState<Account | null>(null);
  const [isConnecting, setIsConnecting] = useState(false);

  useEffect(() => {
    // Subscribe to account changes
    const unsubscribe = connector.on(WalletEvent.ACCOUNT_CHANGED, (acc) => {
      setAccount(acc);
    });

    // Get initial account
    connector.getAccount().then(setAccount);

    return () => unsubscribe();
  }, []);

  const handleConnect = async (walletType: WalletType) => {
    setIsConnecting(true);
    try {
      await connector.connect(walletType);
    } catch (error) {
      console.error('Connection failed:', error);
    } finally {
      setIsConnecting(false);
    }
  };

  const handleDisconnect = async () => {
    await connector.disconnect();
  };

  if (account) {
    return (
      <div>
        <p>Connected: {account.address.slice(0, 6)}...{account.address.slice(-4)}</p>
        <button onClick={handleDisconnect}>Disconnect</button>
      </div>
    );
  }

  return (
    <div>
      <h3>Select Wallet</h3>
      {connector.getAvailableWallets().map((wallet) => (
        <button
          key={wallet.type}
          onClick={() => handleConnect(wallet.type)}
          disabled={isConnecting}
        >
          {wallet.name}
        </button>
      ))}
    </div>
  );
}
```

### WalletConnect Example

WalletConnect requires a project ID from [WalletConnect Cloud](https://cloud.walletconnect.com/).

```typescript
import { 
  WalletConnector, 
  WalletConnectAdapter,
  MetamaskAdapter,
  WalletType 
} from '@tiwiflix/wallet-connector';

const connector = new WalletConnector({
  adapters: [
    new MetamaskAdapter(),
    new WalletConnectAdapter('YOUR_PROJECT_ID'), // Get from WalletConnect Cloud
  ],
  walletConnectProjectId: 'YOUR_PROJECT_ID',
});

// Connect via WalletConnect (shows QR code modal)
await connector.connect(WalletType.WALLETCONNECT);
```

### All Wallets Example

```typescript
import { 
  WalletConnector,
  // EVM
  MetamaskAdapter,
  TrustWalletAdapter,
  BitgetAdapter,
  BaseAdapter,
  AtomicAdapter,
  SafePalAdapter,
  RabbyAdapter,
  ExodusAdapter,
  WalletConnectAdapter,
  // Solana
  PhantomAdapter,
  SolflareAdapter,
  // TON
  TonkeeperAdapter,
  TonHubAdapter,
  MyTonWalletAdapter,
  // Tron
  TronLinkAdapter,
  KleverAdapter,
} from '@tiwiflix/wallet-connector';

const connector = new WalletConnector({
  adapters: [
    // EVM wallets
    new MetamaskAdapter(),
    new TrustWalletAdapter(),
    new BitgetAdapter(),
    new BaseAdapter(),
    new AtomicAdapter(),
    new SafePalAdapter(),
    new RabbyAdapter(),
    new ExodusAdapter(),
    new WalletConnectAdapter('YOUR_WALLETCONNECT_PROJECT_ID'),
    // Solana wallets
    new PhantomAdapter(),
    new SolflareAdapter(),
    // TON wallets
    new TonkeeperAdapter(),
    new TonHubAdapter(),
    new MyTonWalletAdapter(),
    // Tron wallets
    new TronLinkAdapter(),
    new KleverAdapter(),
  ],
  autoConnect: true,
});
```

## API Reference

### WalletConnector

#### Constructor

```typescript
new WalletConnector(config: WalletConnectorConfig)
```

**Config Options:**
- `adapters`: Array of wallet adapters to use
- `autoConnect?`: Auto-connect to previously connected wallet (default: false)
- `storageKey?`: Local storage key for persistence (default: 'tiwiflix_wallet')
- `walletConnectProjectId?`: WalletConnect project ID (required for WalletConnect)

#### Methods

- `getAvailableWallets()`: Get list of installed/available wallets
- `getAllWallets()`: Get list of all registered wallets
- `getWallet(type: WalletType)`: Get specific wallet adapter
- `connect(walletType: WalletType)`: Connect to a wallet
- `disconnect()`: Disconnect from current wallet
- `getAccount()`: Get current account
- `signMessage(message: string)`: Sign a message
- `signTransaction(transaction: any)`: Sign a transaction
- `checkNFTOwnership(collectionAddresses: string[])`: Check NFT ownership for TON wallets
- `getState()`: Get current connection state
- `on(event: WalletEvent, listener)`: Subscribe to events
- `off(event: WalletEvent, listener)`: Unsubscribe from events
- `destroy()`: Clean up resources

### Events

Subscribe to wallet events:

```typescript
// Account changed
connector.on(WalletEvent.ACCOUNT_CHANGED, (account) => {
  console.log('Account changed:', account);
});

// Connected
connector.on(WalletEvent.CONNECTED, (account) => {
  console.log('Connected:', account);
});

// Disconnected
connector.on(WalletEvent.DISCONNECTED, () => {
  console.log('Disconnected');
});

// Connection status changed
connector.on(WalletEvent.STATUS_CHANGED, (status) => {
  console.log('Status:', status);
});

// Error
connector.on(WalletEvent.ERROR, (error) => {
  console.error('Error:', error);
});
```

### NFT Checking

For TON wallets, you can check if a user owns NFTs from specific collections:

```typescript
// Check NFT ownership
const nftResult = await connector.checkNFTOwnership([
  'EQD8rUZqR_pWV1BylWUlPNBzyiTYVoBEmQkMIQDZXICfnuRr',
  'EQB2fNcjH2tppC1cO1R4W1qYdYdP5zAQy9y1k5z6b0p'
]);

if (nftResult.hasNFTs) {
  console.log('User has required NFTs!');
  console.log('Owned NFTs:', nftResult.ownedNFTs);
} else {
  console.log('User does not have required NFTs');
}
```

The `checkNFTOwnership` method returns:
- `hasNFTs`: Boolean indicating if user owns NFTs from any of the collections
- `collections`: Array of collection information
- `ownedNFTs`: Array of owned NFT details

### Types

#### ChainType
```typescript
enum ChainType {
  EVM = 'evm',
  SOLANA = 'solana',
  TON = 'ton',
  TRON = 'tron',
}
```

#### WalletType
```typescript
enum WalletType {
  METAMASK = 'metamask',
  TRUST_WALLET = 'trustwallet',
  BITGET = 'bitget',
  BASE = 'base',
  ATOMIC = 'atomic',
  SAFEPAL = 'safepal',
  WALLETCONNECT = 'walletconnect',
  TONKEEPER = 'tonkeeper',
  TONHUB = 'tonhub',
  MYTONWALLET = 'mytonwallet',
  SOLFLARE = 'solflare',
  PHANTOM = 'phantom',
  TRONLINK = 'tronlink',
  KLEVER = 'klever',
  RABBY = 'rabby',
  EXODUS = 'exodus',
}
```

#### Account
```typescript
interface Account {
  address: string;
  publicKey?: string;
  chainType: ChainType;
}
```

## Custom Wallet Adapters

You can create custom wallet adapters by extending the base adapter classes:

```typescript
import { EVMBaseAdapter, WalletType } from '@tiwiflix/wallet-connector';

class MyCustomWallet extends EVMBaseAdapter {
  readonly name = 'My Custom Wallet';
  readonly type = WalletType.METAMASK; // Use appropriate type
  readonly downloadUrl = 'https://mycustomwallet.com/';

  protected getProvider() {
    return window.myCustomWallet || null;
  }
}

// Use it
const connector = new WalletConnector({
  adapters: [new MyCustomWallet()],
});
```

Available base adapters:
- `EVMBaseAdapter` - For EVM-compatible wallets
- `SolanaBaseAdapter` - For Solana wallets
- `TONBaseAdapter` - For TON wallets
- `TronBaseAdapter` - For Tron wallets
- `BaseWalletAdapter` - For completely custom implementations

## Best Practices

1. **Install Only What You Need**: Only install peer dependencies for chains you use to keep bundle size small.

2. **Error Handling**: Always wrap wallet operations in try-catch blocks:
```typescript
try {
  await connector.connect(WalletType.METAMASK);
} catch (error) {
  // Handle connection errors
  if (error.message.includes('not installed')) {
    // Show install prompt
  }
}
```

3. **Event Cleanup**: Unsubscribe from events when components unmount:
```typescript
useEffect(() => {
  const unsubscribe = connector.on(WalletEvent.ACCOUNT_CHANGED, handler);
  return () => unsubscribe();
}, []);
```

4. **Storage**: Use custom storage keys if you have multiple connectors:
```typescript
const connector = new WalletConnector({
  adapters: [...],
  storageKey: 'my_app_wallet',
});
```

## Troubleshooting

### Wallet not detected
Some wallets inject their providers after page load. Wait for the `window.load` event or add a delay before checking availability.

### Multiple wallets conflict
If multiple wallets are installed, they may conflict. Use wallet-specific detection flags (e.g., `window.ethereum.isMetaMask`).

### TypeScript errors
Make sure all peer dependencies are installed for the chains you're using.

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

For issues and questions, please open an issue on [GitHub](https://github.com/tiwiflix/wallet-connector).

