Skip to content

Conversation

poppyseedDev
Copy link
Contributor

@poppyseedDev poppyseedDev commented Sep 23, 2025

Screen.Recording.2025-09-23.at.17.47.47.mov

@poppyseedDev poppyseedDev changed the title Poppyseed/imporvments Change template Sep 23, 2025
Copy link

vercel bot commented Sep 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
fhevm-react-template Error Error Oct 7, 2025 11:43am

@RegisGraptin
Copy link

Here some comments, please take it as a reflection on the template we want to propose.

Today I think the code implementation is a bit too complex to understand and visualize how users can use FHEVM directly in their dapp. It would be nice to use on the frontend some hooks for reading and writing on the contract by using viem library for that. Same with chain management, I have the feeling for each action we need to fetch and specify it. I would be in favor of having viem managing that directly and delegate this part. In all the cases, we truly need to simplify it. New users might have some knowledge of web3 but today I do not see/understand how we are interacting with the FHE through the demo in the code.

I would also be in favor to organize the code in a way that it is simple for a user to create a new component folder to directly work on their use cases by having the counter as an example, or for experiment developers to delete the counter example and write directly their own implementation. But in all the cases it has to be simple, multiple component if needed to illustrate and understand the different process.

For the demo, I would maybe increase the refresh, to avoid the light on/off effect. And add a delay when we display the decryption of the counter, which in my case is a bit too fast for me to read the value.

Do not hesitate if some of my points are not clear or if I misunderstand something.

Comment on lines +202 to +206
// Wagmi-specific values
chainId,
accounts,
isConnected,
ethersSigner,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to pass those value here? Could we not dissociate the contract process (fhecounter) and the wallet connection?
I think it would be nice if we could simplify this code example to simplify the on-boarding of new users. To let them pass less time trying to understand the code, but more on the interaction process.
I am just thinking of people who could have some experience in React/wagmi but nothing in FHE, it has to be easy and simple.

Comment on lines +11 to +17
export const useFHEDecrypt = (params: {
instance: FhevmInstance | undefined;
ethersSigner: ethers.JsonRpcSigner | undefined;
fhevmDecryptionSignatureStorage: GenericStringStorage;
chainId: number | undefined;
requests: readonly FHEDecryptRequest[] | undefined;
}) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not parse the result value here? I might know where I get the handle from (user balance, result of a poll) then decide to have the parsing done here directly?

Comment on lines +84 to +95
const encryptWith = useCallback(
async (buildFn: (builder: RelayerEncryptedInput) => void): Promise<EncryptResult | undefined> => {
if (!instance || !ethersSigner || !contractAddress) return undefined;

const userAddress = await ethersSigner.getAddress();
const input = instance.createEncryptedInput(contractAddress, userAddress) as RelayerEncryptedInput;
buildFn(input);
const enc = await input.encrypt();
return enc;
},
[instance, ethersSigner, contractAddress],
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code example I can see

const firstInput = functionAbi.inputs[0]!;
const method = getEncryptionMethod(firstInput.internalType);        
const enc = await encryptWith(builder => {
  (builder as any)[method](valueAbs);
});
if (!enc) return setMessage("Encryption failed");

I apologize but I do not understand what it is doing? How can I encrypt multiple elements? Can I stack them? I am afraid than trying to abstract too much here, we are completely losing what we are trying to do here.

In some of our implementation we have try to be exhaustive, maybe not the best approach

Defined types
export enum SUPPORTED_TYPES {
  'ebool',
  'euint4',
  'euint8',
  'euint16',
  'euint32',
  'euint64',
  'euint128',
  'euint160',
  'euint256',
  'address',
  'bytes64',
  'bytes128',
  'bytes256'
}

const SUPPORTED_TYPES_MAP: Record<SUPPORTED_TYPES, number> = {
  [SUPPORTED_TYPES.ebool]: 0,
  [SUPPORTED_TYPES.euint4]: 1,
  [SUPPORTED_TYPES.euint8]: 2,
  [SUPPORTED_TYPES.euint16]: 3,
  [SUPPORTED_TYPES.euint32]: 4,
  [SUPPORTED_TYPES.euint64]: 5,
  [SUPPORTED_TYPES.euint128]: 6,
  [SUPPORTED_TYPES.euint160]: 7, // @dev It is the one for eaddresses.
  [SUPPORTED_TYPES.euint256]: 8,
  [SUPPORTED_TYPES.address]: 7, // @dev It is the one for eaddresses.
  [SUPPORTED_TYPES.bytes64]: 9,
  [SUPPORTED_TYPES.bytes128]: 10,
  [SUPPORTED_TYPES.bytes256]: 11
}

const EXPECTED_TYPE_TO_RESULT_MAP: Record<SUPPORTED_TYPES, 'boolean' | 'bigint' | 'string'> = {
  [SUPPORTED_TYPES.ebool]: 'boolean',
  [SUPPORTED_TYPES.euint4]: 'bigint',
  [SUPPORTED_TYPES.euint8]: 'bigint',
  [SUPPORTED_TYPES.euint16]: 'bigint',
  [SUPPORTED_TYPES.euint32]: 'bigint',
  [SUPPORTED_TYPES.euint64]: 'bigint',
  [SUPPORTED_TYPES.euint128]: 'bigint',
  [SUPPORTED_TYPES.euint160]: 'string', // @dev It is the one for eaddresses.
  [SUPPORTED_TYPES.euint256]: 'bigint',
  [SUPPORTED_TYPES.address]: 'string', // @dev It is the one for eaddresses.
  [SUPPORTED_TYPES.bytes64]: 'bigint',
  [SUPPORTED_TYPES.bytes128]: 'bigint',
  [SUPPORTED_TYPES.bytes256]: 'bigint'
}

But this allow us to simply defined the handle logic

  const decryptionHandle = {
    value: hexHandleToBigInt(bid.eAmount),
    type: SUPPORTED_TYPES.euint64,
    contractAddress: NEXT_PUBLIC_AUCTION_CONTRACT
  }

  const { decryptedValues, isDecrypting, decrypt } = useDecrypt([decryptionHandle])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently it looks at the abi defined internal method to check what kind of type it should be, so it's automated.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I understand that you are reading the ABI to determined the exact type needed for your function. But here how do you handle multiple encrypted parameters? Do you need to stacked them as follow?

const enc = await encryptWith(builder => {
  (builder as any)["add64"](10)["add64"](20);
});
if (!enc) return setMessage("Encryption failed");

IMO, I think we should simplify this process. Maybe a topic to set in an issue.

Comment on lines +11 to +17
export const useFHEDecrypt = (params: {
instance: FhevmInstance | undefined;
ethersSigner: ethers.JsonRpcSigner | undefined;
fhevmDecryptionSignatureStorage: GenericStringStorage;
chainId: number | undefined;
requests: readonly FHEDecryptRequest[] | undefined;
}) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see some parameter that we need to redefined each time as

instance: FhevmInstance | undefined;
ethersSigner: ethers.JsonRpcSigner | undefined;
fhevmDecryptionSignatureStorage: GenericStringStorage;
chainId: number | undefined;

Would it be not possible to abtract them? Cannot we retrieve the instance using the useFhevm() hook if we already initialize before?
This is a naive question and I maybe missed some stuff, but was wondering if a Singleton pattern could not help us here, instead of distributing in our code the instance.
Same with the chainId, is it not something we could retrieve?

And for the storage, we would definitively need a way to store the handles. Could we not defined on by default using a configuration system? As some defined in scaffold.config.ts? Again, not a statement but more a design reflection here

Copy link

@RegisGraptin RegisGraptin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I have the rights to approve this PR.

Nevertheless, I do not know how you want to organized on this project, but please keep track of the discussion. I truly believe we need to simplify the nextjs project as currently, I think, it is really hard to appropriate this template to build your own dapp.
And I do not want to leave it as it is as I think it can be helpful to have a good starter. Let's discuss about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this message after pnpm install

Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
May be we could add an instruction in the README to help the user handle this situation, What do you think ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved this :)

@poppyseedDev
Copy link
Contributor Author

Also changed the visuals to more ZAMA style:

Screenshot 2025-10-08 at 14 01 32

@poppyseedDev poppyseedDev merged commit 4617473 into main Oct 8, 2025
@poppyseedDev poppyseedDev deleted the poppyseed/imporvments branch October 8, 2025 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants