Deploy using our tutorial

Step 1: Clone our tutorial for encrypted-erc20-dapp github repo.

git clone https://github.com/Inco-fhevm/tutorial-encrypted-erc20-dapp

Step 2: Replace the contract ABI from "erc20ABI.json" in the src file with your deployed ABI file.

mv path/to/your/deployedABI.json path/to/your/tutorial-encrypted-erc20-dapp/src/abi/erc20ABI.json

Step 3: Assuming you have replaced your ABI in the project src directory, replace the smart contract address in the ConfidentialERC20.jsx file.

import React from "react";
import { useState, useEffect } from "react";
import { getInstance, provider, getTokenSignature } from "./utils/fhevm";
import { toHexString } from "./utils/utils";
import { Contract } from "ethers";
import erc20ABI from "./abi/erc20ABI";

let instance;
// STEP 3: 
// TODO: Replace Contract Address 
const CONTRACT_ADDRESS = "0xc0340667B4dC75093A5Fc7a2f95BF2EAF5751b09";

Step 4: We need to create an fhevm instance on the client. It expects us to provide a network public key in order to encrypt data locally. Add this in src/utils/fhevm.jsx file:

export const createFhevmInstance = async () => {
  const provider = new BrowserProvider(window.ethereum);
  const network = await provider.getNetwork();
  const chainId = +network.chainId.toString();
  
  // Get the network's private key
  const ret = await provider.call({
    to: FHE_LIB_ADDRESS,
    // first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
    data: '0xd9d47bb001',
  });
  const decoded = AbiCoder.defaultAbiCoder().decode(['bytes'], ret);
  const publicKey = decoded[0];
  
  // Create a client-side instance
  instance = await createInstance({ chainId, publicKey });
  console.info("FHEVM instance created");
};

Step 5: We can use our instance to encrypt data using the network's public key. Go to ConfidentialERC20.jsx and add this to handleAmountMintChange function:

     // Encrypt to a euint32
     const encrypted = instance.encrypt32(Number(e.target.value));
     setEncryptedData(toHexString(encrypted));

Step 6: Inside mint() function we can make a transaction to mint a hidden amount. Add this to mint function in the same ConfidentialERC20.jsx file:

const transaction = await contract.mint("0x" + encryptedData);

Now if we press the "mint" button it should mint tokens. In order to check that this worked, we will read our own balance, and to do that using reencrypt.

Step 7: To make "decrypt own balance" button to work, we provide the users's publicKey as well as the EIP-712 signature, then decrypt the return value using our fhevm instance to read our balance. Add this snippet in the reencrypt function in ConfidentialERC20.jsx:

      // The following function signs a EPI-712 message under the hood
      const { publicKey, signature } = await getTokenSignature(
        CONTRACT_ADDRESS,
        signer.address,
        signer
      );
      
      // Using the smart contract's TFHE.reencrypt function, we receive
      // the ciphertext of the user's own balance.
      const ciphertext = await contract.balanceOf(publicKey, signature);
      
      // Use the users's private key to decrypt.
      const userBalance = instance.decrypt(CONTRACT_ADDRESS, ciphertext);
      console.log(ciphertext, userBalance);
      setUserBalance(String(userBalance));

TFHE.reencrypt enables confidential value decryption, granting access exclusively to the user. This method involves transforming the ciphertext encrypted under the global FHE key into another encrypted ciphertext. This transformation utilizes a temporary public key provided by the user. Subsequently, the user can decrypt the new ciphertext using the corresponding temporary private key, all of which occurs on the client side.

Step 8: Finally, run the following:

npm install
npm run dev

You should see a screen like this popping up at the local host:

Congrats! We have successfully deployed a confidential ERC-20 contract. Now you can press decrypt your balance and it would return the mint amount. Please reach out to us if you have any further questions.

Last updated