> ## 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 exposed on the underlying WASM SDK (`sdk.wasm`), so the code blocks
  below are illustrative and not type-checked 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`.

```typescript theme={null}
// 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.
const currentBlock = Number(await publicClient.getBlockNumber());
const refundAfterBlock = currentBlock + 50_000;

const result = await sdk.wasm.giftFundToWallet({
  tokenAddress: '0x...token-address',
  amount: '1000000000000000000', // 1 token, in wei
  recipientWallet: '0xRecipientEoaAddress',
  refundAfterBlock,
  currentBlock,
});

console.log('Funded gift:', result.txHash);
console.log('Share this claim link with the recipient:', result.claimLink);

// Persist result.giftRecord so you can refund later (see "Refunding" below).
saveGiftRecord(result.giftRecord);
```

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:

```typescript theme={null}
const result = await sdk.wasm.giftFund({
  tokenAddress: '0x...token-address',
  amount: '1000000000000000000',
  recipient: '0x04...recipient-privacy-address', // 194-char privacy address
  recipientWallet: '0xRecipientEoaAddress',
  refundAfterBlock,
  currentBlock,
});
```

### Funding parameters

| Parameter          | Type     | Required        | Description                                                          |
| ------------------ | -------- | --------------- | -------------------------------------------------------------------- |
| `tokenAddress`     | `string` | Yes             | Token contract address                                               |
| `amount`           | `string` | Yes             | Amount in wei (smallest unit)                                        |
| `recipient`        | `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` | `number` | Yes             | Block height after which you may reclaim an unclaimed gift           |
| `currentBlock`     | `number` | 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` extended with two gift
fields:

```typescript theme={null}
interface TransferResult {
  requestId: string;
  txHash: string;
  giftRecord?: GiftRecord; // persist this — it makes the gift refundable
  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:

```typescript theme={null}
const pending = await sdk.wasm.getPendingGifts();
for (const gift of pending) {
  console.log(`#${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):

```typescript theme={null}
// By index (positional):
await sdk.wasm.giftClaim({ index: 0, acknowledgeUnknownSender: true });

// By stable commitment (preferred when the list may change):
await sdk.wasm.giftClaimByCGift({ cGift: pending[0].cGift, acknowledgeUnknownSender: true });
```

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

```typescript theme={null}
await sdk.wasm.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.

```typescript theme={null}
// Records the SDK persisted for gifts you funded:
const records = sdk.wasm.getGiftRecords();

// Refund the one at index 0:
await sdk.wasm.giftRefundByRecord(0);
```

<Info>
  Gift records are what make a gift refundable. They are included in an
  [exported session](/sdk/typescript/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, treeNumber, leafIndex })`.
</Info>

## Previewing a claim link offline

Decode and decrypt a claim link into a preview without any network call — useful
to show the recipient what they are about to accept:

```typescript theme={null}
const preview = sdk.wasm.decodeGiftLink('pbgift:v1:...');
console.log(preview.amount, preview.tokenId, preview.recipientWallet, preview.refundAfterBlock);
```

## Types

```typescript theme={null}
interface GiftRecord {
  recipientWallet: string;
  blind: string;
  refundAfterBlock: number;
  tokenId: number;
  amount: string;
  cGift: string;
  giftNpk: string;
  requestId: string;
  fundingTreeNumber?: number;
  giftLeafIndex?: number;
  status?: string;
}

interface PendingGift {
  index: number;
  treeNumber: number;
  leafIndex: number;
  cGift: string;
  tokenId: number;
  amount: string;
  refundAfterBlock: number;
  recipientWallet: string;
}

interface GiftLinkPreview {
  server: string;
  chainId: number;
  cGift: string;
  recipientWallet: string;
  tokenId: number;
  amount: string;
  refundAfterBlock: number;
}
```

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