The Interfold Contract
This page describes the public API of the Interfold contract (Interfold.sol) for application
builders. It covers the request function and its parameters, where inputs go, the two output
functions, the read functions, the events, and the custom errors. At the end of the page, you can
call the contract directly or read the calls that the SDK makes for you. For the stages and their
deadlines in order, see E3 lifecycle.
What the contract does
The Interfold contract records each E3 and moves it through its stages. It does these tasks:
- Accepts E3 requests and takes the fee.
- Asks the
CiphernodeRegistryto select a committee. - Records the committee public key commitment when the registry reports it.
- Accepts the ciphertext output after the E3 program and the protocol verifier accept the proof.
- Accepts the plaintext output after the decryption verifier accepts the proof.
- Pays rewards on success and sends failed E3s to refund settlement.
The Interfold contract does not accept inputs. Each E3 program accepts its own inputs in its
publishInput function. See Input publication.
- requestThe requester pays the fee. Interfold asks the registry for a committee.
- publishInputData providers send encrypted inputs to the E3 program, not to Interfold.
- publishCiphertextOutputA server sends a proof-backed reference to the encrypted result.
- publishPlaintextOutputCiphernodes send the decrypted result and the decryption proof.
Request an E3
The request function takes one struct and returns the new E3 ID and the stored E3 record.
function request(
E3RequestParams calldata requestParams
) external returns (uint256 e3Id, E3 memory e3);request pulls the fee with transferFrom. Before you call it, approve the Interfold contract to
spend the quoted fee in the fee token. For the fee formula and the refund rules, see
Request an E3.
Request parameters
E3RequestParams is defined in interfaces/IInterfold.sol.
| Field | Type | Meaning | Rule |
|---|---|---|---|
committeeSize | CommitteeSize (uint8) | Minimum (0), Micro (1), or Small (2). | The size must have thresholds configured. The pricing minimums must accept it. |
inputWindow | uint256[2] | Start and end timestamps of the input window, in seconds. | The start must not be in the past. The end must not be before the start. |
e3Program | IE3Program | The E3 program contract. | The contract owner must register the program first. |
paramSet | uint8 | BFV parameter set. 0 is insecure-64, 2 is secure-8192. | The chain must support the set, and the set must be registered. |
computeProviderParams | bytes | Compute provider settings. | Interfold passes the bytes to e3Program.validate. |
customParams | bytes | Application settings. | Interfold stores the bytes on the E3 and passes them to e3Program.validate. |
expectedFeeToken | IERC20 | The fee token that the requester accepts. | Must equal feeToken(). Otherwise the call reverts with FeeTokenChanged. |
expectedCryptoConfigId | bytes32 | The circuit configuration that the requester accepts. | Must equal the ID for paramSet. Otherwise the call reverts with CryptoConfigChanged. |
maxFee | uint256 | The largest total fee that the requester accepts. | The quote must not be more than maxFee. Otherwise the call reverts. |
The configuration IDs for each parameter set are constants in lib/ActiveCryptoConfig.sol
(INSECURE_CONFIG_ID and SECURE_CONFIG_ID). The SDK fills expectedFeeToken,
expectedCryptoConfigId, and maxFee for you. See SDK.
What request checks
request runs these checks in order. The first check that fails reverts the call.
- Requests are not paused (
RequestsPaused). A new deployment starts with requests paused. - The registry, bonding registry, slashing manager, refund manager, and node release registry form
one consistent set (
DependencyConfigurationMismatch). - The current fee token is on the allow-list (
FeeTokenNotAllowed). - The E3 program is registered (
E3ProgramNotAllowed). - The quote succeeds. The quote checks the input window, the total duration, the parameter set, and the committee size.
- The current fee token, the configuration ID for
paramSet, and the quote agree withexpectedFeeToken,expectedCryptoConfigId, andmaxFee. - The E3 program
validatecall returns an encryption scheme ID. Interfold must have a decryption verifier and a public key verifier for that scheme (InvalidEncryptionScheme). - The fee transfer delivers the exact amount (
AssetTransferMismatch). - The registry accepts the committee request. The registry reverts when fewer than N eligible
ciphernodes (
InsufficientCiphernodes) or fewer than N bond owners (InsufficientBondOwners) are available.
The total duration check uses the worst case. Interfold takes the later of the input window end and
the committee setup time, then adds the compute window and the decryption window. The committee
setup time is the randomness timeout, plus the sortition submission window, plus the DKG window. The
total must not be more than maxDuration (InvalidDuration).
What request stores and emits
A successful request does these things:
- Assigns the next E3 ID. The first ID is the Interfold address shifted left by 96 bits, so E3 IDs are large numbers.
- Freezes the registry, bonding registry, refund manager, slashing manager, and timeout configuration for this E3.
- Stores the service fee as escrow. It credits the flat randomness fee to the treasury.
- Sets the stage to
Requested. - Emits
E3Requested(e3Id, e3, cryptoConfigId)andE3StageChanged(e3Id, None, Requested).
The E3 record
getE3(e3Id) returns the E3 struct from interfaces/IE3.sol.
| Field | Type | Content |
|---|---|---|
seed | uint256 | Seed for the computation. Committee selection uses a separate VRF seed. |
committeeSize | CommitteeSize | The requested committee size. |
requestBlock | uint256 | The request timestamp. The name is kept for ABI compatibility. |
inputWindow | uint256[2] | The requested input window. |
encryptionSchemeId | bytes32 | The scheme that e3Program.validate returned. |
e3Program | IE3Program | The E3 program address. |
paramSet | uint8 | The BFV parameter set. |
customParams | bytes | The application settings from the request. |
decryptionVerifier | IDecryptionVerifier | The verifier for the decryption proof. |
pkVerifier | IPkVerifier | The verifier for the DKG public key proof. |
committeePublicKey | bytes32 | The committee public key commitment. It is not the full key. |
ciphertextOutput | bytes32 | Keccak-256 of the serialized ciphertext output. |
plaintextOutput | bytes | The decrypted result. |
requester | address | The account that called request. |
ciphertextCommitment | bytes32 | The SAFE commitment to the ciphertext that the decryption proof uses. |
Input publication
Inputs go to the E3 program. IE3Program defines the entry point:
function publishInput(uint256 e3Id, bytes memory data) external;The E3 program decides the encoding of data, the checks, and the storage. Interfold does not check
the input window for inputs. Interfold enforces the window only on the output: it rejects a
ciphertext output before inputWindow[1]. The default template and CRISP use different input paths.
| Program | Encoding of data | Where the ciphertext bytes go |
|---|---|---|
MyProgram (templates/default) | abi.encode(bytes ciphertext, bytes32 ciphertextCommitment) | On-chain, in the InputPublished(e3Id, data, index) event. The contract inserts the commitment into a LazyIMT tree. |
CRISPProgram (CRISP (opens in a new tab)) | A ballot proof, the voting slot, the ciphertext commitment and hash, the parent index, and a signed availability attestation | To Avail. publishInput reserves the tree leaf and emits InputCommitted. Later, finalizeInput checks the Avail receipt and emits InputPublished. |
The template program does not prove that the ciphertext matches its commitment. A comment in
MyProgram.sol states that a production program must verify this binding. For the program side, see
Program contract.
Publish the ciphertext output
After the compute provider runs, a server publishes a reference to the encrypted result. The ciphertext bytes stay off Ethereum, on a data availability layer.
function publishCiphertextOutput(uint256 e3Id, bytes calldata encodedOutputReference) external;encodedOutputReference is the ABI encoding of one CiphertextOutputReference tuple:
| Field | Type | Content |
|---|---|---|
contentHash | bytes32 | Keccak-256 of the exact serialized ciphertext bytes. |
ciphertextCommitment | bytes32 | The SAFE commitment to the decoded ciphertext. |
computeProof | bytes | The compute proof. It binds contentHash and the commitment. |
availabilityProof | bytes | The data availability receipt for contentHash. |
Any account can call the function. The call succeeds only when all of these conditions are true:
- The E3 is in
KeyPublished. - The current time is at or after
inputWindow[1](InputDeadlineNotReached). - The current time is at or before the compute deadline (
CommitteeDutiesCompleted). - No output exists yet (
CiphertextOutputAlreadyPublished), andcontentHashis not zero. - The committee still has enough active members (
ThresholdNotMetfrom the registry). e3Program.verifyDataAvailability(contentHash, availabilityProof)returns a receipt for the samecontentHash.- The request-time protocol ciphertext verifier and
e3Program.verifyboth accept the proof.
A receipt for a different hash, or a proof that a verifier rejects, reverts with InvalidOutput.
The E3 program can also revert with its own error. On success, the E3 moves to CiphertextReady and
the decryption deadline starts. The contract emits
CiphertextOutputReferencePublished(e3Id, contentHash, ciphertextCommitment, availabilityBlock, availabilityLeafIndex)
and E3StageChanged.
registerE3Program accepts only a program that implements
IE3ProgramDataAvailability.verifyDataAvailability and advertises IE3Program and
IE3ProgramDataAvailability through ERC-165. Otherwise it reverts with
E3ProgramInterfaceMissing. The template version checks only that the proof bytes hash to
contentHash. It is for local development.
Publish the plaintext output
The committee decrypts the output, and one ciphernode publishes the result and the proof.
function publishPlaintextOutput(
uint256 e3Id,
bytes calldata plaintextOutput,
bytes calldata proof
) external returns (bool success);The call succeeds only when the E3 is in CiphertextReady and the decryption deadline has not
passed. The proof must not be empty (ProofRequired). The committee must still be viable, and the
decryption verifier must accept the proof.
On success, the E3 moves to Complete. The contract credits the treasury share and the committee
rewards. It emits RewardsDistributed, PlaintextOutputPublished(e3Id, plaintextOutput, proof),
and E3StageChanged. Rewards are pull payments. Each recipient calls claimReward(e3Id) or
claimRewards(e3Ids).
Failure functions
These functions handle an E3 that does not finish. For the rules and the refund amounts, see Request an E3.
| Function | Caller | Effect |
|---|---|---|
checkFailureCondition(e3Id) | Anyone (view) | Returns (canFail, reason) for the current stage deadline. |
markE3Failed(e3Id) | Anyone after the grace period | Moves an overdue E3 to Failed with a timeout reason. |
cancelE3(e3Id) | The requester only | Fails an E3 whose randomness request expired without a usable result. |
processE3Failure(e3Id) | Anyone | Sends the service escrow to the refund manager and calculates the refund. |
During markFailedGracePeriod after a deadline, only the requester, the contract owner, or an
active committee member can call markE3Failed (MarkE3FailedInGracePeriod).
Read functions
These view functions are the ones that applications use most.
| Function | Returns |
|---|---|
getE3(e3Id) | The E3 record. Reverts with E3DoesNotExist for an unknown ID. |
getE3Stage(e3Id) | The E3Stage value. |
getFailureReason(e3Id) | The FailureReason value. None when the E3 has not failed. |
getRequester(e3Id) | The requester address. |
getDeadlines(e3Id) | E3Deadlines { dkgDeadline, computeDeadline, decryptionDeadline }. |
getE3TimeoutConfig(e3Id) | The timeout windows frozen at request time. |
getE3LifecycleDeadline(e3Id) | The latest possible lifecycle deadline, set at request time. |
getTimeoutConfig() | The current E3TimeoutConfig { dkgWindow, computeWindow, decryptionWindow }. |
getE3Quote(params) | The total fee for an E3RequestParams value at the current block. |
getPricingConfig() | The current PricingConfig. |
feeToken(), feeTokenDecimals() | The current fee token and its expected decimals. |
isFeeTokenAllowed(token) | Whether a token is on the fee-token allow-list. |
requestsPaused() | Whether new requests revert. |
e3Programs(program) | Whether a program is registered for new requests. |
paramSetRegistry(paramSet) | The ABI-encoded BFV parameters. Empty when the set is not registered. |
committeeThresholds(size, index) | Index 0 is H and index 1 is N for a committee size. |
e3CryptoConfigIds(e3Id) | The configuration ID frozen for an E3. |
maxDuration(), markFailedGracePeriod() | The duration limit and the failure grace period, in seconds. |
pendingReward(e3Id, account) | The reward that an account can claim for an E3. |
ciphernodeRegistry(), e3RefundManager() | The current registry and refund manager. |
Events
The Interfold contract emits these events for the E3 lifecycle.
| Event | Emitted when |
|---|---|
E3Requested | request succeeds. It carries the full E3 record and the indexed configuration ID. |
E3StageChanged | Any stage changes. It carries the previous stage and the new stage. |
CommitteeFinalized | The registry finalizes the committee. |
CommitteeFormed | The registry reports the committee public key, and the E3 moves to KeyPublished. |
CiphertextOutputReferencePublished | publishCiphertextOutput succeeds. |
PlaintextOutputPublished | publishPlaintextOutput succeeds. |
RewardsDistributed, RewardCredited | Rewards are credited after success. |
TreasuryCredited | The randomness fee is credited at request time, or the protocol share is credited at success. |
E3Failed | An E3 fails. It carries the stage at failure and the FailureReason. |
E3FailureReclassified | An expulsion changes a requester-paid failure reason to a ciphernode-paid reason. |
E3FailureProcessed | processE3Failure sends the escrow to the refund manager. |
IInterfold also declares InputPublished and CiphertextOutputPublished. The Interfold contract
does not emit them. E3 programs emit their own input events, and new outputs use
CiphertextOutputReferencePublished.
The CiphernodeRegistry emits the committee events. Applications use these most:
| Registry event | Content |
|---|---|
CommitteeRandomnessRequested | The randomness request ID, the provider, and the randomness deadline. |
SortitionCommitteeFinalized | The selected committee and the ticket scores. |
CommitteeFormationFailed | Too few tickets or no usable randomness at finalization. |
CommitteeProofPublished | The committee, the public key commitment, and the verified DKG proof. |
CommitteePublicKeyChunkPublished | One chunk of the serialized public key. Clients join the chunks to get the full key. |
Custom errors
These errors are the ones that an application sees most. All are declared in IInterfold, except
the registry errors.
| Error | Cause |
|---|---|
RequestsPaused() | The owner paused new requests. |
FeeTokenNotAllowed(token) | The current fee token is not on the allow-list. |
E3ProgramNotAllowed(program) | The program is not registered. |
InvalidInputDeadlineStart(start), InvalidInputDeadlineEnd(end) | The input window starts in the past or ends before it starts. |
InvalidDuration(duration) | The worst-case lifecycle is longer than maxDuration. |
UnsupportedCryptoConfig() | The chain does not support the parameter set or the committee shape. |
CommitteeSizeNotConfigured(size) | No thresholds are set for the committee size. |
CommitteeSizeTooSmall(size), ThresholdTooSmall(threshold) | The committee size is below the pricing minimums. |
FeeTokenChanged(expected, actual) | expectedFeeToken is not the current fee token. |
CryptoConfigChanged(expected, actual) | expectedCryptoConfigId is not the ID for paramSet. |
FeeExceedsMaximum(fee, maximum) | The quote is more than maxFee. |
InvalidEncryptionScheme(id) | No verifier is set for the scheme that the program returned. |
InsufficientCiphernodes(requested, available) | Registry: too few eligible ciphernodes for N. |
InputWindowClosedBeforeKeyPublication(e3Id, inputDeadline) | The committee tried to publish its key after the input window closed. |
InvalidStage(e3Id, expected, actual) | The call is not valid in the current stage. |
InputDeadlineNotReached(e3Id, inputDeadline) | A ciphertext output arrived before the input window closed. |
CommitteeDutiesCompleted(e3Id, expiration) | An output arrived after its deadline. |
CiphertextOutputAlreadyPublished(e3Id) | The E3 already has a ciphertext output. |
InvalidOutput(output) | The data availability receipt or the compute proof failed. |
ProofRequired() | The plaintext proof is empty. |
FailureConditionNotMet(e3Id) | markE3Failed was called before the stage deadline passed. |
E3NotCancellable(e3Id, stage) | cancelE3 was called outside its narrow condition. |
Security considerations
- Committee size. The committee enum fixes N, H, and T. You cannot choose other thresholds. A larger committee costs more because the quote grows with N and H.
- Input validation. Interfold does not see inputs. Your E3 program must check who can submit, when, and what. It must also bind each ciphertext to its commitment.
- Output verification. Interfold accepts a ciphertext output only if your program's
verifyaccepts the proof. A weakverifygives a weak guarantee. Your E3s also depend on the trust model of your compute provider. - Event finality. A reorganization can remove an event that you already read. Wait for enough confirmations before you act on an event that moves funds or ends a process.
Next steps
Fees, fee tokens, failure handling, refunds, and committee choice.
BuildSDKCall these functions from TypeScript and React.
BuildProgram contractWrite the E3 program that validates requests, inputs, and outputs.
BuildE3 lifecycleEach stage, its deadline, and what happens on a timeout.
Concepts