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

# Portal Deposit Addresses

> Give a user a reusable, public, exchange-style deposit address. Anyone can fund it with standard ERC-20 transfers, and the funds are credited into the owner's shielded balance without revealing which account was credited.

# Portal Deposit Addresses

A **portal** is a reusable, public deposit address — like a centralized-exchange
deposit address, but self-custodial. The owner publishes one fixed address `E`;
any number of senders fund it with ordinary ERC-20 transfers (no Privacy Boost
software, no per-deposit ceremony); and the funds are later **swept** into the
owner's shielded balance. Crediting is permissionless and decoupled from the
deposit, so the recipient does not have to be online for any individual deposit.

Public observers see the portal address, token, amount, timing, and sender — but
**never which Privacy Boost account receives the funds**.

<Warning>
  **Preview feature — pending external audit.** Portal deposit addresses are
  implemented (contracts, circuit, and SDK) but have not completed external
  security audit, and several pieces are launch-limited (see [Launch
  limitations](#launch-limitations)). Treat the API as stable-but-unaudited and
  gate production use on your own review. The feature is enabled per deployment;
  `sdk.portalDelegateAddress()` returns the delegate address advertised by the
  server's [`/info`](/sdk/concepts/configuration), or `undefined` if the server
  does not support portals.
</Warning>

## How it works

A portal address `E` is a normal Ethereum EOA that the owner controls, upgraded
via [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) so it can only do two
things: sweep supported tokens into the pool, and let the owner reclaim funds
resting at it. It can never spend from the pool.

```text theme={null}
 Sender(s) ──ERC-20──▶  Portal address E   (public, reusable, fixed)
                             │  sweep (permissionless)
                             ▼
                        escrow in PrivacyBoost ──epoch proof──▶ owner credited (owner hidden)
                             │
          owner reclaim ◀────┘  if never swept / never credited, after a cancel delay
```

1. **Create.** The owner derives a fresh portal address `E` from their seed,
   delegates it to the shared portal implementation, and registers a public
   on-chain binding `H` that commits to their account without revealing it.
2. **Publish.** The owner publishes a private registry entry (`E → blind`) so the
   server's indexer can credit deposits to the right account. A missing or wrong
   entry only delays crediting — it can never send funds to the wrong account.
3. **Fund.** Anyone sends standard ERC-20 to `E`. This is an ordinary token
   transfer; the sender needs nothing from Privacy Boost.
4. **Sweep.** Anyone (at launch, an operator) calls the permissionless sweep,
   which measures the actual received balance and escrows it in the pool.
5. **Credit.** The relay submits an epoch proof that credits the swept amount to
   the owner's shielded balance as a new note. The owner's identifying key stays
   private throughout — the proof binds the credit to the public `H` without
   revealing the account.
6. **Reclaim / withdraw.** If a swept deposit is never credited, the owner
   reclaims it after a cancel delay. Funds that were never swept (e.g. an
   unsupported token) can be withdrawn directly from `E`.

A swept deposit only ever ends **credited** or **reclaimed** — no third party can
force any other outcome, and an un-credited deposit is always recoverable.

## SDK API shape

The SDK exposes the same high-level portal lifecycle across TypeScript, CLI,
WASM, iOS, Android, and React Native:

* `create` / `createPortal` derives `E`, gaslessly delegates and registers it,
  and publishes discovery.
* `list`, `deposits`, and `status` expose portal and deposit state.
* `sweep` / `sweepPortal` triggers `requestPortalDeposit` from the connected
  wallet when an app needs a self-sweep backstop.
* `reclaim` / `reclaimPortalDeposit` reclaims an uncredited swept deposit after
  the cancel delay.
* `withdraw` / `withdrawPortal` signs an escape-hatch transaction from `E` for
  raw funds resting at the portal.

The seed-derived high-level flow keeps `E`'s key inside core; it never crosses
the binding boundary. Low-level `generatePortalEoa` and `encodePortalWithdraw`
remain only as custodial escape hatches for integrations that intentionally
manage their own portal EOA key.

## Trust and privacy

The portal is a **deposit-only** extension: it can only add notes to the shared
note tree, never spend or alter existing notes, and it grants no new capability
to the relay or TEE.

| Actor              | Can                                                          | Cannot                                                     |
| ------------------ | ------------------------------------------------------------ | ---------------------------------------------------------- |
| **Owner**          | register once; spend credited funds; reclaim / self-withdraw | —                                                          |
| **Sender**         | send ERC-20 to public `E`                                    | learn which account `E` funds; spend it                    |
| **Sweeper**        | move `E`'s balance into the pool                             | redirect the credit; learn the recipient; alter the amount |
| **Relay / prover** | build the proof from non-spend values; submit the epoch      | change amount/recipient; credit a different account; spend |
| **TEE**            | observe deposits; derive the owner's note via its registry   | sign anything; custody, move, or seize funds               |

A portal note joins the **same shared note tree** as every other deposit and
transfer, so its anonymity set is the full mixed pool. The portal hides *who
receives*, not *that `E` was funded*. Because a reusable public address makes the
`sender ↔ E` link public, use **one portal per counterparty** or rotate portals
when unlinkability between funders matters — these are product-layer mitigations,
not cryptographic guarantees. The discovery registry (`E → blind`) is
privacy-load-bearing and should be treated as confidential.

## Launch limitations

These are known constraints of the current (pre-audit) launch; design around
them:

* **`status.delegated` always reports `false`.** The discovery server does not
  yet compute on-chain delegation status. A portal you just created **is**
  delegated regardless of what this field says — do not gate a "ready" check on
  it.
* **`deposit.cancellableAtBlock` is always `0`.** The reclaim-eligibility block
  is not yet computed by the server. Treat `0` as *unknown*, not "reclaimable
  now."
* **Sweeping is operator-run with a zero fee.** The gross swept amount equals the
  net credited amount today. A permissionless keeper market with a capped,
  per-token fee is a later step.
* **Registration is write-once per `E`.** A portal binding cannot be changed
  after it is set; derive a new portal instead.
* **Single-chain.** Portals credit on a chain that hosts a pool. Multi-chain
  portals are a planned additive extension, out of first-audit scope.

## Using it from the SDK

<CardGroup cols={2}>
  <Card title="TypeScript" href="/sdk/typescript/guides/portal-deposits" />

  <Card title="CLI" href="/sdk/cli/guides/portal-deposits" />

  <Card title="iOS" href="/sdk/ios/guides/portal-deposits" />

  <Card title="Android" href="/sdk/android/guides/portal-deposits" />

  <Card title="React Native" href="/sdk/react-native/guides/portal-deposits" />

  <Card title="WASM" href="/sdk/wasm/guides/portal-deposits" />
</CardGroup>
