Best Practices
This page lists design and operations practices for E3 programs and the applications around them. It is for developers who design an E3 program, request E3s, or run a coordination server. Each practice names the mechanism in the code that makes it necessary. At the end, you have a deployment checklist.
Request parameters
- Choose a supported committee size. The committee enum fixes N, H, and T in
lib/ActiveCryptoConfig.sol. On mainnet, the launch pricing setsminCommitteeSizeto 19, so onlySmallis accepted.getE3Quotereverts withCommitteeSizeTooSmallfor a smaller size. - Use the secure parameter set for private data. Version-7 mainnet accepts only
paramSet2 (secure-8192). The insecure-64 preset has no production security. - Match the SDK preset to the parameter set. The SDK does not compare them. A mismatch encrypts inputs under the wrong parameters.
- Place the input window after the worst-case key time. The worst-case key time is the request
time plus
randomnessRequestTimeout,sortitionSubmissionWindow, anddkgWindow. The committee cannot publish its key afterinputWindow[1](InputWindowClosedBeforeKeyPublication). A window that starts earlier can lose input time while DKG runs. In Avail mode,CRISPProgram.validaterefuses a voting start before the worst-case key time. - Add a start buffer.
inputWindow[0]must not be earlier than the block time when the request executes.calculateInputWindowadds 15 seconds by default. - Keep the input window no longer than necessary. The quote charges node availability from the
request to the end of the input window. The worst-case lifecycle must also stay inside
maxDuration(InvalidDuration). - Put per-E3 settings in
customParams. Interfold stores the bytes on the E3 and passes them toe3Program.validate.CRISPProgramdecodes its round settings fromcustomParams.
Fees
- Quote right before the request. For the same parameters and pricing, a later block gives the same quote or a lower quote. An approval of the latest quote is enough.
- Approve only the quoted amount.
requestpulls exactly the quoted fee withtransferFrom. A larger approval stays open for later calls. - Set
maxFee,expectedFeeToken, andexpectedCryptoConfigId. These fields make the request revert when governance changes the fee, the fee token, or the circuit configuration after your quote.requestE3in the SDK sets the last two for you. - Check
requestsPaused()before you offer a request. A new deployment starts paused, and governance can pause requests again.
Program contract
- Advertise both interfaces.
registerE3ProgramprobesIE3ProgramandIE3ProgramDataAvailabilitythrough ERC-165. It rejects a program that does not advertise both (E3ProgramInterfaceMissing). - Check the request in
validate. Interfold stores the E3 record before it callsvalidate, so the program can read the input window and the frozen timeouts. A revert invalidatecancels the request before the fee transfer. - Gate
publishInputyourself. Interfold does not check inputs. The template program checks onlyinputWindow[1].CRISPProgramalso checks a ballot proof, a commitment deadline, and a signed availability attestation. - Keep each E3 inside the addition budget of its preset. The ciphernodes make the smudging noise
large enough for at most
zfresh ciphertexts added together.zis 100,000 for secure-8192 and for insecure-64. Interfold does not count inputs, so limit them inpublishInput.CRISPProgramstops at 100,000 inputs withInputLimitReached, a limit that fits the secure-8192 budget but not the insecure-64 budget. See Limits on the computation. - Bind each ciphertext to its commitment. The template program inserts the commitment into its
input tree without a proof of the binding. A comment in
MyProgram.solstates that production programs must verify it, because an invalid input can stop the E3 from completing. - Check the input root in
verify. The templateverifyrequires the compute proof to use the stored parameter hash and the current root of the input tree (InvalidComputeContext). A program without this check cannot prove which inputs the computation used. - Verify the arguments, not Interfold storage. Interfold calls
verifybefore it stores the output.IE3Programstates thatverifymust check the supplied hash, commitment, and proof. - Replace the mock data availability verifier. The template
verifyDataAvailabilityaccepts any bytes that hash to the content hash. It is for the local stack only.
Output and liveness
- Publish the ciphertext output inside its window. Interfold accepts it only after
inputWindow[1]and not after the compute deadline. Read the deadline withgetDeadlines(e3Id). - Treat the compute deadline as a hard limit. A missed compute deadline fails the E3 with
ComputeTimeout. The requester pays for that failure: 50% of the service escrow goes to the honest members and 5% to the treasury. - Make publication safe to repeat. A second publication reverts with
CiphertextOutputAlreadyPublished. Check the stage before you retry after a crash. - Store job state on disk. The template server keeps its job state in memory and watches only new key events. After a restart, it does not schedule an E3 whose key was published earlier.
- Publish the ciphertext before you publish the reference. The ciphernodes fetch the bytes from
the data availability layer with the content hash. On the local stack, they read
GET /availability/objects/:contentHashon the template server.
Clients and events
- Check the committee key against its commitment. The key chunks are transport data. Use
CommitteePublicKeyAssemblerandvalidatePublicKeyCommitment, as the template client and server do. - Listen to the events that the contracts emit. Use
CIPHERTEXT_OUTPUT_REFERENCE_PUBLISHED, notCIPHERTEXT_OUTPUT_PUBLISHED. UseCOMMITTEE_PUBLIC_KEY_CHUNK_PUBLISHED, notCOMMITTEE_PUBLISHED. The current contracts do not emitCiphertextOutputPublishedorCommitteePublished. - Filter every event by E3 ID. The SDK watches all events of a type on the contract. The
template handlers compare
event.data.e3Idwith the current E3. - Read history with a start block.
getHistoricalEventsreads in ranges of 10,000 blocks when you givefromBlock. Start at the contract deployment block, not at block 0. - Wait for confirmations before an irreversible action. A reorganization can remove a log.
Ciphernodes apply logs after
ingestion_confirmationsblocks (default 3). The CRISP availability service reads finalized blocks before it retires a job.
Failures and refunds
- Know who can end an overdue E3. Ciphernodes submit
markE3FailedandprocessE3Failure. DuringmarkFailedGracePeriod(1 hour in the mainnet configuration), only the requester, the owner, or an active committee member can callmarkE3Failed. After that, any account can. - Expect a delay before a refund. For an E3 with a finalized committee, settlement opens one day
after
getE3LifecycleDeadline(e3Id). Until then,processE3Failurereverts withSettlementBlocked. - Request from an account that can claim. Only the requester address can call
claimRequesterRefund. A smart contract wallet must be able to make this call.
For the full refund rules, see Request an E3.
Testing
- Run a full E3 in CI.
pnpm test:integrationin the template runs the server tests, then an E3 from the request to the plaintext output (tests/integration.spec.ts). It needs aninterfoldbinary built with thetest-only-skip-proof-aggregationfeature.pnpm dev:setupbuilds it in the monorepo. - Test the runner without a request. With
TEST_MODE=1,GET /teston the server sendsserver/payload.jsonto the program runner.pnpm dev:allsetsTEST_MODE=1. - Test the contracts.
pnpm testin the template runs the Hardhat tests.
Deployment checklist
- Deploy the E3 program. Ask the Interfold owner to register it with
registerE3Program. - Replace the mock
verifyDataAvailabilitywith a real data availability verifier. - Set the chain, the RPC URL, and the preset in the server and the client.
- Fund the server key with gas for
publishCiphertextOutput. - Fund the requester with the fee token. Read the token from
feeToken(). - Confirm that
getE3Quoteaccepts your committee size and parameter set on the target chain. - Run
pnpm test:integrationagainst the new build.
On mainnet, the Interfold owner is the governance DAO. A program registration is a governance action.