Skip to content

Fulfillment Proof

import { Badge, Card } from ‘@astrojs/starlight/components’

Proves a solver correctly executed a swap **without revealing the exact amount or transaction path**. Verifies delivery to the correct stealth address and that output meets minimum requirements.

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)
}
sequenceDiagram
    participant S as Solver
    participant Chain as Blockchain
    participant P as Protocol

    Note over S: Accepts intent<br/>min_output = 100 ZEC

    S->>Chain: Execute swap
    Chain-->>S: Delivered 105 ZEC

    S->>S: Create commitment<br/>C = Pedersen(105, blinding)
    S->>S: Generate fulfillment proof
    Note right of S: Public: intent_id, C, min=100<br/>Private: amount=105, blinding

    S->>P: Submit proof
    P->>P: Verify proof
    P-->>S: Confirmed: "Delivered >= 100 ZEC"
PropertyGuarantee
SoundnessCannot claim false fulfillment
Zero-knowledgeExact amount hidden
BindingCannot change claimed delivery
sequenceDiagram
    participant U as User Intent
    participant S as Solver
    participant P as Protocol

    U->>S: Submit intent
    S->>S: Execute swap
    S->>S: Generate proof
    S->>P: Fulfillment + Proof
    P->>P: Verify
    P-->>S: Verified
    S-->>U: Settlement complete
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