SDK: Description
Hinkal 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.
The SDK allows wallets, payment platforms, and dApps to integrate protocol-level privacy on Ethereum, Solana, Polygon, Base, Arbitrum, and Optimism. It hides transaction history, wallet relationships, and asset flows on-chain while preserving public-chain finality and compliance.
With Hinkal SDK, developers can:
• Enable private transfers 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.
Installation
Using npm:
npm install @hinkal/commonOr, yarn:
yarn add @hinkal/commonUsage
Initialization
To begin using Hinkal in your application, you'll need to initialize the SDK with your preferred Web3 connection library. Hinkal supports multiple popular libraries out of the box, allowing seamless integration with your existing wallet connection setup.
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
ethers.js:
wagmi:
The hinkalConfig is defined as follows:
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, providing privacy for your assets. After initializing the Hinkal object, you can access and calculate your shielded balances:
This returns a map from token address to balance for all tokens held by the user, including ERC20 and ERC721 tokens.
Shielding: depositing funds to the shielded balance
Shielding is the process of moving your tokens from a public blockchain address into a private, encrypted balance. Once shielded, your tokens are no longer visible on-chain to external observers. This provides privacy for your holdings and subsequent transactions.
A user can deposit funds to their shielded address using:
where:
erc20Tokensis an array of tokens to depositamountChangesrepresents the corresponding token amounts for the deposit
The ERC20Token type is defined as follows:
Private Send to Public Address: withdrawing funds from the shielded balance
Private Send to Public Address allows you to send tokens from your private, shielded balance directly to any public blockchain address. The sender's identity is not exposed during this transaction. The recipient receives the funds at their public address, where the tokens become visible on-chain. This is useful when you need to interact with public DeFi protocols, send funds to exchanges, or transfer to any public wallet while maintaining privacy for your shielded balance.
A user can withdraw funds from their shielded address to a public address using:
where:
recipientAddressis the public address that will receive the withdrawn fundsisRelayerOffdetermines whether to use a relayer for the transaction (whenfalse, a relayer handles gas fees; whentrue, the user pays gas directly)RelayerTransactiontype represents the transaction response from the relayer service.
Private Send to Private Address: transfering funds from shielded balance
Private Send to Private Address enables fully confidential transfers between shielded balances. Both the sender and recipient remain anonymous, and the transaction amount is hidden from external observers. This is the most private way to transfer tokens, as neither party's identity nor the transaction details are exposed on-chain.
A user can transfer tokens from their shielded balance to another shielded address using:
where:
privateRecipientAddressis the recipient's private address, formatted as a comma-separated string with five components:randomization- a random value for privacystealthAddress- the recipient's stealth address (hex format starting with0x)encryptionKey- the recipient's encryption key (hex format starting with0x, 66 characters)H0- the first hash component of elliptic curve point for stealth address derivationH1- the second hash component of elliptic curve point for stealth address derivation
Private Send from Public to Public addresses
Private Send from Public to Public addresses enables you to transfer tokens between two public addresses while using Hinkal's privacy infrastructure. The tokens are first shielded from the sender's public address, then unshielded to the recipient's public address either immediately or after some interval. This ensures there is no traceable connection between the sender and recipient on-chain, providing transaction privacy even when both parties use public addresses.
A user can perform a private transfer between public addresses using:
where:
erc20Tokenis the token to transfer (only single token transfers are supported for this method)recipientAmountsis an array of amounts to send to each recipient (in the token's smallest unit)recipientAddressesis an array of public addresses that will receive the fundstxCompletionTime(optional) specifies a delay in milliseconds before the withdrawal completes
Swapping tokens from the shielded balance
Swapping allows you to exchange tokens directly from your shielded balance without revealing your identity. The swap is executed through integrated DEX protocols (Uniswap, 1Inch, Odos) while keeping your transaction private. Your tokens are withdrawn from your shielded balance, swapped through the specified protocol, and the resulting tokens are deposited back into your shielded balance—all in a single private transaction.
A user can swap tokens directly from their shielded balance using:
where:
externalActionIdidentifies the external swap protocol to use. Possible values include:ExternalActionId.Uniswap- for Uniswap swapsExternalActionId.OneInch- for 1Inch swapsExternalActionId.Odos- for Odos swaps
swapDatacontains the encoded swap parameters specific to the chosen protocol
Getting swap calldata:
To obtain the swap calldata using the Hinkal SDK, you can use the built-in swap data generation utilities.
To get swap data for 1Inch, you can use the getOneInchPrice function. This function fetches a quote from the 1Inch aggregator and returns both the expected output amount and the encoded swap data that can be passed to the swap function:
1Inch:
Similar functions are available for other supported swap protocols:
Uniswap:
getUniswapPriceOdos:
getOdosPriceLiFi:
getLifiPrice
Interacting with smart contracts privately
The SDK lets you interact with any smart contract on the blockchain while keeping your identity private. When you initiate a private wallet action, your funds are first unshielded from your Hinkal shielded balance to an intermediary called an Emporium contract. The Emporium then executes your desired actions on-chain (such as swaps, staking, or other DeFi interactions) without exposing who initiated them. After the operations complete, the resulting tokens are automatically shielded back into your Hinkal shielded balance. This means you can use DeFi protocols, NFT marketplaces, or any other smart contract while maintaining full anonymity.
Parameters:
chainId- the blockchain network identifieronChainCreation- array of booleans indicating the direction of token changes:truefor positive changes (tokens received),falsefor negative changes (tokens spent)ops- array of encoded user operations to execute (see User operations below)
User operations (ops) are encoded instructions that tell the Emporium contract what actions to perform. Each operation specifies a target contract, the function to call, and any necessary parameters. For example, to stake ETH with Lido, you would create an operation that calls Lido's submit function with the appropriate value.
To generate user operations, a user will need the emporiumOp function.
The function accepts the following arguments:
contract(required) - target address or contract instance (with address). The contract instance will be used to properly encode the call function, if any, in the custom operation.func(optional) - the name of the function to be called on the target address.args(optional) - arguments of the function to be called on the target address.callDataString(optional) - pre-encoded calldata string. If provided,funcandargsshould not be used.invokeWallet(optional) - boolean flag that determines the type of interaction (see the stateless/stateful interactions below).value(optional) - the value field to the user operation call.
When the Emporium contract executes a user operation, it receives the data in this format:
This enables the Emporium contract to execute generic calls using user operations:
User operations can be categorized into two types based on whether the target protocol needs to track the caller account's history:
Stateless interactions are operations where the resulting token amount changes depend only on the calldata provided. Two different accounts executing the same calldata should receive the same result, regardless of their transaction history. Examples include token swaps, liquidity provision, and simple staking operations.
For example, consider exchanging USDC for ETH using a DEX. To perform a swap, the DEX does not need to know historical data about the caller (e.g., when and what swaps have been performed from his account in the past). It only needs to know how much token to swap and the exchange rate.
In this example:
First operation approves the swap router to spend USDC tokens
Second operation executes the swap from USDC to WETH
Third operation unwraps WETH to ETH
Stateful interactions are operations where the target protocol needs to track the account's history for future calculations, such as staking rewards, voting power, or checkpoints. In these cases, set invokeWallet: true to ensure the operation is executed from a persistent wallet address that the protocol can track.
Consider a scenario where you have already staked Curve LP tokens and want to claim your rewards. The gauge contract needs to track your staking history to calculate accumulated rewards, so it must recognize the same wallet address across multiple interactions.
In this example:
First operation approves the gauge contract to spend LP tokens, executed from the persistent wallet
Second operation deposits LP tokens into the gauge, with the wallet address as the recipient for reward tracking
Access Tokens
Access tokens are required credentials that allow users to interact with Hinkal's privacy smart contracts. Think of them as a "passport" that proves you've completed the necessary compliance verification.
Before you can deposit funds, make transfers, or perform any private transactions through Hinkal, you must have a valid access token associated with your wallet. This is a one-time requirement—once you have an access token, you can use Hinkal's features without needing to verify again.
To check whether a user already has an access token on a specific chain, use the checkAccessToken function:
If the user does not have an access token, they need to complete a compliance verification through one of Hinkal's supported compliance providers. This is a one-time process that verifies the user meets regulatory requirements before they can use the privacy features.
To get a list of all available compliance providers that can be used for verification:
After passing the compliance check with one of the supported providers, the access token will be automatically minted during the user's first transaction with Hinkal. This token is stored on-chain and grants the user permission to interact with Hinkal's privacy contracts.
Last updated