Enclave is now The Interfold.
Build
Project Template

Project Template

interfold init makes a project from the default template (templates/default in the Interfold repository). This page is for developers who change that project. It describes what interfold init does, the folders and scripts of the project, its configuration, and the file to edit for each part. To run the template first, see the Quick Start.

What interfold init does

interfold init [PATH] [--template <URL>] [--skip-install] [--skip-cleanup]
Argument or optionEffect
PATHThe project folder. The folder must be empty or must not exist. Without PATH, the command uses the current folder.
--template <URL>The template source, in the form git+https://github.com/theinterfold/interfold.git#main:templates/default. The part after # is the branch or tag and the path.
--skip-installDo not run pnpm install. Use this option for an offline setup or for release candidates that are not published.
--skip-cleanupKeep the project folder if the command fails. This option is mainly for tests of the installer.

Without --template, the command uses tag v<CLI version> of https://github.com/theinterfold/interfold.git. For CLI 0.18.0, the tag is v0.18.0. The command does these operations in sequence:

  1. It makes a shallow clone of the repository in /tmp/__interfold-tmp-folder.1.
  2. It copies the template to the project folder. In each package.json, it replaces the workspace versions of @interfold/contracts, @interfold/react, and @interfold/sdk with the versions of the cloned release. In each Cargo.toml, including the guest's, it replaces every path dependency on an Interfold crate (e3-program-runner, e3-bfv-client, e3-fhe-params, e3-compute-provider, e3-openvm-types, and e3-safe) with a Git dependency at the cloned commit.
  3. It replaces .gitignore with .gitignore.bak, renames pnpm-workspace.yaml.bak to pnpm-workspace.yaml, and deletes lib/.
  4. It runs git init.
  5. It runs pnpm install, unless you give --skip-install.
  6. It commits all files with the message Initial Commit.

interfold init does not run when the CLI finds an interfold.config.yaml in the current folder, in a parent folder, or in the default configuration folder. In that case, it stops with Cannot run `interfold init` when a configuration exists.

Layout

The template copier uses e3-fs, a small async filesystem adapter. Production copying uses the physical filesystem; tests can use the same operations over an in-memory root. That test seam does not make copying or replacement an atomic filesystem transaction.

    • Cargo.toml
    • deployed_contracts.json
    • flake.nix
    • hardhat.config.ts
    • interfold.config.yaml
    • package.json
    • pnpm-workspace.yaml
    • remappings.txt
    • rust-toolchain.toml
  • PathContents
    program/The Rust crate e3-user-program. src/lib.rs exports fhe_processor (the FHE computation) and policy (the input policy).
    guest/The OpenVM guest that proves program/. A Cargo workspace of its own; openvm.toml lists the VM extensions.
    contracts/MyProgram.sol, the E3 program contract, and Mocks/MockOpenVmReceiptVerifier.sol, a verifier that accepts every receipt, for the local chain only.
    deploy/default.tsdeployTemplate, which deploys the receipt verifier and MyProgram, registers MyProgram on the Interfold contract, and writes the addresses to the config.
    scripts/The shell scripts behind the dev:* scripts, the local deploy entry point deploy-local.ts, and anvil-automine.mjs.
    server/The coordination server (index.ts) and the client for the program server (runner.ts).
    client/The React and Vite web client. It is the only package in pnpm-workspace.yaml.
    tests/The end-to-end test integration.spec.ts and its Anvil helpers.
    runner/The crate e3-user-program-runner. Its program-runner binary serves program/ as the development runner or the OpenVM proving service.
    Cargo.tomlThe Cargo workspace. Its members are program and runner.
    deployed_contracts.jsonThe deployment records that the deploy scripts read and write.
    flake.nixA Nix development shell with Rust 1.91.1, Node.js, and pnpm. .envrc loads it with direnv.

    A project that has an .interfold/support folder cannot run interfold program. To migrate it, delete .interfold/support and its two workspace members from Cargo.toml. Then copy runner/ from the template and add runner to the workspace members. In [workspace.dependencies], replace e3-program-server with e3-program-runner ={' '} {((git = 'https://github.com/theinterfold/interfold'), (rev = '<rev>'))}. Use the same rev as the other e3-* dependencies of the project.

    The scripts make more folders when they run:

    • .interfold/config/ and .interfold/data/: the ciphernode keys and databases.
    • .interfold/noir/: bb and the circuits that interfold noir setup installs.
    • .interfold/data-availability/: the output ciphertexts that the coordination server serves.
    • .interfold/caches/openvm/: the guest build, its proving keys, the receipt identity, and the worker configuration that interfold program compile writes.
    • types/, artifacts/, and cache/: the Hardhat and TypeChain output.
    • target/: the Cargo output.

    The .gitignore of the project ignores .interfold/, artifacts/, cache/, target/, node_modules, and .env files.

    Scripts

    package.json in the project root defines these scripts. Run a script with pnpm run <name>, for example pnpm run dev:all. The other pages use the short form, for example pnpm dev:all.

    ScriptCommandWhat it does
    dev:all./scripts/dev_all.shStarts the full local stack. See What runs. With --tmux, it runs scripts/dev_all_tmux.sh instead.
    predev:all./scripts/compile_program.shRuns interfold program compile with the local settings, before dev:all.
    dev:setupbash ./scripts/setup.shRuns pnpm install --frozen-lockfile, cargo build, interfold program compile, pnpm compile, and interfold noir setup. It stops if no interfold CLI is installed. Inside an Interfold repository checkout, it also builds the circuits and installs the CLI from source.
    dev:evmhardhat nodeStarts a Hardhat node on port 8545. dev:all uses Anvil instead. Only the tmux mode uses this script.
    dev:ciphernodes./scripts/dev_ciphernodes.shWaits for the chain. Sets the ciphernode wallets, runs interfold noir setup, deploys the contracts, starts the five nodes, and registers them.
    dev:server./scripts/dev_server.shWaits for the ciphernodes, sets the server environment, and starts server/index.ts with tsx.
    dev:program./scripts/dev_program.shWaits for the ciphernodes and runs interfold program start.
    dev:frontend./scripts/dev_frontend.shWaits for the chain and the program server. Exports the VITE_ variables and starts the client on port 3000.
    compilehardhat compileCompiles the Solidity contracts and generates the TypeChain types in types/.
    deploypnpm clean:deployments && hardhat run scripts/deploy-local.ts --network localhostDeletes the local deployment records, then deploys the protocol and MyProgram to localhost. Run it with pnpm run deploy, because pnpm deploy is a built-in pnpm command.
    deploy:devhardhat run scripts/deploy-local.ts --network localhostDeploys the protocol and MyProgram to localhost. It does not run clean:deployments first.
    clean:deploymentshardhat utils:clean-deploymentsDeletes the deployment records for a network. The default network is localhost.
    linteslint .Runs ESLint.
    testhardhat testRuns the Hardhat test runner.
    test:servervitest run ./server/runner.test.tsRuns the unit tests of the program server client.
    test:integrationpnpm test:server && ./scripts/test_integration.shRuns the server tests, then starts the stack and runs tests/integration.spec.ts. It needs a CLI built with the test-only-skip-proof-aggregation feature.

    The client package (client/package.json) has its own scripts: dev (vite --no-open --host), build, preview, format, and format:check.

    interfold.config.yaml

    interfold.config.yaml configures the local chain, the program mode, and the local ciphernodes. The CLI reads it from the current folder or from a parent folder. The template file has this structure. The contract addresses, the deploy blocks, and the node addresses are placeholders here. The deploy script writes the contract values.

    interfold.config.yaml
    chains:
      - name: 'localhost'
        rpc_url: 'ws://localhost:8545'
        ingestion_confirmations: 0
        rpc_poll_interval_ms: 250
        data_availability:
          mode: mock_http
          rpc_url: http://127.0.0.1:8080/availability
        contracts:
          e3_program:
            address: '<address>'
            deploy_block: <block>
          interfold:
            address: '<address>'
            deploy_block: <block>
          # ciphernode_registry, bonding_registry, slashing_manager, and fee_token
          # have the same two keys.
    program:
      dev: false
    nodes:
      cn1:
        address: '<Anvil account 1>'
        quic_port: 9201
        ctrl_port: 50501
        autonetkey: true
        autopassword: true
        dashboard_port: 8004
      cn2:
        address: '<Anvil account 2>'
        quic_port: 9202
        ctrl_port: 50502
        autonetkey: true
        autopassword: true
      # cn3, cn4, and cn5 follow the same pattern (ports 9203 to 9205 and 50503 to 50505).
    KeyTemplate valueMeaning
    chains[].namelocalhostThe chain name. interfold print-env --chain localhost and the deploy scripts use this name.
    chains[].rpc_urlws://localhost:8545The RPC endpoint of the chain.
    chains[].ingestion_confirmations0Confirmations before a node applies EVM logs. The default is 3. Use 0 only for a single-process development chain such as Anvil.
    chains[].rpc_poll_interval_ms250Milliseconds between the polls of an HTTP provider for a receipt or a new block. The default is 7000. Use 250 only for a single-process development chain such as Anvil.
    chains[].data_availability.modemock_httpWhere nodes fetch the output ciphertext. mock_http reads it from a local HTTP service. The other mode is avail.
    chains[].data_availability.rpc_urlhttp://127.0.0.1:8080/availabilityThe coordination server. It serves each object at /availability/objects/<contentHash>.
    chains[].contracts.<name>address, deploy_blockThe contract address and the block to read events from. deploy/default.ts writes these values for the contracts that it deploys.
    program.devfalsefalse proves with OpenVM. true runs the development runner natively, without a proof. The local scripts set E3_PROGRAM__DEV=true unless TEMPLATE_REAL_PROOFS=1.
    program.openvmCommented outThe OpenVM workers and backend for dev: false. See Compute Provider.
    nodes.<name>.addressAnvil accounts 1 to 5The Ethereum address of the ciphernode.
    nodes.<name>.quic_port9201 to 9205The QUIC port for peer-to-peer traffic.
    nodes.<name>.ctrl_port50501 to 50505The port of the control socket that the CLI uses to talk to a running node.
    nodes.<name>.autonetkeytrueGenerate a network key on start if none is set.
    nodes.<name>.autopasswordtrueGenerate a password on start if none is set.
    nodes.<name>.dashboard_port8004 (cn1 only)Serves the node dashboard at http://127.0.0.1:8004.

    interfold program compile and interfold program start also accept --dev true or --dev false. The flag overrides program.dev for that one command. The local scripts load scripts/lib/dev_config.sh, which sets E3_PROGRAM__DEV=true and TEMPLATE_UNPROVED_TEST=1 unless TEMPLATE_REAL_PROOFS=1. TEMPLATE_UNPROVED_TEST=1 makes deployTemplate deploy MockOpenVmReceiptVerifier, and it works only on chain ID 31337.

    The CLI keeps the node data next to this file: keys in .interfold/config/<node>, databases in .interfold/data/<node>, and the prover files in .interfold/noir/. An environment variable with the E3_ prefix overrides a key. Two underscores separate the levels, for example E3_NODES__CN1__SKIP_PROOF_AGGREGATION=true. For every key, see the configuration reference.

    Environment variables

    The template ships no .env files. The scripts set the environment when they start each process.

    Client. scripts/dev_frontend.sh exports the output of interfold print-env --vite --chain localhost. If a required variable is missing, the client shows Environment Configuration Required. You can also set these variables in client/.env.

    VariableRequiredSource or default
    VITE_INTERFOLD_ADDRESSYeschains[].contracts.interfold
    VITE_E3_PROGRAM_ADDRESSYeschains[].contracts.e3_program
    VITE_REGISTRY_ADDRESSYeschains[].contracts.ciphernode_registry
    VITE_BONDING_REGISTRY_ADDRESSYeschains[].contracts.bonding_registry
    VITE_FEE_TOKEN_ADDRESSYeschains[].contracts.fee_token
    VITE_RPC_URLNochains[].rpc_url. Default: http://localhost:8545.
    VITE_THRESHOLD_BFV_PARAMS_PRESET_NAMENoDefault: INSECURE_THRESHOLD_64.
    VITE_WALLETCONNECT_PROJECT_IDNoA WalletConnect project ID for ConnectKit.

    Coordination server. scripts/dev_server.sh sets PRIVATE_KEY (Anvil account 0), CHAIN_ID=31337, and the output of interfold print-env --chain localhost: INTERFOLD_ADDRESS, RPC_URL, REGISTRY_ADDRESS, BONDING_REGISTRY_ADDRESS, E3_PROGRAM_ADDRESS, and FEE_TOKEN_ADDRESS. Then it sets RPC_URL=http://localhost:8545. These optional variables have defaults:

    VariableDefaultUse
    PORT8080The port of the coordination server.
    PROGRAM_RUNNER_URLhttp://127.0.0.1:13151The program server. The server posts each job to /run_compute.
    CALLBACK_URLhttp://127.0.0.1:8080The URL that the program server calls with the result.
    DATA_AVAILABILITY_DIRECTORY.interfold/data-availabilityThe folder for the output ciphertexts that the server serves.
    TEST_MODENot setWhen set, the server adds a GET /test route. dev:all sets it.

    Hardhat. hardhat.config.ts loads a .env file from the project root. It reads MNEMONIC (default: the Anvil test mnemonic), PRIVATE_KEY, RPC_URL, and block explorer API keys, for example ETHERSCAN_API_KEY.

    Dev scripts. scripts/lib/dev_config.sh reads BFV_PRESET (insecure-64 or secure-8192, default insecure-64) and COMMITTEE (default minimum). These variables have an effect only when the template is inside an Interfold repository checkout, where the scripts build the circuits. scripts/anvil-automine.mjs reads ANVIL_RPC_URL (default http://127.0.0.1:8545).

    Where to change things

    To changeEdit
    The FHE computationfhe_processor in program/src/lib.rs. See Hello World.
    Which inputs the computation usespolicy in program/src/lib.rs. The default policy uses every input.
    Input checks and proof verificationpublishInput, validate, verify, and verifyDataAvailability in contracts/MyProgram.sol.
    How the contracts are deployeddeploy/default.ts. scripts/deploy-local.ts calls it after it deploys the protocol with mocks.
    The committee size, input window, and parameter sethandleRequestComputation in client/src/pages/steps/RequestComputation.tsx. It uses DEFAULT_E3_CONFIG.committeeSize, a 100-second window, and paramSet: 0.
    How the client encrypts and publishes inputsclient/src/pages/steps/EnterInputs.tsx and client/src/utils/input.ts.
    How the client shows the resultclient/src/pages/steps/EncryptSubmit.tsx and client/src/pages/steps/Results.tsx.
    The SDK setupclient/src/utils/sdk-config.ts and client/src/context/WizardContext.tsx (client), createPrivateSDK in server/index.ts (server).
    When the computation starts and how the output is publishedserver/index.ts. The server schedules the job when the input window closes. It skips an E3 with fewer than two inputs.
    The program server and its proofrunner/src/main.rs calls e3_program_runner::run. program-runner dev is unproved. program-runner openvm is the OpenVM service.
    What the guest proves withguest/openvm.toml (the VM extensions) and the openvm-hashes feature of program/Cargo.toml. A change gives a new receipt identity.
    The local ciphernodesThe nodes section of interfold.config.yaml and scripts/dev_ciphernodes.sh. Both files must list the same nodes.
    The local chainThe anvil command in scripts/dev_all_concurrently.sh and scripts/anvil-automine.mjs.

    Change the ciphernode set

    scripts/dev_ciphernodes.sh has one private key per node (PRIVATE_KEY_CN1 to PRIVATE_KEY_CN5). It reads each node address from interfold.config.yaml, expects five nodes to start (EXPECTED_NODES=5), and registers each address with ciphernode:admin-add. To add or remove a node, change all of these items together with the nodes section of interfold.config.yaml.

    ⚠️

    The template is for local development. MyProgram.publishInput does not prove that a ciphertext matches its commitment, and verifyDataAvailability is a local mock. A production E3 program must do both checks. The CRISP program (opens in a new tab) shows one approach. The program server does not authenticate callers, so it is not safe on an untrusted network.

    Next steps