Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/frol/near-connect-ios/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The sendNEAR() method provides a simple way to transfer NEAR tokens from the connected account to any receiver. The wallet handles transaction signing and broadcasting.

Basic Transfer

Send NEAR tokens to another account:
do {
    let result = try await walletManager.sendNEAR(
        to: "bob.near",
        amountYocto: "1000000000000000000000000"  // 1 NEAR
    )
    print("Transaction hash: \(result.transactionHashes.first ?? "")")
} catch {
    print("Transfer failed: \(error.localizedDescription)")
}
NEAR amounts must be specified in yoctoNEAR (1 NEAR = 10²⁴ yoctoNEAR). Use the conversion utilities to convert from human-readable amounts.

Amount Conversion

Convert between NEAR and yoctoNEAR:
// Convert "1.5" NEAR to yoctoNEAR
if let yocto = NEARWalletManager.toYoctoNEAR("1.5") {
    print(yocto)  // "1500000000000000000000000"
}

Complete Example

Here’s the real transfer flow from the example app:
import SwiftUI
import NEARConnect

struct TransactionDemoView: View {
    @EnvironmentObject var walletManager: NEARWalletManager
    @State private var receiverId = ""
    @State private var amount = "0.01"
    @State private var isProcessing = false
    @State private var showError = false
    @State private var errorMessage = ""
    
    var body: some View {
        Form {
            Section(header: Text("Transfer Details")) {
                HStack {
                    Text("From")
                        .foregroundColor(.secondary)
                    Spacer()
                    Text(walletManager.currentAccount?.accountId ?? "")
                        .font(.caption)
                }
                
                TextField("Receiver (e.g., bob.near)", text: $receiverId)
                    .textInputAutocapitalization(.never)
                    .autocorrectionDisabled()
                
                HStack {
                    TextField("Amount", text: $amount)
                        .keyboardType(.decimalPad)
                    Text("NEAR")
                        .foregroundColor(.secondary)
                }
            }
            
            Section {
                Button(action: sendTransaction) {
                    HStack {
                        Spacer()
                        if isProcessing {
                            ProgressView()
                                .padding(.trailing, 8)
                        }
                        Text(isProcessing ? "Sending..." : "Send NEAR")
                        Spacer()
                    }
                }
                .disabled(isProcessing || receiverId.isEmpty || amount.isEmpty)
            }
        }
        .alert("Error", isPresented: $showError) {
            Button("OK", role: .cancel) { }
        } message: {
            Text(errorMessage)
        }
    }
    
    private func sendTransaction() {
        guard let yocto = NEARWalletManager.toYoctoNEAR(amount) else {
            errorMessage = "Invalid amount"
            showError = true
            return
        }
        
        Task {
            isProcessing = true
            defer { isProcessing = false }
            
            do {
                let txResult = try await walletManager.sendNEAR(
                    to: receiverId,
                    amountYocto: yocto
                )
                let hashes = txResult.transactionHashes.joined(separator: ", ")
                print("✅ Transaction hashes: \(hashes)")
            } catch {
                errorMessage = error.localizedDescription
                showError = true
            }
        }
    }
}

Transaction Result

The sendNEAR() method returns a TransactionResult:
public struct TransactionResult {
    public let transactionHashes: [String]
    public let rawResult: String?
}

Accessing Transaction Data

let result = try await walletManager.sendNEAR(
    to: "receiver.near",
    amountYocto: yoctoAmount
)

// Get transaction hash(es)
if let hash = result.transactionHashes.first {
    print("Transaction hash: \(hash)")
    
    // Build NEAR Explorer URL
    let explorerURL: String
    if walletManager.network == .mainnet {
        explorerURL = "https://nearblocks.io/txns/\(hash)"
    } else {
        explorerURL = "https://testnet.nearblocks.io/txns/\(hash)"
    }
    print("View on explorer: \(explorerURL)")
}

// Raw result from wallet (if available)
if let raw = result.rawResult {
    print("Raw result: \(raw)")
}

Error Handling

Handle common transfer errors:
do {
    let result = try await walletManager.sendNEAR(
        to: receiverId,
        amountYocto: yoctoAmount
    )
    print("✅ Transfer successful")
} catch NEARError.notSignedIn {
    print("❌ Please connect a wallet first")
} catch NEARError.operationInProgress {
    print("❌ Another operation is in progress")
} catch NEARError.webViewNotReady {
    print("❌ Wallet bridge not ready, please wait")
} catch NEARError.walletError(let message) {
    print("❌ Wallet error: \(message)")
} catch {
    print("❌ Unexpected error: \(error.localizedDescription)")
}
The sendNEAR() method requires an active wallet connection. Check walletManager.isSignedIn before calling.

Handling User Rejection

Users can reject transactions in the wallet UI:
Task {
    do {
        let result = try await walletManager.sendNEAR(
            to: receiverId,
            amountYocto: yoctoAmount
        )
        // Transaction approved and sent
        showSuccessMessage("Transfer sent!")
    } catch NEARError.walletError(let message) {
        if message.contains("Cancelled") || message.contains("rejected") {
            // User cancelled - this is not an error
            print("User cancelled transaction")
        } else {
            // Actual error
            showErrorMessage(message)
        }
    } catch {
        showErrorMessage(error.localizedDescription)
    }
}

Validation Best Practices

1

Validate receiver account

Check that the receiver ID is not empty and follows NEAR account format:
func isValidAccountId(_ accountId: String) -> Bool {
    // Basic validation: non-empty, lowercase, contains valid characters
    let pattern = "^[a-z0-9._-]+$"
    return !accountId.isEmpty && 
           accountId.range(of: pattern, options: .regularExpression) != nil
}
2

Validate amount

Ensure the amount is valid and can be converted to yoctoNEAR:
guard let yocto = NEARWalletManager.toYoctoNEAR(amount),
      !yocto.isEmpty,
      yocto != "0" else {
    showError("Invalid amount")
    return
}
3

Check sufficient balance (optional)

Query the account balance before sending:
do {
    let accountInfo = try await walletManager.viewAccount()
    if let balanceStr = accountInfo["amount"] as? String,
       let balance = Decimal(string: balanceStr),
       let sendAmount = Decimal(string: yocto),
       sendAmount > balance {
        showError("Insufficient balance")
        return
    }
} catch {
    // Balance check failed, proceed anyway (wallet will reject if insufficient)
}

Displaying Balance

Fetch and display the connected account’s balance:
struct BalanceView: View {
    @EnvironmentObject var walletManager: NEARWalletManager
    @State private var balance: String?
    
    var body: some View {
        VStack {
            if let balance {
                Text("\(balance) NEAR")
                    .font(.title2)
            } else {
                ProgressView()
            }
        }
        .task {
            await fetchBalance()
        }
    }
    
    private func fetchBalance() async {
        do {
            let result = try await walletManager.viewAccount()
            if let amountStr = result["amount"] as? String {
                balance = NEARWalletManager.formatNEAR(yoctoNEAR: amountStr)
            }
        } catch {
            print("Failed to fetch balance: \(error)")
        }
    }
}

Advanced: Custom Actions

For more control, use signAndSendTransaction() with custom actions:
let actions: [[String: Any]] = [
    [
        "type": "Transfer",
        "params": ["deposit": yoctoAmount]
    ]
]

let result = try await walletManager.signAndSendTransaction(
    receiverId: receiverId,
    actions: actions
)
This allows combining multiple actions in a single transaction (e.g., transfer + function call).

Next Steps