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

# Transfers

# Private Transfers

This guide covers sending tokens privately between privacy addresses.

## Basic Transfer

```swift theme={null}
do {
    let result = try await sdk.send(
        tokenAddress: "0x...token-address",
        amount: "1000000000000000000", // 1 token
        recipientPrivacyAddress: "0x04..." // 194-char privacy address
    )
    print("Transaction hash: \(result.txHash)")
} catch {
    print("Transfer failed: \(error)")
}
```

## Transfer Parameters

| Parameter                 | Type     | Required | Description                               |
| ------------------------- | -------- | -------- | ----------------------------------------- |
| `tokenAddress`            | `String` | Yes      | Token contract address                    |
| `amount`                  | `String` | Yes      | Amount in wei (smallest unit)             |
| `recipientPrivacyAddress` | `String` | Yes      | Recipient's 194-character privacy address |

## Transfer Result

```swift theme={null}
struct TransferResult {
    let txHash: String  // Transaction hash
    let fee: String     // Fee paid (in wei)
}
```

## Privacy Address Validation

Always validate privacy addresses before sending:

```swift theme={null}
let recipientAddress = "0x04..."

guard sdk.isValidPrivacyAddress(recipientAddress) else {
    print("Invalid privacy address")
    return
}

let result = try await sdk.send(
    tokenAddress: "0x...",
    amount: "1000000000000000000",
    recipientPrivacyAddress: recipientAddress
)
```

## Looking Up Privacy Addresses

If you have a user's MPK or Ethereum address, you can look up their privacy address:

```swift theme={null}
do {
    let identity = try await sdk.resolveIdentity(identifier: "0x...ethereum-address")
    print("Privacy address: \(identity.privacyAddress)")

    // Now send to their privacy address
    let result = try await sdk.send(
        tokenAddress: "0x...",
        amount: "1000000000000000000",
        recipientPrivacyAddress: identity.privacyAddress
    )
} catch {
    print("Address lookup failed: \(error)")
}
```

## Checking Balance Before Transfer

```swift theme={null}
func safeTransfer(
    tokenAddress: String,
    amount: String,
    recipient: String
) async throws -> TransferResult {
    let balance = try await sdk.getBalance(tokenAddress: tokenAddress)

    guard let shielded = UInt64(balance.shieldedBalance),
          let requested = UInt64(amount),
          requested <= shielded else {
        throw SDKError.insufficientBalance(message: "Insufficient shielded balance")
    }

    return try await sdk.send(
        tokenAddress: tokenAddress,
        amount: amount,
        recipientPrivacyAddress: recipient
    )
}
```

## Transfer Privacy

Private transfers provide:

* **Sender Privacy**: Your wallet address is not linked to the transaction
* **Recipient Privacy**: The recipient's wallet address is not revealed
* **Amount Privacy**: The transfer amount is encrypted
* **Relationship Privacy**: No public link between sender and recipient

Only the sender and recipient can see the transfer details.

## Error Handling

```swift theme={null}
do {
    let result = try await sdk.send(
        tokenAddress: tokenAddress,
        amount: amount,
        recipientPrivacyAddress: recipient
    )
} catch SDKError.insufficientBalance {
    print("Not enough shielded balance")
} catch SDKError.invalidAddress {
    print("Invalid privacy address")
} catch SDKError.invalidAmount {
    print("Invalid amount")
} catch SDKError.walletError(let message) {
    print("Wallet error: \(message)")
} catch SDKError.networkError(let message) {
    print("Network error: \(message)")
} catch SDKError.transferError(let code, let message) {
    print("Transfer error [\(code)]: \(message)")
} catch {
    print("Transfer error: \(error)")
}
```

## Best Practices

### 1. Validate All Inputs

```swift theme={null}
func validateTransfer(
    tokenAddress: String,
    amount: String,
    recipient: String
) throws {
    guard sdk.isValidAddress(tokenAddress) else {
        throw SDKError.invalidAddress
    }
    guard sdk.isValidPrivacyAddress(recipient) else {
        throw SDKError.invalidAddress
    }
    guard let value = UInt64(amount), value > 0 else {
        throw SDKError.invalidAmount
    }
}
```

### 2. Confirm Large Transfers

```swift theme={null}
func transferWithConfirmation(
    tokenAddress: String,
    amount: String,
    recipient: String,
    onConfirm: (String) async -> Bool
) async throws -> TransferResult {
    let formatted = try sdk.formatAmount(amount, decimals: 18)

    guard await onConfirm("Send \(formatted) tokens to \(recipient.prefix(10))...?") else {
        throw SDKError.signatureRejected
    }

    return try await sdk.send(
        tokenAddress: tokenAddress,
        amount: amount,
        recipientPrivacyAddress: recipient
    )
}
```

### 3. Handle Network Delays

```swift theme={null}
func transferWithRetry(
    tokenAddress: String,
    amount: String,
    recipient: String,
    maxRetries: Int = 3
) async throws -> TransferResult {
    for attempt in 1...maxRetries {
        do {
            return try await sdk.send(
                tokenAddress: tokenAddress,
                amount: amount,
                recipientPrivacyAddress: recipient
            )
        } catch SDKError.networkError(_) where attempt < maxRetries {
            try await Task.sleep(nanoseconds: UInt64(2_000_000_000 * attempt))
            continue
        }
    }
    throw SDKError.networkError("Max retries exceeded")
}
```

## Next Steps

* [Deposits Guide](./deposits)
* [Withdrawals Guide](./withdrawals)
* [Balances Guide](./balances)
* [Error Handling](./error-handling)
