Skip to main content
Set up a Foundry project with @cofhe/foundry-plugin, write a contract that stores an encrypted uint32, and test the encrypt to store to decrypt flow under forge test.
Want to skip the setup? Clone the cofhe-foundry-starter template to get a pre-configured project with everything ready to go.

Prerequisites

  • Foundry (forge, cast, anvil)
  • Node.js 18+ with npm/pnpm/yarn (for installing the plugin’s npm packages)

1. Install dependencies

The plugin and its CoFHE dependencies are distributed via npm. Install them as dev dependencies, then forge install for forge-std:

2. Configure foundry.toml

foundry.toml
code_size_limit = 100000 is required, the mock contracts exceed the EIP-170 24 KB limit.
evm_version = "cancun" is no longer required as of @cofhe/mock-contracts@0.7.1. MockACL was migrated off transient storage to block-number-based storage. Set it only if your own contracts need cancun-specific opcodes.

3. Configure remappings.txt

remappings.txt
The hardhat/=node_modules/forge-std/src/ line is load-bearing. MockCoFHE.sol imports hardhat/console.sol, and this alias resolves it to forge-std’s compatible console.sol.

4. Write a contract

src/MyContract.sol
  • euint32: an encrypted uint32 stored onchain as a ciphertext handle.
  • externalEuint32: the encrypted input handle produced by CofheClient, paired with a bytes proof.
  • FHE.allowThis / FHE.allowSender: grant the contract and caller permission to read the encrypted value (required by the ACL).

5. Write a test

test/MyContract.t.sol

6. Run

What just happened?

  1. deployMocks() deployed the full CoFHE coprocessor mock stack (TaskManager, ACL, ZK verifier, threshold network) to the in-process EVM.
  2. createCofheClient() + bob.connect(BOB_PKEY) spun up an in-Solidity SDK shim bound to vm.addr(BOB_PKEY).
  3. bob.createExternalEuint32(42, address(myContract)) produced a signed externalEuint32 and its proof, the same shape your contract receives on testnet, signed by MockZkVerifierSigner.
  4. vm.prank(bob.account()) + setValue(...) called the contract as Bob. The contract stored the ciphertext handle and granted ACL access to itself and Bob.
  5. expectPlaintext(myContract.storedValue(), 42) read the onchain plaintext directly from MockTaskManager.mockStorage, no ACP, no SDK round-trip.

Next steps