Skip to main content
This example demonstrates the full lifecycle of working with encrypted data: initialize the SDK, encrypt a value, send it to a contract, and decrypt the result — both for UI display and for on-chain verification.

The contract

A simple contract that stores an encrypted uint64 balance and allows the owner to set and read it.
contracts/ConfidentialVault.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import '@fhenixprotocol/cofhe-contracts/FHE.sol';

contract ConfidentialVault {
    mapping(address => euint64) private _balances;

    function deposit(InEuint64 calldata encryptedAmount) external {
        euint64 amount = FHE.asEuint64(encryptedAmount);
        _balances[msg.sender] = FHE.add(_balances[msg.sender], amount);
        FHE.allowThis(_balances[msg.sender]);
        FHE.allowSender(_balances[msg.sender]);
    }

    function getBalance() public view returns (euint64) {
        return _balances[msg.sender];
    }

    function publishBalance(
        euint64 ctHash,
        uint64 plaintext,
        bytes calldata signature
    ) external {
        FHE.publishDecryptResult(ctHash, plaintext, signature);
    }
}

SDK: full flow

import { createCofheConfig, createCofheClient } from '@cofhe/sdk/web';
import { Encryptable, FheTypes } from '@cofhe/sdk';
import { chains } from '@cofhe/sdk/chains';
import { createPublicClient, createWalletClient, http, custom } from 'viem';
import { sepolia } from 'viem/chains';

// 1. Initialize
const config = createCofheConfig({
  supportedChains: [chains.sepolia],
});
const client = createCofheClient(config);

const publicClient = createPublicClient({
  chain: sepolia,
  transport: http(),
});
const walletClient = createWalletClient({
  chain: sepolia,
  transport: custom(window.ethereum),
});

await client.connect(publicClient, walletClient);

// 2. Create a permit
await client.permits.getOrCreateSelfPermit();

// 3. Encrypt and deposit
const [encryptedAmount] = await client
  .encryptInputs([Encryptable.uint64(100n)])
  .onStep((step, ctx) => {
    if (ctx?.isStart) console.log(`Encrypting: ${step}...`);
  })
  .execute();

await contract.deposit(encryptedAmount);

// 4. Decrypt for UI display
const ctHash = await contract.getBalance();
const balance = await client
  .decryptForView(ctHash, FheTypes.Uint64)
  .execute();

console.log('Balance:', balance); // 100n

// 5. Decrypt for on-chain verification
const { decryptedValue, signature } = await client
  .decryptForTx(ctHash)
  .withPermit()
  .execute();

await contract.publishBalance(ctHash, decryptedValue, signature);