For the complete documentation index, see llms.txt. This page is also available as Markdown.

React Native SDK

Hinkal React Native SDK

Hinkal is a privacy middleware and smart-contract SDK for public blockchains that enables confidential transactions and settlement flows without changing wallets, custody, or chains.

@hinkal/react-native is a prebundled build of the Hinkal SDK for React Native and Expo. It includes the polyfills, shims, and worker runtime required on mobile — no custom Metro configuration is needed.

The SDK allows mobile wallets, dApps, and payment apps to integrate protocol-level privacy on Ethereum, Solana, Tron, Polygon, Base, Arbitrum, and Optimism.

With Hinkal SDK, developers can: • Enable private sends between public wallets • Perform confidential payouts and settlements • Route transactions through Hinkal’s privacy contracts without exposing sender, recipient, or amounts • Maintain non-custodial control with optional compliance visibility via viewing keys

Compatibility

Environment
Supported
Notes

React Native

v0.74+

Expo

dev client or bare

Installation

npm install @hinkal/react-native

Or, yarn:

yarn add @hinkal/react-native

Usage

HinkalProvider

Wrap your app with HinkalProvider before using any SDK function. It runs the React Native bootstrap and mounts the hidden WebView worker host.

Initialization

After the wallet is connected, initialize a Hinkal instance with your preferred provider helper.

Initializing the SDK creates a Hinkal object that encapsulates:

  • The user's shielded balances

  • Actions the user can perform, such as shielding (depositing), transfers, and swapping

  • Cryptographic keys for privacy-preserving operations

Each provider exposes three prepare helpers:

  • prepare*Hinkal — signs the Hinkal login message and initializes user keys (deterministic signers)

  • prepare*HinkalWithEnclaveSignIn — signs in through the secure enclave and stabilizes identity for non-deterministic signers (smart contract wallets, some hardware wallets)

  • prepare*HinkalFromSignature — initializes user keys from a previously stored signature

wagmi:

ethers.js:

Solana:

Tron:

The same WithEnclaveSignIn and FromSignature variants are available for each provider (for example, prepareWagmiHinkalWithEnclaveSignIn, prepareSolanaHinkalFromSignature).

The hinkalConfig is defined as follows:

Identity persistence

When a user connects their wallet, they sign a fixed login message to authenticate with Hinkal. That signature defines their Hinkal identity. Their shielded balances, transaction ability, and all private operations depend on it.

Most wallets return the same signature every time for the same message. Some do not. Smart contract wallets, certain hardware wallets, and other non-deterministic signers may produce a different signature on each login, even for the same address and message.

When that happens, a returning user appears as a new account. Funds deposited in an earlier session remain tied to the original identity and are not accessible from the new one.

Recommended approach: use prepare*HinkalWithEnclaveSignIn instead of prepare*Hinkal. 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.

Manual approach: if you manage identity yourself, call storeAndGetInitialSignature and then either initUserKeysWithSignature or prepare*HinkalFromSignature:

Parameters:

  • authSignature — signature from the current login session

  • isSolanaLedger — set to true for a Solana Ledger wallet. Defaults to false

  • txMessageForSolanaLedger — base64-encoded transaction message used for Solana Ledger authentication. Required when isSolanaLedger is true

Typical flow with a stored signature:

Call this once per session, after wallet connection and before fetching balances or submitting transactions.

You do not need enclave sign-in if your wallet produces deterministic signatures for the same login message on every session — in that case, prepare*Hinkal is sufficient. It is also not needed if you persist the signature yourself via prepare*HinkalFromSignature, or if you use seed-phrase-based login through initUserKeysFromSeedPhrases.

Security

The stored signature is protected at every stage. Before leaving the client, the signature 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 secure enclave, Google Cloud KMS decrypts the symmetric key. 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 in the database. A caller cannot retrieve a stored signature by wallet address alone. Each request must include any valid signature that proves wallet ownership.

Requests that fail this check are rejected. The first signature stored for a given address is never replaced. Later logins only use a fresh signature to authenticate retrieval of the original.

Shielded balance

Shielded balances are encrypted token holdings stored within the Hinkal protocol. Unlike regular blockchain balances that are publicly visible, shielded balances are hidden from external observers.

After initializing the Hinkal object and calling initUserKeys (or a prepare helper), fetch balances for a specific chain:

TokenBalance contains chainId, erc20Address, balance, and an optional timestamp.

For reactive UI updates, subscribe to balance changes with USD values:

Shielding: depositing funds to the shielded balance

Shielding moves tokens from a public blockchain address into a private, encrypted balance. Once shielded, tokens are no longer visible on-chain to external observers.

where:

  • chainId — target chain

  • erc20Addresses — token contract addresses to deposit

  • amountChanges — corresponding deposit amounts in the token's smallest unit

  • preEstimateGas — if true (default), gas is estimated before executing the deposit

  • returnTxData — if true, returns unsigned transaction data without executing. Defaults to false

On Solana, use depositSolana(chainId, erc20Address, amount).

To shield funds for another user's private address, use depositForOther (EVM/Tron) or depositSolanaForOther (Solana) with their recipientInfo string from getRecipientInfo().

Private Send to Public Address: withdrawing funds from the shielded balance

Private Send to Public Address sends tokens from a shielded balance to any public blockchain address without exposing the sender.

where:

  • recipientAddress — public address that receives the withdrawn funds

  • isRelayerOff — when false, a relayer handles gas fees; when true, the user pays gas directly

  • feeToken — optional token address used to pay protocol fees

  • feeStructureOverride — optional custom fee structure

Private Send to Private Address: transferring funds from shielded balance

Private Send to Private Address enables fully confidential transfers between shielded balances.

where:

  • recipientAddress — recipient's private address string from getRecipientInfo(). Pass it as-is; do not reformat. It is a comma-separated string with five components:

    • stealthAddress — recipient's stealth address (hex, 0x prefix, 64–66 characters)

    • H0[0] — first coordinate of the H0 elliptic-curve point

    • H0[1] — second coordinate of the H0 elliptic-curve point

    • H1[1] — second coordinate of the H1 elliptic-curve point

    • encryptionKey — recipient's encryption public key (hex, 0x prefix, 66 characters)

Private Send from Public to Public addresses

Private Send from Public to Public transfers tokens between two public addresses through Hinkal's privacy infrastructure. Tokens are shielded from the sender, then withdrawn to recipient public addresses on a relayer schedule.

where:

  • erc20Address — token contract address (single-token transfers only)

  • recipientAmounts — amounts to send to each recipient in the token's smallest unit

  • recipientAddresses — public addresses that receive the funds

  • txCompletionTime — optional Unix timestamp in seconds by which all scheduled withdrawals must complete

  • feeStructureOverride — optional custom fee structure

  • preEstimateGas — if true (default), gas is estimated before executing the deposit

The function returns:

For cross-chain private sends, use depositAndBridge(chainId, erc20Address, recipientBridges, ...) with BridgeRecipient entries that include bridge quotes and destination addresses.

Checking scheduled send status

After depositAndWithdraw or depositAndBridge, fetch scheduled withdrawal status using the returned scheduleId:

Possible values for ScheduledTransactionStatus:

  • pending — scheduled, waiting for execution time

  • processing — relayer is submitting the withdrawal on-chain

  • waiting_for_relayer — relayer is busy; withdrawal is queued

  • sent_on_chain — submitted on-chain; txHash is available

  • completed — confirmed on-chain

  • failed — withdrawal transaction failed

Swapping tokens from the shielded balance

Getting swap quotes and calldata:

EVM chainsgetEvmSwapPrices(chainId, inSwapAmount, inSwapTokenAddress, outSwapTokenAddress) returns quotes from Uniswap, Odos, and 1Inch. Pass swap calldata with the matching externalActionId:

  • Uniswapuniswap.poolFee with ExternalActionId.Uniswap

  • Odosodos.odosDataValue with ExternalActionId.Odos

  • 1InchoneInch.oneInchDataValue with ExternalActionId.OneInch

SolanagetSolanaSwapPrices(...) returns an OKX quote. Pass okx.okxDataValue to swap with ExternalActionId.Okx.

Interacting with smart contracts privately

Generate user operations with emporiumOp:

Stateless interactions (swaps, simple staking) use default invokeWallet: false.

Stateful interactions (reward tracking, voting power) require invokeWallet: true so the call runs from a persistent wallet address.

Supported Chains

Chain
Chain ID
Status

Ethereum

1

✅ Live

Arbitrum

42161

✅ Live

Polygon

137

✅ Live

Base

8453

✅ Live

Tempo

4217

✅ Live

BNB

56

✅ Live

Solana

501

✅ Live

Tron

728126428

✅ Live

Arc Testnet

5042002

✅ Live

Tron Nile

3448148188

✅ Live

Last updated