





































Adjusted stablecoin transaction volume hit a record $1.79 trillion in June 2026, a 63% jump from May, according to Visa's Allium-powered onchain analytics dashboard.
Every one of those transfers is settled on a public ledger, which means the balances, counterparties, and amounts behind them are readable by anyone with a block explorer.
Hinkal provides privacy infrastructure for stablecoin payments and on-chain financial operations, letting businesses move funds across public chains while keeping payment, settlement, payout, and treasury data confidential, without changing existing wallets, chains, custody, or compliance controls.
If you already run an embedded wallet through Privy, Turnkey, or Crossmint, you have the hardest part solved: users are authenticated and a signer exists. Hinkal needs nothing else to give that same user a private balance sitting next to their public one.
This guide walks through the integration provider by provider: what changes, what does not, and the one design decision that determines whether your integration survives a second login.
[[KEY_TAKEAWAYS]]

Embedded wallet providers removed the seed phrase from onboarding. A user signs in with email, social, or a passkey, and a self-custodial wallet appears inside your product. What did not change is the ledger underneath it.
The moment that wallet receives its first stablecoin, its balance, its payment history, and every counterparty it ever touches become public and permanent.
For a consumer app, that is an annoyance. For a payroll platform, a PSP, an iGaming operator, or a merchant settlement product, it is a commercial problem.
Hinkal's answer is not a different wallet or a different chain. It is a smart contract on the chains you already use, holding a private balance controlled by the exact same keys your embedded wallet already manages.
Your provider keeps doing what it does: authenticate the user, hold the key material, produce signatures. Hinkal consumes those signatures and nothing else.
The result inside your interface is simple. Next to the regular balance, a private balance. Next to the regular send, a private send.
The Hinkal SDK is a TypeScript package (@hinkal/common) that exposes Hinkal's shielded pool to your frontend or backend. It handles balance decryption, UTXO selection, proof generation, and transaction building, then hands you a small set of functions.
Four payment flows are available:
Around those sit the operational pieces you will actually ship: reactive private balance reads with USD values via onPrivateBalancesWithUSDChange, batch and scheduled payouts to many recipients through depositAndWithdraw, cross-chain private sends via depositAndBridge, swaps executed inside the shielded balance, and viewing-key management for selective disclosure. It runs on Node.js v18+, in the browser (React, Next.js, vanilla JS), and on React Native or Expo through @hinkal/react-native.
Full method signatures live in the Hinkal SDK documentation. This guide covers the integration decisions around them.
Three parties are involved in every private operation, and holding the separation clearly is worth more than any code sample.
The execution model is UTXO-style commitments and nullifiers stored in canonical on-chain contract state. Settlement happens on the same public chain, with the same finality your product already relies on.

Install with npm install @hinkal/common, or @hinkal/react-native for mobile.
One environment note that blocks more first days than anything else: the SDK depends on snarkjs, which uses WebAssembly, so any client-side app must allow the 'wasm-unsafe-eval' directive under script-src in its Content Security Policy. Without it, proving silently fails to initialize.
Confirm your target chain is live before planning a sprint around it:
Every live chain supports the full feature set: shielding, transfers, withdrawals, swaps, and confidential contract interaction.
Read this before you scope the work. It is the difference between an integration that works and one that loses track of user funds.
When a user connects, they sign a fixed login message. That signature defines their Hinkal identity. Their shielded balances, their ability to transact, and every private operation derive from it.
Most wallets return the same signature every time for the same message. Some do not. Smart contract wallets, passkey signers, certain hardware wallets, and other non-deterministic signers produce a different signature on each login, even for the same address and the same message.
When that happens, a returning user appears as a brand new account. Funds deposited in an earlier session stay tied to the original identity and are not reachable from the new one. The user sees a zero balance. Nothing is lost on-chain, but from the product's point of view it is a support fire.
Each provider exposes three prepare helpers, and choosing correctly is the whole game:
Recommended default for embedded wallets: prepare*HinkalWithEnclaveSignIn. It signs the login message, stores the first signature server-side through the secure enclave, and always initializes with the original identity on later sessions. Solana Ledger wallets are handled automatically.
Because that stored signature is the user's identity, its handling matters. Before leaving the client it is encrypted with hybrid encryption: the payload is encrypted with a symmetric key, and that key is encrypted with the enclave's public key.
Inside the enclave, Google Cloud KMS decrypts the symmetric key, and only then is the signature decrypted. The plaintext signature never leaves the enclave unprotected. At rest, only the encrypted signature and encrypted key are stored.
A caller cannot retrieve a stored signature by wallet address alone, since every request must include a valid signature proving wallet ownership. The first signature stored for an address is never replaced.
If you would rather persist, storeAndGetInitialSignature followed by initUserKeysWithSignature gives you the same result under your own control. You can skip enclave sign-in entirely if your wallet signs deterministically, if you persist the signature yourself, or if you use seed-phrase login through initUserKeysFromSeedPhrases.
This is the thesis of the entire integration. Every provider below converges on the same call:

Privy, Turnkey, and Crossmint differ only in how you obtain signer. Everything after that line is byte-for-byte identical. If you are on wagmi rather than ethers, swap in prepareWagmiHinkalWithEnclaveSignIn; Solana and Tron have their own equivalents.

Privy authenticates users through email, social login, passkey, or an existing wallet. Its default embedded wallet is an EOA secured through TEEs and Shamir's Secret Sharing. Compatible with browser environments (React, Next.js) via @privy-io/react-auth v3.
Get the embedded wallet, pull its EIP-1193 provider, and wrap it:

Pass that signer to prepareEthersHinkalWithEnclaveSignIn and you are done. Privy's default EOA signs deterministically, so plain prepareEthersHinkal would technically work. Use the enclave variant anyway.
It costs nothing, and it protects you the day you enable Privy's ERC-4337 smart wallets on EVM, where the signature comes from a contract account and determinism is no longer guaranteed.
From there, deposit shields funds from the user's Privy wallet, transfer sends privately to another shielded balance, and withdraw sends to any public address. The deposit broadcasts from the user's own wallet, which is expected: it is the public on-ramp into privacy.
Transfers and withdrawals are proved by the enclave and broadcast by the relayer, so the Privy wallet never appears as the transaction origin.
Turnkey holds private keys inside hardware-isolated enclaves that are never exposed, not even to Turnkey. Its role is unchanged: manage keys, enforce policy, produce signatures. Compatible with browser environments via @turnkey/react-wallet-kit v2 and @turnkey/ethers.

client is the authenticated Turnkey client, organizationId identifies the org that owns the key, and signWith is the address to sign as. If the user has no EVM wallet yet, create one first with httpClient.createWallet using a standard secp256k1 BIP-32 account at m/44'/60'/0'/0/0.
The Hinkal call that follows is identical to the Privy path. That is the point.
Worth noting for institutional buyers: Turnkey policies are evaluated at signing time. If a policy requires a second approver above a threshold, that approval gates the Hinkal signature, which gates the private operation. You get approval workflows over confidential payouts without building an approval system, and without the amount ever landing on a public ledger. That pairs naturally with the pending-payout and batch-payout workflows in Hinkal Prime.
Crossmint takes a different architectural route. Its default wallet is a smart contract wallet across EVM, Solana, and Stellar, controlled by a modular signer layer (TEE-backed keypairs, passkeys, email, or an external wallet). The advantage is that the signer can be rotated without migrating assets, because the wallet address never changes.
That architecture also makes Crossmint the integration where the identity persistence section stops being theoretical.
The honest summary: on Crossmint, always use the enclave sign-in variant. A passkey signer produces a fresh signature for the same message on every login by design. Without enclave sign-in, every returning user is a new Hinkal identity and their prior shielded balance is orphaned.
There is one more wrinkle, and it is the only place the smart contract wallet model changes the mechanics. The shielding deposit must originate from the address that actually holds the tokens, which is the Crossmint smart wallet, not an EOA signer sitting behind it. Use returnTxData to get unsigned calldata from Hinkal and hand it to Crossmint to execute:

Withdrawals, transfers, and swaps need no special handling, because the relayer broadcasts them. Only the public-to-private deposit leaves from the user's own address.
Validate on Sepolia before you scale: confirm that the same user, logging out and back in, resolves to the same Hinkal identity and the same shielded balance. If your signer configuration is unusual, this is exactly the case to raise with Hinkal's forward-deployed engineer, who assists throughout the integration.
A private balance is only useful if users see it without leaving your product. The SDK exposes a reactive surface for this: hinkal.privateBalancesWithUSD holds current state keyed by chain, onPrivateBalancesWithUSDChange subscribes to updates and returns an unsubscribe function, and refreshBalance forces a refresh after a transaction settles. For a plain read, getTotalBalance(chainId) returns token balances for a single chain. Balances are per-chain, so call it for each chain you support.
The UX pattern that works: render the private balance as a peer of the public balance in the same list, not as a separate mode or a separate screen. The send flow gets one toggle, "send privately," and everything else stays where the user already expects it. Privacy is infrastructure here, not a destination.
Receiving works through a recipient info string obtained from getRecipientInfo(). It is not a public address. It is a comma-separated string of five components covering the recipient's stealth address, three elliptic-curve point coordinates, and their encryption public key. Pass it to transfer exactly as received: do not reformat, trim, or re-checksum it. To shield funds directly into another user's private balance from a public wallet, depositForOther (EVM and Tron) and depositSolanaForOther take the same string.

For payroll, contractor, vendor, affiliate, and gaming payouts, the pattern is one public deposit and many private payouts. depositAndWithdraw shields from the sender's public address and then unshields to each recipient's public address, immediately or after an interval, so there is no traceable on-chain connection between sender and recipients. It takes a single token address, an array of amounts, an array of public recipient addresses, and an optional completion deadline.
The important design point is what it returns: a depositTxHash and a scheduleId, not a final state. A 200-recipient payroll run is one deposit and 200 independently scheduled withdrawals. Poll checkSendTransactionStatus(scheduleId) for per-recipient status, which moves through pending, processing, waiting_for_relayer, sent_on_chain, and completed, or lands on failed. Build your UI around that state machine and give failed a retry path rather than a support ticket.
For cross-chain payouts, depositAndBridge takes bridge quotes and destination addresses and preserves privacy across the hop.
If your finance team wants a dashboard rather than an API for this, that is Hinkal Prime: permissioned multi-user access, pending payouts held for review before execution, batch payouts in one confidential operation, and compliance controls on high-value transactions.
Hinkal is not a mixer, and this is not a semantic distinction. Compliance is embedded at the entry point.
Chainalysis KYT screens wallet addresses before execution, preventing high-risk funds from entering the smart contract at all. The screening happens before the deposit, not as an afterthought, which is the structural difference from sanctioned, compliance-free obfuscation tools.
Viewing keys let users decrypt their own transaction history and share it selectively. Disclosure can be scoped, full or partial, limited to specific transactions or time ranges, time-bounded, and revocable. That covers audits, regulators, and counterparties without exposing anything on the public ledger. Downloadable transaction history is available out of the box.
The framing your compliance team will need: privacy here means opacity to the public ledger, not opacity to your auditors. Nothing about the integration changes your existing custody model or your existing compliance controls.
The SDK is not the only integration path, and picking the wrong one costs weeks.
Two teams are running the SDK in production today. If you already operate Privy, Turnkey, or Crossmint, the SDK is almost always right, because you already have the wallet and the signer. The API is the better call when your payout engine lives in a Python or Go backend and the frontend is not where the money moves.
Phase 1, testnet: Sepolia for EVM, Tron Nile for Tron. Validate the full loop: deposit, read balance, transfer to a second identity, withdraw to a public address. Then log out and back in and confirm identity persistence.
Phase 2, single-chain mainnet, internal only: Pick your highest-volume chain and run real payouts through it with your own funds. Watch the relayer statuses. Confirm fee token behavior matches your accounting.
Phase 3, shadow launch: Enable the private balance for a small cohort. The UX signal you want is that nobody asks what it is, because it looks like a balance next to a balance.
Phase 4, multi-chain and batch: Add remaining chains and move payroll or vendor runs to depositAndWithdraw.
Hinkal has been live in production for roughly 3.5 years, has processed more than $500M in cumulative volume, and has completed 6 security audits. It is backed by Draper Associates, SALT, SNZ Capital, and NGC Ventures, and was incubated at Stanford and Binance MVB. It integrates with Polygon, Borderless, Vault, Khalani, Rubic, MPC Vault, Peso, and Utila, among others.
The enterprise settlement fee is 10 BPS (0.10%) per transaction. Fee tokens are selectable per operation, and a fee structure override exists if you need custom handling. Fetch the current structure rather than hard-coding it.
One dependency to plan around: confidential operations are broadcast by the relayer, which is the mechanism keeping the user's wallet off-chain as an origin. Withdrawals can be run with the relayer off, having the user pay gas directly, at the cost of that unlinkability.

Hinkal provides privacy infrastructure for stablecoin payments and on-chain financial operations, adding confidentiality to the chains, wallets, and stablecoins your product already runs on, without a migration, a custody change, or a new wallet for your users.
This guide covered the embedded wallet integration end to end: the three-party architecture of signer, enclave, and relayer, the identity persistence rule that decides whether your integration survives a second login, the signer setup for Privy, Turnkey, and Crossmint, and the operational patterns for private balances, batch payouts, and viewing-key disclosure.
The pattern underneath all of it is the same, because once your provider hands you a signer, the Hinkal SDK does not care which provider it came from.
If you are running an embedded wallet and want to see what a private balance looks like inside your product, book a demo and a forward-deployed engineer will walk your stack through it.
Read Next:
The best way to add private balances to an embedded wallet in 2026 is to integrate the Hinkal SDK on top of your existing wallet provider. Because Hinkal only needs a standard signer, a Privy, Turnkey, or Crossmint wallet plugs in directly. The same wallet a user signs in with can hold a shielded balance and run confidential deposits, transfers, withdrawals, and swaps, with no chain migration and no custody change.
You integrate the Hinkal SDK with Privy in three steps. First, install @privy-io/react-auth, ethers, and @hinkal/common. Second, get the embedded wallet from useWallets(), call getEthereumProvider(), and wrap it in an ethers BrowserProvider to obtain a Signer. Third, pass that signer to prepareEthersHinkalWithEnclaveSignIn. From there, every Hinkal call is identical to any other wallet.
Smart contract wallets break Hinkal identity because they can produce a different signature each time for the same login message, and that signature is what defines the user's Hinkal identity. A returning user then appears as a new account, and funds from earlier sessions stay tied to the original identity. The fix is prepare*HinkalWithEnclaveSignIn, which stores the first signature server-side inside the secure enclave and always initializes with the original identity on later logins.
The Hinkal SDK supports Ethereum, Arbitrum, Optimism, Polygon, Base, Solana, Tron, and Tempo in production, plus Arc Testnet, Sepolia, and Tron Nile for testing. Every live chain supports the full feature set, including shielding, transfers, withdrawals, swaps, and confidential contract interaction, and cross-chain private sends are available through depositAndBridge.
Adding the Hinkal SDK does not change your compliance obligations or your custody model. Hinkal is non-custodial and never holds funds or keys, since the private balance is controlled by the same wallet keys your provider already manages. Chainalysis KYT screens wallet addresses before execution to keep high-risk funds out of the smart contract, viewing keys allow scoped, time-bounded, revocable disclosure to auditors and regulators, and transaction history is downloadable out of the box.






















