Skip to main content

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. Sweeping is permissionless and crediting is submitted by an allowed relay, both 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.

How it works

A portal address E is a normal Ethereum EOA that the owner controls, upgraded via EIP-7702 so it can do three things: bind its recipient record once (a second binding reverts), sweep supported tokens into the pool (wrapping plain ETH for the configured wrapped-native token), and let the owner withdraw funds resting at it. It can never spend from the pool.
Funds still resting at E use its owner’s direct withdrawal path without the pool’s cancellation delay.
  1. Create. The owner derives a fresh portal address E from their nullifying key, 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 → (recipientMPK, blind), where the client supplies only 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 calls the permissionless sweep, which measures the actual received balance and escrows it in the pool. Deployments typically run a keeper so owners do not have to.
  5. Credit. The relay submits an epoch proof that credits the net amount after the recorded sweep fee 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, anyone can cancel it after the delay. The contract returns the full gross amount to E, regardless of who calls. 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. Cancellation becomes eligible at requestBlock + cancelDelay, where requestBlock is recorded at the sweep and cancelDelay() gives the pool’s configured delay in blocks. For the configured wrapped-native token, a sweep can wrap native ETH above the portal’s 0.001 ETH reserve. Receiving ETH alone does not wrap or credit it. Ordinary ERC-20 sweeps leave native ETH untouched.

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.
  • listPage / listPortalsPage, depositsPage / listPortalDepositsPage, and status / getPortalStatus 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. 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 → (recipientMPK, blind)) is privacy-load-bearing and should be treated as confidential. Preserve recipientMPK and blind for recovery.

Current limitations

These are known constraints of the current implementation; design around them:
  • status.delegated always reports false. A portal you created is delegated regardless; gate readiness on registered and published.
  • deposit.cancellableAtBlock is always 0. Treat it as unknown, not “reclaimable now” — the chain still enforces the delay on reclaim.
  • The sweep fee is one global rate, not per-token. requestPortalDeposit is permissionless: the caller is recorded as the fee payee, and the rate is snapshotted into the record at sweep time so a later rate change cannot alter an already-escrowed sweep. The credited amount is gross - floor(gross * feeBps / 10000); cancellation returns the gross amount. The rate is a single owner-set value capped at 10%, so a deployment running it at zero credits the full gross amount. If fee payment fails at settlement, the sweeper can claim the deferred fee later.
  • Registration is write-once per E. A portal binding cannot be changed after it is set; derive a new portal instead.
  • Not every network has a PortalDelegate. Portals need the shared EIP-7702 delegate deployed on the target chain and advertised by the server. In TypeScript and React, sdk.portal.delegateAddress() returns nothing when it is absent, as does portalDelegateAddress() on the other platforms. See Contract Addresses.
  • Same-chain credit. Portals credit the pool on the portal’s chain. Moving funds between chains requires a separate bridge flow; multi-chain portals are a planned additive extension.

Using it from the SDK

TypeScript

CLI

iOS

Android

React Native

WASM