Skip to main content
This guide walks you through using the Stoffel CLI’s Solidity templates to build on-chain coordinated MPC applications.

Choosing a Template

Stoffel provides two Solidity templates:
TemplateFrameworkBest For
solidity-foundryFoundryRust developers, CI/CD pipelines, fast compilation
solidity-hardhatHardhatJavaScript/TypeScript developers, existing Hardhat workflows
Both templates generate identical contract code - choose based on your team’s preferred tooling.

Creating a Project

Generated Project Structure

Foundry Template

Hardhat Template

Understanding MyMPCApp.sol

The generated MyMPCApp.sol extends StoffelCoordinator and requires you to implement 4 abstract methods that control the MPC lifecycle.

The 4 Required Methods

Implementing Each Method

1. startPreprocessing()

Called by the designated party to initialize the preprocessing phase.
You MUST call initialzeInputMaskBuffer() during preprocessing. Without this, clients cannot reserve input masks and submit inputs.

2. gatherInputs()

Transitions the contract to accept client inputs.
After this method executes, clients can:
  1. Call reserveInputMask(index) to reserve a slot
  2. Request their input mask from MPC nodes off-chain
  3. Call submitMaskedInput(maskedInput, reservedIndex) to submit

3. initiateMPCComputation()

Triggers the off-chain MPC computation.
MPC nodes listen for the MPCComputationInitiated event to begin the off-chain computation. Ensure your event includes all necessary context.

4. publishOutputs()

Called after the MPC computation completes to publish results.

Complete Implementation Example

Here’s a complete example for a secure voting application:

Testing Your Contract

Foundry Tests

Example test file (test/MyMPCApp.t.sol):

Hardhat Tests

Deployment

Foundry Deployment

Hardhat Deployment

End-to-End Workflow

Here’s the complete flow for running an MPC computation:

Handling Optional Public State

When clients submit masked inputs via submitMaskedInput, your application may also need to track associated public state - data that doesn’t need privacy protection but is logically tied to the input.
This pattern is optional. Many applications only need the masked input itself and can skip this section entirely.

When You Need Public State

Use CasePublic State Example
VotingVoter’s preferred language for result notifications
AuctionBidder’s display name (not the bid amount)
SurveyRespondent’s demographic category
ComputationInput metadata (timestamp, format version)

When You Don’t Need Public State

  • Simple computations where only the masked value matters
  • Applications where all metadata is handled off-chain
  • Minimal contracts that only need MPC results

Implementation Pattern

Create a wrapper function that calls submitMaskedInput and stores additional public metadata:
Public state is stored on-chain and visible to everyone. Only use it for non-sensitive metadata. The actual secret input remains protected by the masking mechanism.

Example: Voting with Voter Preferences

Next Steps