Skip to main content

Overview

LocalProver handles proving of intents that are fulfilled on the same chain where they were created. It provides a unique flash-fulfill capability that atomically withdraws rewards, executes fulfillment, and pays the solver. Contract: contracts/prover/LocalProver.sol Inheritance: ILocalProver, Semver, ReentrancyGuard Proof Type: "Same chain"
LocalProver is designed for same-chain intents and does not require cross-chain messaging. Proofs are created immediately upon fulfillment.

Constructor

Initializes the LocalProver contract.
address
required
Address of the Portal contract (provides IntentSource + Inbox functionality)
Errors:
  • ChainIdTooLarge(uint256): Current chain ID exceeds uint64.max
Location: contracts/prover/LocalProver.sol:43

State Variables

_PORTAL

Address of the Portal contract. Immutable to prevent unauthorized changes.

_CHAIN_ID

Current chain ID stored as uint64.

_flashFulfillInProgress

Tracks which intent is currently being flash-fulfilled. Used to enable withdrawal during flashFulfill execution (before Portal.claimants is set). Only one flashFulfill can execute at a time due to nonReentrant modifier.

Core Functions

prove

No-op function for same-chain proving. Proofs are created immediately upon fulfillment, so this function does nothing.
This function is payable for compatibility but does not use ETH. Any ETH sent to this function will remain in the contract and be distributed to the next flashFulfill caller as part of their reward. Do not send ETH to this function.
Behavior:
  • Intentionally empty (no-op)
  • Does not revert to allow usage with fulfillAndProve
Location: contracts/prover/LocalProver.sol:115

provenIntents

Returns proof data for a given intent hash. For same-chain intents, proofs are created immediately upon fulfillment.
bytes32
required
Hash of the intent to query
Returns: ProofData struct with:
  • claimant (address): Address eligible for rewards
  • destination (uint64): Chain ID (_CHAIN_ID)
Behavior (4 cases):
  1. Griefing Protection: If Portal.claimants contains LocalProver address (without using flashFulfill)
    • Returns ProofData(address(0), 0) to treat intent as unfulfilled
    • Allows refunds after deadline
  2. Intent Fulfilled: If Portal.claimants contains valid solver address
    • Validates address is valid EVM address
    • Returns ProofData(solver, _CHAIN_ID)
    • If invalid EVM address, returns ProofData(address(0), 0) for griefing protection
  3. Flash Fulfill In Progress: If _flashFulfillInProgress == intentHash
    • Returns ProofData(address(this), _CHAIN_ID)
    • Enables withdrawal to LocalProver during atomic execution
  4. Intent Not Fulfilled:
    • Returns ProofData(address(0), 0)
Location: contracts/prover/LocalProver.sol:65

flashFulfill

Atomically fulfills an intent and pays claimant with remaining funds. This is the primary function for same-chain intent fulfillment.
Route
required
Route information for the intent execution
Reward
required
Reward details for the intent
bytes32
required
Address of the claimant eligible for rewards (receives immediate payout)
Returns: bytes[] - Results from the fulfill execution Execution Flow:
  1. CHECKS:
    • Validates claimant is not zero
    • Validates claimant is not LocalProver address
    • Computes intentHash from route and reward
  2. EFFECTS:
    • Sets _flashFulfillInProgress = intentHash
  3. INTERACTIONS:
    • Withdraws reward from vault to LocalProver
    • Approves Portal to spend route tokens
    • Calls Portal.fulfill with entire contract balance
    • Portal records actual claimant (not LocalProver)
  4. EFFECTS (Cleanup):
    • Transfers all remaining reward tokens to claimant
    • Transfers all remaining native ETH to claimant
    • Emits FlashFulfilled event
Claimant Receives:
  • All ERC20 tokens in reward.tokens (minus any consumed by route.tokens)
  • All native ETH from reward.nativeAmount (minus consumed by route.nativeAmount)
  • Plus any msg.value sent by caller
Errors:
  • InvalidClaimant(): Claimant is zero or LocalProver address
  • NativeTransferFailed(): Native token transfer to claimant failed
Security:
  • Uses nonReentrant modifier to prevent reentrancy attacks
  • Follows checks-effects-interactions pattern
Front-Running Risk: This function is permissionless and subject to front-running. Any solver can call this function for any intent and specify themselves as the claimant. Solvers should use private transaction pools (e.g., Flashbots) or coordinate off-chain with intent creators to mitigate front-running risks. This is standard MEV behavior in intent-based systems.
Location: contracts/prover/LocalProver.sol:170

challengeIntentProof

No-op function for same-chain intents. Same-chain intents cannot be challenged. Behavior:
  • Intentionally empty (no-op)
Location: contracts/prover/LocalProver.sol:131

getProofType

Returns: "Same chain" Location: contracts/prover/LocalProver.sol:104

receive

Allows contract to receive native tokens. Required for vault withdrawals that include native rewards. Location: contracts/prover/LocalProver.sol:242

Events

FlashFulfilled

Emitted when an intent is successfully flash-fulfilled.
bytes32
Hash of the fulfilled intent
bytes32
Address that received the rewards
uint256
Amount of native tokens transferred to claimant

Errors

InvalidClaimant

Thrown when claimant is zero address or LocalProver address.

NativeTransferFailed

Thrown when native token transfer to claimant fails.

ChainIdTooLarge

Thrown when current chain ID exceeds uint64.max.

Usage Example

Flash Fulfill an Intent

Check Proof Status

Griefing Protection

LocalProver includes protection against griefing attacks:
  1. LocalProver as Claimant: If someone calls Portal.fulfill with LocalProver as claimant (without using flashFulfill), provenIntents returns address(0) to treat the intent as unfulfilled.
  2. Invalid EVM Address: If Portal.claimants contains a non-EVM bytes32 value, provenIntents returns address(0) to allow refunds.
These protections ensure intent creators can always get refunds after deadline if something goes wrong.

Flash Fulfill Atomicity

The flash fulfill mechanism provides atomic execution:
  1. Withdraw rewards from vault → LocalProver
  2. Approve Portal to spend route tokens
  3. Call Portal.fulfill (which executes route steps)
  4. Transfer remaining rewards → claimant
All in a single transaction. If any step fails, entire transaction reverts.

Reentrancy Protection

The nonReentrant modifier prevents:
  • Multiple simultaneous flash fulfills
  • Cross-intent reentrancy attacks
  • State manipulation during execution
Only one flashFulfill can execute at a time.