Skip to content

sedaprotocol/seda-evm-fast-verification

Repository files navigation

SEDA Fast Verification

Solidity contract for verifying SEDA Fast API responses on-chain using secp256k1 signatures.

Overview

The FastVerifier contract allows smart contracts to verify that data returned by the SEDA Fast API was genuinely signed by SEDA's trusted execution environment. This enables low-latency oracle data consumption without waiting for full consensus.

Installation

# Clone
git clone https://github.com/sedaprotocol/seda-evm-fast-verification.git
cd seda-evm-fast-verification

# Install dependencies
forge install
npm install

Configuration

Copy the example environment file and configure:

cp .env.example .env

Required variables:

Variable Description
SEDA_FAST_SIGNER SEDA Fast API signer address
PRIVATE_KEY Deployer private key (for deployment)
BASE_SEPOLIA_RPC_URL RPC endpoint
BASESCAN_API_KEY For contract verification

Deriving Signer Address

Get the public key from the SEDA Fast API and derive the address:

# Get public key from SEDA Fast API
curl https://fast-api.seda.xyz/info | jq -r '.publicKey'

# Derive address
node -e "console.log(require('ethers').computeAddress('0x<public-key>'))"

Usage

Build

forge build

Test

forge test -vv

Deployment

Prerequisites

  1. Get testnet ETH for Base Sepolia from a faucet

  2. Get a Basescan API key from basescan.org/apis

  3. Configure .env:

    cp .env.example .env
    SEDA_FAST_SIGNER=0x593CEBb17C116D48d69b108711f2D8C419ed8758
    PRIVATE_KEY=0x...your-private-key...
    BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
    BASESCAN_API_KEY=your-api-key

Deploy to Base Sepolia

# Deploy and verify (reads PRIVATE_KEY from .env automatically)
forge script script/FastVerifier.s.sol:FastVerifierScript \
  --rpc-url base_sepolia \
  --broadcast \
  --verify \
  -vvvv

Deploy to Other Networks

Add the network to foundry.toml:

[rpc_endpoints]
base_sepolia = "${BASE_SEPOLIA_RPC_URL}"
base_mainnet = "${BASE_MAINNET_RPC_URL}"
arbitrum_sepolia = "${ARBITRUM_SEPOLIA_RPC_URL}"

[etherscan]
base_sepolia = { key = "${BASESCAN_API_KEY}", url = "https://api-sepolia.basescan.org/api" }
base_mainnet = { key = "${BASESCAN_API_KEY}", url = "https://api.basescan.org/api" }
arbitrum_sepolia = { key = "${ARBISCAN_API_KEY}", url = "https://api-sepolia.arbiscan.io/api" }

Then deploy:

forge script script/FastVerifier.s.sol:FastVerifierScript \
  --rpc-url <network_name> \
  --broadcast \
  --verify

Manual Verification

If automatic verification fails, verify manually:

forge verify-contract <DEPLOYED_ADDRESS> src/FastVerifier.sol:FastVerifier \
  --chain base-sepolia \
  --constructor-args $(cast abi-encode "constructor(address)" $SEDA_FAST_SIGNER) \
  --etherscan-api-key $BASESCAN_API_KEY

Dry Run (Simulation)

Test deployment without broadcasting:

forge script script/FastVerifier.s.sol:FastVerifierScript \
  --rpc-url base_sepolia \
  -vvvv

Verifying Fast API Responses

Use the verification script to test a deployed contract with a SEDA Fast API response.

Option 1: From a file

Save the Fast API response to a file and verify:

[...]
{
  "data": {
    "dataResult": {
      "drId": "b37491d3969dc300eb8313234c73fd695d83ff351f3d2ec8fda62c00d2c95b14",
      "gasUsed": "45768976025625",
      "blockHeight": "0",
      "blockTimestamp": "1767018307922",
      "consensus": true,
      "exitCode": 0,
      "version": "0.0.1",
      "result": "7b22...",
      "paybackAddress": "",
      "sedaPayload": ""
    },
    "signature": "c414c3de2b367c36..."
  }
}
[...]

# Verify against deployed contract
node scripts/verify.js <CONTRACT_ADDRESS> "$(cat response.json)"

Output

πŸ“‹ Verification Details:
  Contract: 0xbaa298897006f5707676354a6325930d368352a2
  DR ID: 0xb37491d3969dc300eb8313234c73fd695d83ff351f3d2ec8fda62c00d2c95b14
  Timestamp: 2025-12-29T14:25:07.922Z
  Consensus: true
  Exit Code: 0
  Expected Signer: 0x593CEBb17C116D48d69b108711f2D8C419ed8758

βœ… VALID signature

Contract Interface

interface IFastVerifier {
    /// @notice Verifies a SEDA Fast API response signature
    /// @param result The data result from the Fast API
    /// @param signature The secp256k1 signature (65 bytes)
    /// @return isValid True if signature is valid
    function verify(
        SedaDataTypes.Result calldata result,
        bytes calldata signature
    ) external view returns (bool isValid);

    /// @notice Verifies and returns the result data
    /// @dev Reverts if signature is invalid
    function verifyAndGetResult(
        SedaDataTypes.Result calldata result,
        bytes calldata signature
    ) external view returns (bytes memory);
}

Integration Example

import {FastVerifier} from "./FastVerifier.sol";
import {SedaDataTypes} from "@seda-protocol/evm/contracts/libraries/SedaDataTypes.sol";

contract MyContract {
    FastVerifier public verifier;

    constructor(address _verifier) {
        verifier = FastVerifier(_verifier);
    }

    function consumeOracleData(
        SedaDataTypes.Result calldata result,
        bytes calldata signature
    ) external {
        // Verify and get the result in one call
        bytes memory data = verifier.verifyAndGetResult(result, signature);
        
        // Decode and use the data
        // ...
    }
}

Data Result Structure

The SedaDataTypes.Result struct matches the SEDA Fast API response:

struct Result {
    bytes32 drId;           // Data Request ID
    uint128 gasUsed;        // Gas consumed
    uint64 blockHeight;     // Block height (0 for Fast API)
    uint64 blockTimestamp;  // Unix timestamp in milliseconds
    bool consensus;         // Consensus reached
    uint8 exitCode;         // Execution exit code
    string version;         // Protocol version ("0.0.1")
    bytes result;           // The actual result data
    bytes paybackAddress;   // Payback address (usually empty)
    bytes sedaPayload;      // SEDA payload (usually empty)
}

Security

  • The contract verifies signatures against a trusted signer address set at deployment
  • Uses OpenZeppelin's battle-tested ECDSA library
  • Handles both standard (v=27/28) and compact (v=0/1) signature formats

License

MIT

About

Example contract that does DataResult verification in Solidity for evm chains.

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors