npm package: @pyratzlabs/react-fhevm-utils
Description: React hooks and utilities for Fhevmjs
Author: Pyratzlabs
Latest version: 3.6.4

## Introduction

@pyratzlabs/react-fhevm-utils is a typescript library that enables developers to interact with Zama's [fhevmjs](https://www.npmjs.com/package/fhevmjs?activeTab=readme) API. This library provides a React hooks set that allow frontend developers to easily decrypt/encrypt values or transfer encrypted tokens.

## Installation

```bash
# Using npm
npm install @pyratzlabs/react-fhevm-utils

# Using Yarn
yarn add @pyratzlabs/react-fhevm-utils

# Using pnpm
pnpm add @pyratzlabs/react-fhevm-utils
```

This will download and install the @pyratzlabs/react-fhevm-utils library and its dependencies into your project.

## Initialization

### Install dependencies

```bash
# Using npm
npm install @tanstack/react-query ethers wagmi
```

You can also use yarn or pnpm depending on your preferences

### Providers

You can declare these providers at the root of your projet, wherever it makes more sense to you.

```tsx
// src/app/layout.tsx

import React from "react";
import FhevmProvider from "@pyratzlabs/react-fhevm-utils";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider } from "wagmi";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const queryClient = new QueryClient();
  const config = {
    // ... your wagmi config
  };

  return (
    <html lang="en">
      <body>
        <WagmiProvider config={config}>
          <QueryClientProvider client={queryClient}>
            <FhevmProvider>{children}</FhevmProvider>
          </QueryClientProvider>
        </WagmiProvider>
      </body>
    </html>
  );
}
```

## Retrieve user encrypted balance

To retrieve user encrypted balance you can use useGetEncryptedBalance hook.

```tsx
// src/app/page.tsx

import React from "react";

const TOKEN_ADDRESS = "0xD61a80ec935D210b54FC97F0FBCB8C4793bE80C8";

export default function Home() {
  const { encryptedBalance } = useGetEncryptedBalance({
    tokenAddress: TOKEN_ADDRESS,
  });

  return (
    <div className="space-y-4">
      <p>User encrypted balance : {encryptedBalance}</p>
    </div>
  );
}
```

## Decrypt user balance

You can decrypt the user balance using useDecryptBalance hook.

```tsx
// src/app/page.tsx

import React, { useState } from "react";

const TOKEN_ADDRESS = "0xD61a80ec935D210b54FC97F0FBCB8C4793bE80C8";

export default function Home() {
  const [decryptedBalance, setDecryptedBalance] = useState<number>();

  const { encryptedBalance } = useGetEncryptedBalance({
    tokenAddress: TOKEN_ADDRESS,
  });

  const { mutate, isPending: isDecrypting } = useDecryptBalance({
    tokenAddress: TOKEN_ADDRESS,
  });

  const decrypt = async () => {
    if (!encryptedBalance) {
      setDecryptedBalance(0);
      return;
    }

    mutate(encryptedBalance, {
      onSuccess: (balance: bigint) => {
        setDecryptedBalance(balance * 10 ** -18);
      },
    });
  };

  return (
    <div className="space-y-4">
      <p>User encrypted balance : {encryptedBalance}</p>

      <div className="flex items-center">
        <p>User decrypted balance :</p>
        {decryptedBalance ? (
          <div>{decryptedBalance}</div>
        ) : (
          <button>{isDecrypting ? "Decrypting..." : "Decrypt"}</button>
        )}
      </div>
    </div>
  );
}
```

## Encrypt value

In order to encrypt value before a transfer you can use useEncryptValue hook.

```tsx
// src/app/page.tsx

import React from "react";

const TOKEN_ADDRESS = "0xD61a80ec935D210b54FC97F0FBCB8C4793bE80C8";

export default function Home() {
  const [value, setValue] = useState<number>();

  const {
    mutate: encrypt,
    isPending: isEncrypting,
    isSuccess: isEncryptSuccess,
    isFailed: isEncryptFailed,
  } = useEncryptValue({
    tokenAddress: TOKEN_ADDRESS,
  });

  const handleEncrypt = () => {
    const valueToEncrypt = BigInt(value * 10 ** 18);

    encrypt(valueToEncrypt);
  };

  return (
    <div className="space-y-4">
      <input
        placeholder="Enter value"
        onChange={(e) => setValue(e.target.value)}
      />
      <button onClick={handleEncrypt}>
        {isEncrypting ? "Encrypting..." : `Encrypt value : ${value}`}
      </button>
      {isEncryptSuccess && <p>Encrypt Success</p>}
      {isEncryptFailed && <p>Encrypt Failed</p>}
    </div>
  );
}
```

## Transfer encrypted token

If you want to transfer tokens you need to encrypt value before calling the transfer method.

```tsx
// src/app/page.tsx

import React from "react";
import { Address } from "viem";

const TOKEN_ADDRESS = "0xD61a80ec935D210b54FC97F0FBCB8C4793bE80C8";

export default function Home() {
  const [value, setValue] = useState<number>();
  const [address, setAddress] = useState<Address>();

  const {
    mutate: encrypt,
    isPending: isEncrypting,
    isSuccess: isEncryptSuccess,
    isFailed: isEncryptFailed,
  } = useEncryptValue({
    tokenAddress: TOKEN_ADDRESS,
  });

  const {
    transfer,
    isLoading: isTransferring,
    isSuccess: isTransferSuccess,
    isFailed: isTransferFailed,
  } = useEncryptedTransfer({
    tokenAddress: TOKEN_ADDRESS,
  });

  const transfer = () => {
    if (!address || !value) return;

    const valueToEncrypt = BigInt(value * 10 ** 18);

    encrypt(valueToEncrypt, {
      onSuccess: (result) => {
        const { handles, inputProof } = result;
        transfer(address, handles, inputProof);
      },
    });
  };

  return (
    <div className="space-y-4">
      <input
        placeholder="Enter value"
        onChange={(e) => setValue(e.target.value)}
      />
      <input
        placeholder="Reciever address"
        onChange={(e) => setAddress(e.target.value)}
      />

      <button onClick={transfer}>
        {isEncrypting
          ? "Encrypting..."
          : isTransferring
          ? "Transferring..."
          : "Transfer"}
      </button>

      {isEncryptSuccess && <p>Encrypt Success</p>}
      {isEncryptFailed && <p>Encrypt Failed</p>}
      {isTransferSuccess && <p>Transfer Success</p>}
      {isTransferFailed && <p>Transfer Failed</p>}
    </div>
  );
}
```

## Retrieve Fhevm instance

To retrieve fhevm instance you can use useFhevmInstance hook.

```tsx
// src/app/page.tsx

import React from "react";

export default function Home() {
  const { instance } = useFhevmInstance();

  return (
    <div className="space-y-4">
      <p>Fhevm instance : {instance.toString()}</p>
    </div>
  );
}
```

## Override Fhvem configuration

You can override Fhevm configuration depending on the chain you're working with.

```tsx
// src/app/layout.tsx

import React from "react";
import FhevmProvider, { FhevmConfig } from "@pyratzlabs/react-fhevm-utils";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider } from "wagmi";
import { polygonAmoy } from "viem/chains";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const queryClient = new QueryClient();
  const config = {
    // ... your wagmi config
  };

  const customFhevmConfig: FhevmConfig = {
    network: polygonAmoy,
    // other overridable configurations
    // chainId: 11221212,
    // networkUrl: "https://example-polygon-amoy-rpc.com/
  };

  return (
    <html lang="en">
      <body>
        <WagmiProvider config={config}>
          <QueryClientProvider client={queryClient}>
            <FhevmProvider config={customFhevmConfig}>{children}</FhevmProvider>
          </QueryClientProvider>
        </WagmiProvider>
      </body>
    </html>
  );
}
```

## License

This library is distributed under the MIT license.