> ## 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.

# Claimable transfers

# Claimable Transfers (Gifts)

Send shielded funds to an Ethereum wallet address that has not registered with
Privacy Boost yet. The recipient claims by proving ownership of that address; you
reclaim the funds if they never do. See
[Claimable Transfers](/sdk/concepts/claimable-transfers) for the concept and
trust model.

<Warning>
  **Preview feature — pending external audit, and enabled per deployment.** Gift
  methods are called directly on the `PrivacyBoost` instance (`sdk` below). They
  may not be present in the checked-in generated Swift bindings, so the code
  blocks here are illustrative and not verified against the published build.
</Warning>

## Sending a gift

The most common case: you know the recipient's wallet address but they have not
joined Privacy Boost. Use `giftFundToWallet`. Every fund/claim/refund call
returns a `TransferResult`.

```swift theme={null}
// Read the current chain head from your own RPC / chain client.
// Refund deadline: a block height after which you can reclaim an unclaimed gift.
// The min/max delay is advertised from the server's /info endpoint.
let currentBlock: UInt64 = try await myRpcClient.blockNumber()
let refundAfterBlock = currentBlock + 50_000

do {
    let result = try await sdk.giftFundToWallet(
        tokenAddress: "0x...token-address",
        amount: "1000000000000000000", // 1 token, in wei
        recipientWallet: "0xRecipientEoaAddress",
        refundAfterBlock: refundAfterBlock,
        currentBlock: currentBlock
    )
    print("Funded gift: \(result.txHash)")
    if let link = result.claimLink {
        print("Share this claim link with the recipient: \(link)")
    }
    // Persist result.giftRecord so you can refund later (see "Refunding" below).
    if let record = result.giftRecord {
        saveGiftRecord(record)
    }
} catch {
    print("Gift funding failed: \(error)")
}
```

If the recipient is already a Privacy Boost user, fund with their privacy address
too (`giftFund`) so the gift ciphertext is sealed to their viewing key for the
smoothest discovery. Note the argument label is `recipientPrivacyAddress` — the
194-char privacy address — alongside the recipient's wallet:

```swift theme={null}
let result = try await sdk.giftFund(
    tokenAddress: "0x...token-address",
    amount: "1000000000000000000",
    recipientPrivacyAddress: "0x04...recipient-privacy-address", // 194-char privacy address
    recipientWallet: "0xRecipientEoaAddress",
    refundAfterBlock: refundAfterBlock,
    currentBlock: currentBlock
)
```

### Funding parameters

| Parameter                 | Type     | Required        | Description                                                          |
| ------------------------- | -------- | --------------- | -------------------------------------------------------------------- |
| `tokenAddress`            | `String` | Yes             | Token contract address                                               |
| `amount`                  | `String` | Yes             | Amount in wei (smallest unit)                                        |
| `recipientPrivacyAddress` | `String` | `giftFund` only | Recipient's 194-char privacy address (the ciphertext's ECDH target)  |
| `recipientWallet`         | `String` | Yes             | Recipient's Ethereum address the gift binds to (may be unregistered) |
| `refundAfterBlock`        | `UInt64` | Yes             | Block height after which you may reclaim an unclaimed gift           |
| `currentBlock`            | `UInt64` | Yes             | Current chain head; pre-validates the refund delay before submitting |

<Warning>
  The gift binds **irrevocably** to `recipientWallet`. A wrong-but-valid address
  can be claimed by whoever controls it, and only an unclaimed gift is
  refundable. Show the exact checksummed address and require explicit
  confirmation before funding.
</Warning>

### Funding result

`giftFund` / `giftFundToWallet` return a `TransferResult` carrying two optional
gift fields:

```swift theme={null}
struct TransferResult {
    let requestId: String
    let txHash: String
    let fee: String                 // Fee paid (in wei)
    let giftRecord: GiftRecord?     // persist this — it makes the gift refundable
    let claimLink: String?          // pbgift:v1:... — share with the recipient
}
```

## Sharing the claim link

`result.claimLink` is a `pbgift:v1:...` string that carries the encrypted opening
the recipient needs. Share it out of band (message, QR code). Treat it like a
password — it reveals the gift's amount and recipient to anyone who reads it.

## Claiming a gift

The recipient registers Privacy Boost with the same wallet address, then claims.

List the pending gifts addressed to the authenticated wallet:

```swift theme={null}
let pending = try await sdk.getPendingGifts()
for gift in pending {
    print("#\(gift.index): \(gift.amount) of token \(gift.tokenId)")
}
```

Claim one by its position in that list, or — more robustly — by its stable
commitment `cGift` (the list can shift as gifts settle):

```swift theme={null}
// By index (positional):
let claimed = try await sdk.giftClaim(index: 0, acknowledgeUnknownSender: true)

// By stable commitment (preferred when the list may change):
let claimed = try await sdk.giftClaimByCGift(
    cGift: pending[0].cGift,
    acknowledgeUnknownSender: true
)
```

Or claim straight from a claim link, without a server lookup first:

```swift theme={null}
let claimed = try await sdk.giftClaimFromLink(
    link: "pbgift:v1:...",
    acknowledgeUnknownSender: true
)
```

<Info>
  `acknowledgeUnknownSender` must be `true` to claim. The hidden-sender model
  cannot reveal who funded a gift, so the recipient explicitly acknowledges
  accepting funds from an unknown sender. Surface this as a consent prompt.
</Info>

A successful claim re-mints the gift into a normal shielded note — from then on it
behaves like any other note in the recipient's balance.

## Refunding an unclaimed gift

A claim and a refund spend the same nullifier, so only one can ever settle. After
the refund deadline passes, reclaim an unclaimed gift using the local record you
saved at funding time.

```swift theme={null}
// Records the SDK persisted for gifts you funded:
let records = sdk.getGiftRecords()

// Refund the one at index 0 (a positional UInt32, not a record value):
let refunded = try await sdk.giftRefundByRecord(index: 0)
```

<Info>
  Gift records are what make a gift refundable. They are included in an
  [exported session](/sdk/ios/guides/session-storage), so persisting and restoring
  the session keeps your unclaimed gifts refundable across restarts. If you ever
  lose the record, you can still refund by supplying every field manually via
  `giftRefund(recipientWallet:, blind:, refundAfterBlock:, tokenId:, amount:, fundingTreeNumber:, giftLeafIndex:)`.
</Info>

## Previewing a claim link offline

Decode a claim link into a preview with no network call — useful to show the
recipient what they are about to accept. `decodeGiftLink` is synchronous and
offline (throwing, no `await`):

```swift theme={null}
let preview = try sdk.decodeGiftLink(link: "pbgift:v1:...")
print(preview.amount, preview.tokenId, preview.recipientWallet, preview.refundAfterBlock)
```

## Types

```swift theme={null}
struct GiftRecord {
    let recipientWallet: String
    let blind: String
    let refundAfterBlock: UInt64
    let tokenId: UInt16
    let amount: String
    let cGift: String
    let giftNpk: String
    let requestId: String
    let fundingTreeNumber: UInt64?
    let giftLeafIndex: UInt64?
    let status: String?
}

struct PendingGift {
    let index: UInt32
    let treeNumber: UInt64
    let leafIndex: UInt64
    let cGift: String
    let tokenId: UInt16
    let amount: String
    let refundAfterBlock: UInt64
    let recipientWallet: String
}

struct GiftLinkPreview {
    let server: String
    let chainId: UInt64
    let cGift: String
    let recipientWallet: String
    let tokenId: UInt16
    let amount: String
    let refundAfterBlock: UInt64
}
```

<Info>
  A third funding mode, `giftFundSecretBearer`, binds a gift to a secret instead
  of a wallet so it can be claimed before the recipient has any wallet. It is
  **experimental, disabled by default, and a bearer instrument** (whoever holds
  the link can claim). See the [concept page](/sdk/concepts/claimable-transfers)
  before considering it.
</Info>
