Enclave is now The Interfold.
Build
Request an E3

Request an E3

This page is for requesters. A requester is the account that calls request on the Interfold contract and pays for an E3. The page explains the fee and how the contract computes it, the fee token on each network, and the lifecycle from the requester side. It also explains failures, refunds, and the choice of committee size and parameter set. It ends with a checklist that you can use before each request.

For the function signatures, see The Interfold Contract. For the SDK calls, see SDK.

What the requester pays

The requester pays the total fee in one transfer when request succeeds. The total has two parts.

PartWhere it goesRefund on failure
Service feeEscrow in the Interfold contract (e3Payments) until the E3 ends.Full or partial. See Who pays for a failure.
Flat randomness feeCredited to the request-time treasury when the request succeeds.None.

The flat randomness fee (randomnessFlatFee) pays for the VRF request that selects the committee. The margin does not apply to it.

When the E3 completes, the service escrow is split in two:

  • The treasury gets protocolShareBps of the service escrow.
  • The active committee members share the rest in equal parts. One member gets the rounding dust.
  • If no active member remains, the requester gets the service escrow back.

Committee rewards are pull payments. The contract credits them, and each recipient claims them.

How the fee is computed

getE3Quote(params) returns the total fee. The math is in lib/InterfoldPricing.sol. It uses N and H from committeeThresholds for the committee size and the PricingConfig. It also uses the timeout windows, the sortition submission window, the input window, and the block time.

Each node produces a fixed number of proofs:

P=14+4(N−1)P = 14 + 4(N - 1)

The base cost BB is the sum of these terms. Each coefficient is a PricingConfig field in raw fee-token units.

TermFormulaPricingConfig field
Key generation, fixed partkf⋅Nk_f \cdot NkeyGenFixedPerNode
Key generation, proofskp⋅N⋅Pk_p \cdot N \cdot PkeyGenPerEncryptionProof
Key generation coordinationc⋅N(N−1)/2c \cdot N(N-1)/2coordinationPerPair
Proof verificationv⋅N⋅Pv \cdot N \cdot PverificationPerProof
Availabilitya⋅N⋅Da \cdot N \cdot DavailabilityPerNodePerSec
Decryptiond⋅Hd \cdot HdecryptionPerNode
Decryption coordinationc⋅H(H−1)/2c \cdot H(H-1)/2coordinationPerPair
PublicationpppublicationBase

DD is the billable duration in seconds. The contract takes the larger of two pre-compute estimates, then adds weighted compute and decryption time. It rounds DD down to whole seconds.

D=max⁡(Ws+L+Wkuk, E−t)+Wcuc+WdudD = \max\left(W_s + L + W_k u_k,\ E - t\right) + W_c u_c + W_d u_d

In this formula:

  • WsW_s is the sortition submission window, and LL is the input window length.
  • WkW_k, WcW_c, and WdW_d are the DKG, compute, and decryption windows.
  • uku_k, ucu_c, and udu_d are dkgUtilizationBps, computeUtilizationBps, and decryptUtilizationBps, as fractions of 10,000.
  • EE is the input window end, and tt is the block time.

The service fee is S=B⋅(10000+m)/10000S = B \cdot (10000 + m) / 10000, where mm is marginBps. The total fee is SS plus randomnessFlatFee. The contract uses integer division.

These rules follow from the formula:

  • A larger committee costs more. The key generation and coordination terms grow with N2N^2.
  • A later input window costs more for the same length. The E−tE - t term reserves node availability from the request to the end of the input window.
  • For the same parameters and pricing, a later block gives the same quote or a lower quote. request computes the quote again, so a fee approved from an earlier quote is enough.

getE3Quote reverts when the request is not valid. The errors are InvalidInputDeadlineStart, InvalidInputDeadlineEnd, InvalidDuration, UnsupportedCryptoConfig, CommitteeSizeNotConfigured, CommitteeSizeTooSmall, ThresholdTooSmall, and PaymentRequired. An unregistered parameter set reverts with the message BFV param set not registered.

Fee token and pricing per network

The deployment configuration sets the fee token and the pricing. Governance can change these values with setFeeAssetConfig and setRandomnessFlatFee. Read the live values with feeToken(), feeTokenDecimals(), and getPricingConfig().

SettingEthereum mainnetSepoliaLocal chains
Fee tokenUSDS, 18 decimalsMockUSDC, 6 decimalsMockUSDC, 6 decimals
randomnessFlatFee5 USDS1 USDC1.00 MockUSDC
marginBps1000 (10%)1000 (10%)1000 (10%)
protocolShareBps182 (1.82% of service fees)182182
minCommitteeSize1930 (no minimum)
minThreshold220 (no minimum)

The mainnet values come from deploy/protocol/mainnet-protocol.config.json. The Sepolia values come from deploy/protocol/sepolia-protocol.config.json. The local values come from scripts/deployInterfold.ts. On Sepolia, MockUSDC is a test token that anyone can mint. To get Sepolia USDC, run interfold faucet --chain sepolia. You can also call faucet() on the Faucet contract, or call mint on MockUSDC. For the contract addresses, see Contracts & Addresses.

Each request freezes its fee token. Refunds and rewards for that E3 use the frozen token, also after governance changes the fee token.

The lifecycle from the requester side

E3 lifecycle for a requester
RequesterE3Requested

Requested

The fee transfer succeeds. The registry requests VRF randomness and opens ticket submission.

Each stage has a deadline. The contract sets each deadline when the E3 enters the stage.

StageDeadlineFailure reason after the deadline
RequestedThe registry committee deadline. The contract adds the DKG window when enough tickets arrive.CommitteeFormationTimeout
CommitteeFinalizeddkgDeadline: the committee deadline plus the DKG window.DKGTimeout
KeyPublishedcomputeDeadline: the later of key publication and the input window end, plus the compute window.ComputeTimeout
CiphertextReadydecryptionDeadline: the ciphertext publication time plus the decryption window.DecryptionTimeout

The committee must publish its key before the DKG deadline and before the input window ends. A key publication after the DKG deadline reverts with DKGDeadlinePassed. A key publication after the input window end reverts with InputWindowClosedBeforeKeyPublication. Read the deadlines of an E3 with getDeadlines(e3Id).

The mainnet deployment configuration sets these windows:

WindowMainnet value
Randomness request timeout3600 s (1 hour)
Sortition submission window600 s (10 minutes)
DKG window21600 s (6 hours)
Compute window604800 s (7 days)
Decryption window21600 s (6 hours)
maxDuration2592000 s (30 days)
markFailedGracePeriod3600 s (1 hour)

When an E3 fails

An E3 moves to Failed in one of these ways:

  • Timeout. After a stage deadline, markE3Failed(e3Id) records the timeout reason for that stage. During markFailedGracePeriod, only the requester, the owner, or an active committee member can call it. After the grace period, anyone can call it.
  • Committee formation. finalizeCommittee on the registry records CommitteeFormationTimeout when no usable randomness arrived. It records InsufficientCommitteeMembers when fewer than N tickets arrived.
  • Slashing. An expulsion that leaves fewer than H active members records InsufficientCommitteeMembers.
  • Cancellation. The requester calls cancelE3. See Cancel a request.

Ciphernodes watch the deadlines and submit markE3Failed and processE3Failure for you. Any account can also submit them.

Who pays for a failure

lib/FailurePayerLib.sol assigns each failure reason to a payer. The payer decides the refund.

PayerFailure reasonsRequester refund of the service escrow
CiphernodesCommitteeFormationTimeout, InsufficientCommitteeMembers, DKGTimeout, DKGInvalidShares, DecryptionTimeout, DecryptionInvalidShares, VerificationFailed100%
RequesterNoInputsReceived, ComputeTimeout, ComputeProviderExpired, ComputeProviderFailed, RequesterCancelledThe share for work that was not done

For a requester-paid failure, the refund manager uses the work allocation that was frozen at request time. The default allocation is committeeFormationBps 1000, dkgBps 4000, decryptionBps 4500, and protocolBps 500. The four requester-paid reasons that new E3s can record map to the KeyPublished stage, so the split is:

RecipientShare of the service escrow
Honest committee members50%
Requester45%
Treasury5%

If no honest member remains, the members' share goes to the requester. RequesterCancelled is kept only for old E3s. New cancellations use CommitteeFormationTimeout.

⚠️

An E3 that gets no ciphertext output before the compute deadline fails with ComputeTimeout. The requester pays for that failure. Make sure that your compute provider and your server can publish the output inside the compute window.

These rules apply in every case:

  • The flat randomness fee is not refunded.
  • Slashed ciphernode collateral goes to the honest committee members, or to the treasury when no honest member remains. It does not go to the requester.

Cancel a request

cancelE3(e3Id) is a recovery path for a randomness request that did not produce a usable result. The call succeeds only when all of these conditions are true:

  • The caller is the requester (NotRequester).
  • The E3 is in Requested.
  • The registry has no sortition seed for the E3.
  • The randomness deadline has passed.

Otherwise the call reverts with E3NotCancellable. A valid VRF result disables cancellation. A requester therefore cannot see a committee and then cancel it to get a new draw.

A cancellation fails the E3 with CommitteeFormationTimeout and releases the committee. The requester gets 100% of the service escrow after settlement. The registry marks the randomness provider as degraded and emits RandomnessCircuitBreakerTripped. This flag is advisory. It does not stop new requests, and a new provider clears it.

Claim a refund

Refunds are pull payments. Any account can do the first three steps. Do the last step from the requester address.

Confirm that the E3 failed

Read getE3Stage(e3Id) on the Interfold contract. The value must be Failed (6). The E3Failed event also gives the reason.

Wait for settlement to open

For an E3 with a finalized committee, settlement opens one day after getE3LifecycleDeadline(e3Id). It also waits until no open proposal can expel a committee member. An E3 without a finalized committee settles at once. Before settlement opens, processE3Failure reverts with SettlementBlocked.

Process the failure

Call processE3Failure(e3Id) on the Interfold contract, if no other account has called it. The call moves the service escrow to the refund manager, and the refund manager emits RefundDistributionCalculated. NoPaymentToRefund means that another account already processed the E3.

Claim the refund

Call claimRequesterRefund(e3Id) on the E3RefundManager from the requester address. The contract pays the refund in the fee token that was frozen for the E3. It emits RefundClaimed.

Use the refund manager that was current when you made the request. e3RefundManager() on the Interfold contract returns the current one. getRefundDistribution(e3Id) returns the calculated split, and hasRequesterClaimed(e3Id, account) shows whether you already claimed. The refund manager has no claim deadline. The claim reverts with RefundNotCalculated, NotRequester, AlreadyClaimed, or NoRefundAvailable when it cannot pay.

Choose a committee size and parameter set

The committee size is an enum. Each size fixes N, H, and T in lib/ActiveCryptoConfig.sol. You cannot choose other values.

SizeEnum valueN (members)H (honest count)T (threshold)Shares to decrypt (T + 1)
Minimum03212
Micro19545
Small21914910

The committee stays viable while at least H members stay active. Decryption needs T + 1 shares.

The parameter set selects the BFV parameters. The SDK preset must match it.

paramSetSDK preset nameRing degreeUse
0INSECURE_THRESHOLD_6464Tests only. It has no production security.
2SECURE_THRESHOLD_81928192Production.

Each network accepts different pairs:

NetworkParameter setsCommittee sizes
Ethereum mainnet2 onlySmall only. The launch pricing sets minCommitteeSize to 19.
Sepolia, local chains (31337 and 1337)0 and 2All three sizes, when the deployment configures their thresholds.

A parameter set must also be registered on the chain. paramSetRegistry(paramSet) returns empty bytes for an unregistered set. The local deploy script registers the set of the active circuit build (set 0 in the checked-in configuration). With mock verifiers, it configures thresholds for all three sizes. With ENABLE_ZK_VERIFICATION=true, it configures thresholds only for the committee of the active circuit build, because its verifiers check only that committee. Mainnet retains index 1 for older E3s; version-7 requests use index 2.

Use these rules to choose:

  • Choose paramSet 2 for any value that must stay private.
  • Choose a larger committee for more fault tolerance. It costs more.
  • Make sure that the network has enough eligible ciphernodes and bond owners. The request reverts when fewer than N are available.
  • Call getE3Quote to test a pair before you request. It reverts for a pair that the chain does not accept.

Checklist

Before each request:

  • Confirm that requestsPaused() returns false.
  • Confirm that e3Programs(program) returns true.
  • Confirm that the chain accepts your committee size and parameter set.
  • Set the SDK preset to match paramSet.
  • Set the input window start a few seconds after the current block time.
  • Set the input window end after the worst-case key publication time.
  • Get the fee with getE3Quote.
  • Approve exactly that amount for the Interfold contract.
  • Set maxFee to the quoted amount.

The worst-case key publication time is the request time plus the randomness timeout, the sortition submission window, and the DKG window. On mainnet, that sum is 25,800 seconds.

After the request:

  • Watch E3StageChanged and E3Failed for your E3 ID.
  • Publish the ciphertext output before the compute deadline.
  • If the E3 fails, process the failure and claim the refund from the requester address.

Next steps