Skip to main content

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.

Private Transfers

This guide covers sending tokens privately between privacy addresses.

Basic Transfer

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

ParameterTypeRequiredDescription
tokenAddressStringYesToken contract address
amountStringYesAmount in wei (smallest unit)
recipientPrivacyAddressStringYesRecipient’s 194-character privacy address

Transfer Result

struct TransferResult {
    let txHash: String  // Transaction hash
    let fee: String     // Fee paid (in wei)
}

Privacy Address Validation

Always validate privacy addresses before sending:
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:
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

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
    }

    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

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

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

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

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