> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# External Wallets

> Instructions for using external wallets with the ParaSwift SDK.

export const DemoCallout = ({variant = "card", title = "Interactive Demo", description = "Try the live demo to explore authentication flows and customize your modal before integrating."}) => {
  if (variant === "subtle") {
    return <div className="not-prose my-4 px-4 py-3 rounded-xl border border-orange-200 bg-orange-50/50">
        <div className="flex items-center justify-between gap-4">
          <p className="text-sm text-gray-700 m-0">
            {description}
          </p>
          <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose flex-shrink-0 inline-flex items-center gap-2 px-3 py-1.5 text-xs font-semibold text-orange-600 bg-white border border-orange-200 rounded-lg hover:bg-orange-50 transition-colors no-underline">
            Try Demo
            <svg width="12" height="12" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
              <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="currentColor" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </a>
        </div>
      </div>;
  }
  return <a href="https://demo.getpara.com/" target="_blank" rel="noopener noreferrer" className="not-prose block my-4 p-5 rounded-xl bg-gradient-to-r from-orange-600 via-pink-600 to-purple-600 hover:opacity-95 transition-opacity no-underline">
      <div className="flex items-center justify-between gap-4">
        <div>
          <h3 className="text-base font-semibold text-white m-0">{title}</h3>
          <p className="text-xs text-white/80 mt-1 m-0">{description}</p>
        </div>
        <div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center">
          <svg width="14" height="14" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M40 472L472 40M472 40H83.2M472 40V428.8" stroke="white" strokeWidth="66.6667" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </div>
      </div>
    </a>;
};

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

## Overview

This guide outlines how to integrate and use external cryptocurrency wallets with the ParaSwift SDK. With the unified wallet architecture, the Swift SDK has removed all blockchain-specific dependencies and now provides a streamlined approach to external wallet connectivity.

The SDK supports external wallets like MetaMask through deep-linking protocols and provides built-in authentication and transaction signing capabilities. You can also use external wallet addresses to authenticate with Para.

<Note>
  **Unified Wallet Architecture:** The Swift SDK uses only BigInt for handling blockchain values and avoids blockchain-specific package dependencies such as web3swift or solana-swift. This provides a cleaner, more maintainable architecture while still supporting all necessary external wallet operations.

  The SDK now has minimal dependencies:

  * **BigInt**: For handling large blockchain numbers (Wei, gas values, etc.)
  * **PhoneNumberKit**: For phone number validation in authentication flows
</Note>

## Deep Linking

The ParaSwift SDK communicates with other apps via deep linking. To enable deep linking for your application, you'll need to configure your app appropriately.

### Configure URL Schemes

First, you need to configure your app to handle custom URL schemes:

1. Open your app's Info.plist file
2. Add a new entry for `LSApplicationQueriesSchemes` as an array
3. Add the URL schemes of supported wallets as strings to this array

```xml theme={null}
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>metamask</string>
</array>
```

### Configure URL Types

Next, you need to set up URL Types to handle callbacks from external wallets:

1. In Xcode, select your app target
2. Go to "Info" tab
3. Expand "URL Types"
4. Click the "+" button to add a new URL Type
5. Set the "Identifier" to your app's bundle identifier
6. Set the "URL Schemes" to a unique identifier for your app

<Warning>
  **Important:** You must use a unique URL scheme to avoid conflicts with other apps. We recommend using reverse-domain notation like `com.yourcompany.yourapp`.

  In our examples we use `paraswift`, but you **must replace this** with your own unique scheme:

  ```xml theme={null}
  <!-- In Info.plist -->
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
      <key>CFBundleURLSchemes</key>
      <array>
        <!-- Replace with your unique scheme -->
        <string>com.yourcompany.yourapp</string>
      </array>
    </dict>
  </array>
  ```
</Warning>

## MetaMask Connector

### Setup

Create and initialize the MetaMask connector with your app's configuration:

```swift theme={null}
import ParaSwift

// Create MetaMask configuration
let appScheme = "com.yourcompany.yourapp" // Replace with your unique scheme
let metaMaskConfig = MetaMaskConfig(
    appName: "Your App Name",
    appId: appScheme,
    apiVersion: "1.0"
)

// Initialize the connector
let metaMaskConnector = MetaMaskConnector(
    para: paraManager,
    appUrl: "https://\(appScheme)",
    config: metaMaskConfig
)
```

### Handle Deep Links

Handle incoming deep links from MetaMask by adding a URL handler in your SwiftUI app:

```swift theme={null}
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    // Handle MetaMask deep links with URL validation
                    if url.scheme == "yourapp", url.host == "mmsdk" {
                        MetaMaskConnector.handleDeepLink(url)
                    }
                }
        }
    }
}
```

<Note>
  The deep link handling has been simplified to use a static method. You no longer need to maintain a MetaMaskConnector instance at the app level just for handling deep links.
</Note>

### Connecting

To connect to MetaMask and retrieve the user's accounts:

```swift theme={null}
do {
    try await metaMaskConnector.connect()
    // MetaMask will automatically attempt Para authentication after connection
    // Access connected accounts via metaMaskConnector.accounts
} catch {
    // Handle connection error
}
```

<Note>
  **Automatic Authentication:** The MetaMask connector automatically attempts to authenticate with Para after a successful connection. This streamlines the user experience by reducing the number of manual steps required.
</Note>

### Sign Message

To request a signature for a message from MetaMask:

```swift theme={null}
guard let account = metaMaskConnector.accounts.first else { return }

do {
    let signature = try await metaMaskConnector.signMessage(
        "Message to sign! Hello World",
        account: account
    )
    // Use the signature
} catch {
    // Handle signing error
}
```

### Send Transaction

To send a transaction through MetaMask using the EVMTransaction model:

```swift theme={null}
import BigInt

guard let account = metaMaskConnector.accounts.first else { return }

do {
    // Convert 0.001 ETH to wei (1 ETH = 10^18 wei)
    let valueInWei = BigUInt("1000000000000000")! // 0.001 ETH in wei
    let gasLimit = BigUInt(100000)

    let transaction = EVMTransaction(
        to: "0x13158486860B81Dee9e43Dd0391e61c2F82B577F",
        value: valueInWei,
        gasLimit: gasLimit
    )

    let txHash = try await metaMaskConnector.sendTransaction(transaction, account: account)
    // Transaction sent successfully, use txHash
} catch {
    // Handle transaction error
}
```

### Alternative: Raw Transaction Format

You can also use a raw transaction dictionary format:

```swift theme={null}
guard let account = metaMaskConnector.accounts.first else { return }

let transaction: [String: String] = [
    "from": account,
    "to": "0x13158486860B81Dee9e43Dd0391e61c2F82B577F",
    "value": "0x38D7EA4C68000", // 0.001 ETH in wei (hex)
    "gasLimit": "0x186A0" // 100000 in hex
]

do {
    let txHash = try await metaMaskConnector.sendTransaction(
        transaction,
        account: account
    )
    // Transaction sent successfully
} catch {
    // Handle transaction error
}
```

### Properties

The MetaMask connector provides several useful properties:

```swift theme={null}
// Check if connected to MetaMask
let isConnected = metaMaskConnector.isConnected

// Get list of connected accounts
let accounts = metaMaskConnector.accounts

// Get current chain ID (e.g., "0x1" for Ethereum mainnet)
let chainId = metaMaskConnector.chainId
```

### Supported Networks

The MetaMask connector works with any EVM-compatible network that MetaMask supports. Common networks include:

| Network          | Chain ID   | Description           |
| ---------------- | ---------- | --------------------- |
| Ethereum Mainnet | `0x1`      | Main Ethereum network |
| Sepolia Testnet  | `0xaa36a7` | Ethereum test network |
| Polygon          | `0x89`     | Polygon mainnet       |
| Arbitrum One     | `0xa4b1`   | Arbitrum Layer 2      |
| Base             | `0x2105`   | Base Layer 2          |

## Working with BigUInt Values

Since the Swift SDK now uses BigInt for handling blockchain values, here are some utility patterns for working with Ether and Wei conversions:

```swift theme={null}
import BigInt

// Convert Ether to Wei (multiply by 10^18)
func etherToWei(_ ether: String) -> BigUInt? {
    guard let etherDecimal = Decimal(string: ether) else { return nil }
    let weiDecimal = etherDecimal * pow(10, 18)
    return BigUInt(weiDecimal.description.components(separatedBy: ".").first ?? "")
}

// Convert Wei to Ether (divide by 10^18)
func weiToEther(_ wei: BigUInt) -> String {
    let weiDecimal = Decimal(string: wei.description) ?? 0
    let etherDecimal = weiDecimal / pow(10, 18)
    return etherDecimal.description
}

// Usage examples
let oneEthInWei = etherToWei("1.0")! // 1000000000000000000
let halfEthInWei = etherToWei("0.5")! // 500000000000000000
let pointZeroOneEthInWei = etherToWei("0.01")! // 10000000000000000

// Convert back to Ether
let ethAmount = weiToEther(BigUInt("1000000000000000000")!) // "1"
```

<Note>
  These utility functions help you convert between human-readable Ether amounts and the Wei values required by the blockchain. Always validate decimal inputs to prevent runtime crashes.
</Note>

## Advanced Configuration

### Customizing MetaMask Connection

You can customize various aspects of the MetaMask connection by modifying the MetaMaskConfig:

```swift theme={null}
let metaMaskConfig = MetaMaskConfig(
    appName: "Your App Name",
    appId: bundleId,
    apiVersion: "1.0"
)
```

### Working with Different Networks

MetaMask supports multiple networks. You can check the current network and adjust your app's behavior accordingly:

```swift theme={null}
switch metaMaskConnector.chainId {
case "0x1":
    // Ethereum Mainnet
case "0x5":
    // Goerli Testnet
case "0x89":
    // Polygon
default:
    // Other network
}
```

## External Wallet Authentication with Para

Para supports authentication using external wallets like MetaMask. This allows users to log into Para using their existing wallet credentials.

### Using External Wallet for Para Login

After connecting to MetaMask, you can use the wallet address to authenticate with Para:

```swift theme={null}
// First, connect to MetaMask
try await metaMaskConnector.connect()

// Get the first connected account
guard let account = metaMaskConnector.accounts.first else {
    throw ParaError.error("No MetaMask accounts found")
}

// Create external wallet info for Para authentication
let externalWallet = ExternalWalletInfo(
    address: account,
    type: .evm,
    provider: "metamask",
    isConnectionOnly: false // Set to false for full authentication
)

// Login to Para using the external wallet
try await paraManager.loginExternalWallet(wallet: externalWallet)

// User is now logged into Para with their MetaMask wallet
```

### Complete External Wallet Login Example

Here's a complete example showing external wallet authentication:

```swift theme={null}
import SwiftUI
import ParaSwift

struct ExternalWalletLoginView: View {
    @EnvironmentObject var paraManager: ParaManager
    @EnvironmentObject var appRootManager: AppRootManager
    @StateObject private var metaMaskConnector: MetaMaskConnector

    @State private var isConnecting = false
    @State private var errorMessage: String?

    init(paraManager: ParaManager) {
        let config = MetaMaskConfig(
            appName: "Your App",
            appId: "com.yourcompany.yourapp", // Use your unique app scheme
            apiVersion: "1.0"
        )

        _metaMaskConnector = StateObject(wrappedValue: MetaMaskConnector(
            para: paraManager,
            appUrl: "https://com.yourcompany.yourapp", // Use your unique app scheme
            config: config
        ))
    }

    var body: some View {
        VStack(spacing: 20) {
            Image("metamask")
                .resizable()
                .frame(width: 80, height: 80)

            Text("Connect with MetaMask")
                .font(.title2)
                .fontWeight(.semibold)

            Text("Use your existing MetaMask wallet to log into Para")
                .font(.body)
                .foregroundColor(.secondary)
                .multilineTextAlignment(.center)

            if let errorMessage = errorMessage {
                Text(errorMessage)
                    .foregroundColor(.red)
                    .font(.caption)
                    .padding()
                    .background(Color.red.opacity(0.1))
                    .cornerRadius(8)
            }

            Button {
                connectAndLogin()
            } label: {
                if isConnecting {
                    ProgressView()
                        .tint(.white)
                } else {
                    Text("Connect MetaMask")
                        .fontWeight(.semibold)
                }
            }
            .frame(maxWidth: .infinity)
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(10)
            .disabled(isConnecting)
        }
        .padding()
        .navigationTitle("External Wallet")
    }

    private func connectAndLogin() {
        isConnecting = true
        errorMessage = nil

        Task {
            do {
                // Connect to MetaMask
                try await metaMaskConnector.connect()

                // Get the first account
                guard let account = metaMaskConnector.accounts.first else {
                    throw ParaError.error("No MetaMask accounts found")
                }

                // Create external wallet info
                let externalWallet = ExternalWalletInfo(
                    address: account,
                    type: .evm,
                    provider: "metamask",
                    isConnectionOnly: false // Set to false for full authentication
                )

                // Login to Para using external wallet
                try await paraManager.loginExternalWallet(wallet: externalWallet)

                // Navigate to home on success
                appRootManager.currentRoot = .home

            } catch {
                errorMessage = error.localizedDescription
            }

            isConnecting = false
        }
    }
}
```
