Integrating Rhino bridge with a Privy embedded wallet
Last updated: May 28, 2026
Privy is an embedded wallet provider that lets apps create non-custodial wallets on behalf of users — typically tied to an email address or social login. This article covers the technical steps required to bridge funds using the Rhino SDK when the depositing wallet is a Privy embedded wallet, including how to solve the gas problem without taking custody of user funds.
Why this differs from a standard integration
In a standard integration you would typically use Rhino's Smart Deposit Addresses (SDAs) — Rhino-managed addresses that detect deposits and execute the bridge automatically. Partners using Privy embedded wallets often need the deposit address and withdrawal address to be identical for legal and compliance reasons (see the companion overview article for context). That rules out Rhino SDAs, which use a separate intermediary address. Instead, the user's own Privy embedded wallet acts as the deposit address, and the partner detects the incoming funds and initiates the bridge from their backend.
The gas problem and why Privy's built-in sponsorship doesn't apply here
Users in this flow are typically depositing from a CEX into a brand new embedded wallet. That wallet will have no native gas token — creating a chicken-and-egg problem: the user needs gas to initiate the bridge, but has no gas.
Privy offers two wallet modes:
Non-custodial embedded wallets (EOAs) — the user holds the keys and can export them. However, Privy's gas sponsorship only works with Privy's smart account solution, not with standard EOAs.
Smart accounts (server-side) — support Privy's native gas sponsorship, but require server-side control of the wallet, which breaks the self-custody requirement and changes the legal classification of the product.
Because taking server-side control of wallets is not acceptable — it would make the partner a custodian — Privy's built-in gas sponsorship is not available for this flow.
The solution: EIP-2612 permits
The agreed approach is to use ERC-20 permits (EIP-2612). Instead of requiring the user to hold gas, the flow works as follows:
The user's embedded wallet holds a supported token on the source chain.
The partner prompts the user to sign a permit — an off-chain EIP-712 signature that authorises Rhino to pull a specific token amount from the user's wallet.
The permit signature is passed to Rhino along with the bridge request.
Rhino submits the transaction on-chain, paying the gas itself, and recoups that cost from the partner as part of normal fee settlement.
The user never needs to hold any native gas token. The wallet remains fully non-custodial — the user is signing a scoped authorisation, not handing over their keys.
This requires a minor addition to the Rhino SDK to accept a permit as part of the bridge call. That change is under discussion with the Rhino team.
Chain compatibility: EIP-2612 support is the deciding factor
Whether this integration pattern can be used on a given source chain depends entirely on whether that chain and the token being transferred support EIP-2612 permit functionality.
On chains where EIP-2612 is supported, the full gasless flow is available. The user signs an off-chain permit, no gas pre-funding is required, and the deposit experience is seamless. This is the ideal setup and the one this integration pattern is designed around.
On chains where EIP-2612 is not supported, the permit-based approach is unavailable. Without it, there is no way for Rhino to pull funds from the user's wallet without the user first submitting an on-chain approval — which itself requires gas. This creates the original chicken-and-egg problem with no clean resolution. On such chains, partners would need to either require users to fund gas manually (poor UX), use a different wallet architecture, or limit the flow to chains that do support EIP-2612.
When evaluating which source chains to support, EIP-2612 compatibility for the token you intend to use (e.g. USDC, USDT) should be the first thing you check. Not all tokens implement permits even on chains that technically support EIP-2612, so token-level support must be verified independently for each chain.
The deposit flow
Step 1 — User sends funds to their Privy embedded wallet
The user withdraws a supported token from a CEX or external wallet to their Privy embedded wallet on the source chain. This is the same address from which they will eventually withdraw, preserving deposit/withdrawal address symmetry.
Step 2 — Partner backend detects the deposit
The partner monitors the Privy wallet addresses created for their users. When a deposit is confirmed on-chain, the backend surfaces this to the user and prompts them to sign a permit.
Step 3 — User signs the permit
The user signs an EIP-2612 permit for the deposit amount. This is an off-chain signature — no gas is required at this step. The permit authorises Rhino to pull exactly that amount from the wallet.
Step 4 — Rhino executes the bridge
The partner passes the permit to the Rhino bridge SDK alongside the bridge parameters. Rhino submits the transaction on-chain (paying the source-chain gas), bridges the funds cross-chain, and credits the user's destination account. Gas costs are settled with the partner as part of normal fee reconciliation.
Step 5 — Funds arrive at the destination
The user's account on the destination chain is credited. The withdrawal address will be the same Privy embedded wallet address, closing the compliance loop.
The benefits of this setup
There are a few benefits of this setup for the integrating partner and their users.
A user can prove ownership of the deposit address with a signature which is a requirement from some CEXes before they allow withdrawals.
A user can easily recover a deposit in cases such as unsupported token deposits or limit breaches.
What was ruled out
Privy smart accounts / server-side wallets — Privy does offer a gas-sponsored smart account product, but it requires the partner to control the wallet server-side. This would make the partner a custodian, changing the legal and regulatory classification of the product. This option was explicitly rejected.