> For the complete documentation index, see [llms.txt](https://hinkal-team.gitbook.io/hinkal/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hinkal-team.gitbook.io/hinkal/hinkal-mobile-sdk/ios/guides/transfers.md).

# Transfers

A private transfer sends tokens from your private balance to another Hinkal user's private balance (`private → private`). There is no public trace of sender, recipient, or amount. It runs server-side through a Hinkal relayer.

### Basic Transfer

SDK calls take an `NSError` out-parameter, wrapped here with the `call` helper from Getting Started.

```swift
let wei = try call { MobileAmountToWei(chainId, tokenAddress, "0.5", &$0) }
let txHash = try call {
    hinkal.transfer(
        chainId,
        tokenAddrsJSON: "[\"\(tokenAddress)\"]",
        amountsWeiJSON: "[\"\(wei)\"]",
        recipient: recipientPrivateAddress,
        feeToken: tokenAddress,
        feeStructureJSON: "",
        error: &$0
    )
}
print("Transfer tx:", txHash)
```

### Parameters

| Parameter          | Type     | Description                             |
| ------------------ | -------- | --------------------------------------- |
| `chainID`          | `Int64`  | Target chain id.                        |
| `tokenAddrsJSON`   | `String` | JSON array of token addresses.          |
| `amountsWeiJSON`   | `String` | JSON array of amounts in wei.           |
| `recipient`        | `String` | The recipient's Hinkal private address. |
| `feeToken`         | `String` | Token the relayer fee is paid in.       |
| `feeStructureJSON` | `String` | Fee quote, or empty for defaults.       |

### Recipient addresses

The recipient is a Hinkal private address. The recipient shares theirs via `getRecipientInfo`, and you can validate a value with `MobileIsValidPrivateAddress(_:)`:

```swift
guard MobileIsValidPrivateAddress(recipientPrivateAddress) else {
    // prompt the user to re-enter the address
    return
}
```

### Error Handling

```swift
do {
    let txHash = try call {
        hinkal.transfer(chainId, tokenAddrsJSON: "[\"\(tokenAddress)\"]", amountsWeiJSON: "[\"\(wei)\"]",
                        recipient: recipientPrivateAddress, feeToken: tokenAddress, feeStructureJSON: "", error: &$0)
    }
} catch {
    print("Transfer failed:", error.localizedDescription)
}
```

### Best Practices

#### 1. Validate the recipient

```swift
guard MobileIsValidPrivateAddress(recipient) else { return }
```

#### 2. Confirm the balance covers amount + fee

The fee is charged on top of the amount; ensure the shielded balance covers `amount + fee` (quote with the fee helpers on `MobileClient`).
