Claimable Transfers
A claimable transfer (a gift) lets you send shielded funds to an Ethereum
wallet address that is not yet a registered Privacy Boost account. You need
only the recipient’s wallet address and an amount. The recipient later registers
Privacy Boost with that same address and claims the funds into a normal shielded
note; if they never claim, you reclaim the funds after a deadline you set.
Like a normal private transfer, the recipient and amount stay hidden on chain.
Unlike a normal transfer, the recipient does not have to exist on Privacy Boost
when you send.
Preview feature — pending external audit. Claimable transfers are
implemented across the protocol and SDKs but have not completed external
security audit. Treat the API as stable-but-unaudited and gate production use
on your own review. The feature is enabled per deployment; the server’s
/info advertises gift support through its
gift refund-delay bounds (giftMinRefundDelayBlocks /
giftMaxRefundDelayBlocks).
How it works
The protocol cannot send a spendable note to an address it has never seen — a
note is only spendable by a registered account’s keys. Claimable transfers solve
this with a two-step fund → claim flow built around a gift note:
SENDER ON-CHAIN / NOTE TREE RECIPIENT
│ 1. fund a gift note bound to the recipient wallet W
│ (ordinary private transfer; amount + recipient hidden)
│ ────────────────────────────▶ gift note appended
│ 2. share a claim link (optional, off-chain) ────────────▶ 3. register PB with wallet W
│ 4. discover the pending gift
│ claim ◀───────────────────── 5. claim → receive a normal note
│
│ 6. if unclaimed past the refund deadline → refund ──────▶ funds return to sender
- Fund. You build a gift note bound to the recipient’s wallet address
W
and a fresh hiding factor, then fund it through an ordinary shielded transfer.
On chain it is indistinguishable from any other transfer — the amount and the
recipient are hidden. The SDK records the gift locally so you can always
refund it, and (for the wallet-bound modes) returns an off-chain claim
link carrying the encrypted opening.
- Claim. The recipient registers Privacy Boost with the same wallet
W,
discovers the pending gift, and claims it. Claiming proves control of W with
a zero-knowledge proof and re-mints the gift into a normal shielded note. The
amount stays hidden.
- Refund. You pick a refund deadline (a block height) at funding time. If
the gift is still unclaimed after it, you reclaim the funds. A claim and a
refund spend the same nullifier, so exactly one of them can ever settle —
the recipient can’t claim a refunded gift, and you can’t refund a claimed one.
If the relay or TEE is unavailable, a recipient can always recover the funds
through a permissionless public exit (which reveals the amount, like a forced
withdrawal). Funds are self-custodial end to end: only the user’s own keys plus a
valid proof move them. The TEE assists discovery and can never seize or redirect
a gift.
Funding modes
The SDK exposes three ways to fund a gift. Pick the one that matches what you
know about the recipient.
| Mode | You provide | When to use |
|---|
| Wallet + privacy address | recipient wallet W and their privacy address | The recipient is already a Privacy Boost user — the ciphertext is sealed to their viewing key for the smoothest discovery. |
| Wallet only | recipient wallet W | The recipient has an EOA but has not joined Privacy Boost. The claim link carries everything they need. |
| Secret-bearer | nothing but an amount | The recipient has no wallet at all yet. See the warning below. |
Secret-bearer mode is experimental, off by default, and a bearer
instrument. It binds the gift to a secret embedded in the claim link instead
of a wallet, so anyone who holds the link can claim the funds — if the link
leaks, the funds are stealable, exactly like cash or a gift card. It is gated
on audit and product sign-off, is not exposed in the CLI, and a secret-bearer
gift can only be claimed through the public (amount-revealing) exit. Do not use
it in production without your own review. The wallet-bound modes above are the
supported default.
Discovering a gift
A recipient finds a pending gift in one of three ways, in increasing order of
trustlessness:
- TEE discovery. Behind a normal authenticated session for wallet
W, the
server lists the pending gifts addressed to that wallet. This is the default
path the SDK’s “list pending gifts” call uses.
- Claim link. The sender shares a
pbgift:v1:... link out of band (message,
QR code). The recipient can decode it offline to preview the gift, then claim
directly from it — no server lookup required to read it. Treat a claim link
like a password: for wallet-bound gifts the recipient still needs their own
keys to claim, but the link reveals the amount and recipient to anyone who sees
it.
- Trustless recovery. Using only the claim link’s encrypted opening and
public on-chain data, a recipient can rebuild and submit the claim with no TEE
and no relay. This is the ultimate liveness backstop.
Refunds and the deadline
You choose refundAfterBlock when you fund. It is bounded by the server (at
least a minimum delay, at most a maximum, both advertised from /info) so a
genuinely abandoned gift always stays recoverable but a sender cannot claw back
immediately. Anti-clawback is enforced on chain — a refund proof requires the
deadline block to have genuinely elapsed.
To refund, the SDK uses the local gift record it saved at funding time
(getGiftRecords() / gift_refund_by_record). Keep these records: they are what
makes an unclaimed gift refundable. They travel inside an
exported session (see your platform’s session-storage guide), and a chain context can
rehydrate them with import_gift_records. If you lose them, you can still refund
by supplying the gift’s fields manually (gift_refund).
What observers and the TEE learn
| Observer learns | Funding | Private claim | Public exit |
|---|
Recipient wallet W | hidden | hidden | revealed (as destination) |
| Amount | hidden | hidden | revealed |
| That a settlement happened | as a transfer | yes (one event) | yes |
| Whether it was a claim or a refund | — | indistinguishable | — |
A private claim and a private refund are indistinguishable on chain. The TEE
learns the recipient wallet W during discovery — a deliberate, narrow
privacy-scope widening versus a normal transfer — but can never move funds. A
reusable funding pattern carries the usual send-to-address correlation caveat: a
checksummed-address confirmation prompt and an optional unknown-sender warning
on claim blunt it, but funding any address is inherently address-bound.
Using it from the SDK
The full method surface — giftFund, giftFundToWallet, giftClaim,
giftClaimFromLink, giftRefundByRecord, getPendingGifts, decodeGiftLink,
and the gift fields added to the transfer result — is documented per platform: