Skip to content

Fulfillment Proof

The Fulfillment Proof demonstrates that a solver correctly executed a swap without revealing transaction details.

After fulfilling an intent, the solver must prove:

“I delivered at least X tokens to the correct recipient” without revealing “exact amount or transaction path”

InputVisibilityDescription
intent_idPublicIntent being fulfilled
output_commitmentPublicCommitment to output amount
min_outputPublicMinimum required output
recipient_stealthPublicStealth address for delivery
output_amountPrivateActual delivered amount
output_blindingPrivateCommitment randomness
tx_proofPrivateProof of on-chain execution
  1. Minimum Met: output_amount >= min_output
  2. Commitment Valid: Pedersen(output_amount, blinding) = output_commitment
  3. Delivery Verified: Transaction sent to recipient_stealth
use dep::std::hash::pedersen_hash;
fn main(
// Public inputs
intent_id: pub Field,
output_commitment: pub Field,
min_output: pub u64,
recipient_stealth: pub Field,
// Private inputs
output_amount: u64,
output_blinding: Field,
tx_hash: Field,
tx_recipient: Field,
) {
// Constraint 1: Minimum output met
assert(output_amount >= min_output);
// Constraint 2: Commitment correctness
let computed = pedersen_hash([
output_amount as Field,
output_blinding
]);
assert(computed == output_commitment);
// Constraint 3: Correct recipient
assert(tx_recipient == recipient_stealth);
// Binding: tx_hash commits to execution
// (verified on-chain separately)
}
1. Solver accepts intent with min_output=100 ZEC
2. Solver executes swap, delivers 105 ZEC
3. Solver creates output commitment: C = Pedersen(105, blinding)
4. Solver generates fulfillment proof:
- Public: intent_id, C, min=100, stealth_addr
- Private: amount=105, blinding, tx_hash
5. Protocol verifies: "Solver delivered at least 100 ZEC"
PropertyGuarantee
SoundnessCannot claim false fulfillment
Zero-knowledgeExact amount hidden
BindingCannot change claimed delivery
User Intent Solver Protocol
│ │ │
├──────Submit───────────►│ │
│ │ │
│ Execute swap │
│ │ │
│ Generate proof │
│ │ │
│ ├──────Fulfillment────────►│
│ │ + Proof │
│ │ │
│ │◄─────Verified────────────┤
│ │ │
│◄────Settlement─────────┤ │
import { MockProofProvider, FulfillmentProofParams } from '@sip-protocol/sdk'
const proofProvider = new MockProofProvider()
const params: FulfillmentProofParams = {
intentId: '0x...',
outputCommitment: '0x...',
minOutput: 100n,
recipientStealth: '0x...',
outputAmount: 105n,
outputBlinding: '0x...',
txHash: '0x...'
}
const result = await proofProvider.generateFulfillmentProof(params)
interface FulfillmentProof {
proof: HexString
publicInputs: {
intentId: Field
outputCommitment: Field
minOutput: u64
recipientStealth: Field
}
framework: 'noir' | 'mock'
timestamp: number
}

For cross-chain verification, an oracle may attest to delivery:

interface OracleAttestation {
intentId: string
chainId: string
txHash: string
recipient: string
amount: bigint
timestamp: number
oracleSignature: string
}
CaseHandling
Partial fillMultiple proofs for partial
OverpaymentValid (exceeds minimum)
Wrong recipientProof verification fails
Failed txNo proof generated
MetricMockNoir (estimated)
Proof generation<1ms2-4s
Proof size64 bytes~200 bytes
Verification<1ms~10ms