Skip to content

bleu/cow-programmatic-orders-indexer

Repository files navigation

ComposableCoW Signature Decoder PoC

A proof of concept demonstrating how to match CoW Protocol order UIDs with ComposableCoW conditional orders by decoding the order signature.

Overview

This project shows how to link orders from the CoW Protocol API back to their originating ConditionalOrderCreated events by decoding the EIP-1271 signature. This approach works for any ComposableCoW order type (Perpetual Swaps, TWAP, etc.) and doesn't require on-chain calls.

The challenge with programmatic orders is that the order details are computed dynamically by a handler contract. The order UID alone doesn't reveal which conditional order created it. However, the signature contains all the information needed to trace back to the original conditional order.

How Signature Decoding Works

When a ComposableCoW order is submitted to CoW Protocol, it uses EIP-1271 signature verification. For Safe wallets, the signature follows a specific structure that embeds the ComposableCoW payload.

Signature Structure

┌─────────────────────────────────────────────────────────────────┐
│ Safe Signature                                                   │
│ selector: safeSignature(bytes32,bytes32,bytes,bytes)            │
├─────────────────────────────────────────────────────────────────┤
│ ├── domainSeparator (bytes32)                                   │
│ ├── typeHash (bytes32)                                          │
│ ├── encodeData (bytes)                                          │
│ └── payload (bytes) ◄─── Contains ComposableCoW data            │
│     ├── proof (bytes32[])    - Merkle proof (if using root)     │
│     ├── params (tuple)                                          │
│     │   ├── handler (address)  - e.g., PerpetualSwap handler    │
│     │   ├── salt (bytes32)                                      │
│     │   └── staticInput (bytes) - Handler-specific parameters   │
│     └── offchainInput (bytes)                                   │
└─────────────────────────────────────────────────────────────────┘

Matching Flow

1. ConditionalOrderCreated event
   ├── Compute hash = keccak256(abi.encode(handler, salt, staticInput))
   └── Store: owner, handler, salt, staticInput, hash

2. Order from CoW Protocol API
   ├── Check if signature starts with safeSignature selector
   ├── Decode Safe signature to extract payload
   ├── Decode payload to get ComposableCoW params
   ├── Compute hash = keccak256(abi.encode(params))
   └── Match hash with indexed conditional orders

Key Steps

  1. Index conditional orders: When a ConditionalOrderCreated event is emitted, compute and store the hash of (handler, salt, staticInput).

  2. Decode the signature: Extract the function selector to identify Safe signatures, then decode the ABI-encoded parameters.

  3. Extract the payload: The fourth parameter of safeSignature contains the ComposableCoW payload with proof and order params.

  4. Hash and match: Compute the same hash from the decoded params and match against indexed conditional orders.

Code Walkthrough

Signature Decoding Functions

// 1. Check if signature uses Safe's safeSignature format
function getSignatureSelectorAndData(signature: Hex) {
  const selector = signature.slice(0, 10);
  const isSafe = selector === SAFE_SIGNATURE_SELECTOR;
  return { selector, data, isSafe };
}

// 2. Decode Safe signature to extract components
function decodeSafeSignatureData(signatureData: Hex) {
  // Returns: domainSeparator, typeHash, encodeData, payload
  return decodeAbiParameters([...], signatureData);
}

// 3. Decode ComposableCoW payload and hash the params
function hashComposableCoWPayload(payload: Hex) {
  // Decode: { proof, params: { handler, salt, staticInput }, offchainInput }
  // Return: keccak256(abi.encode(params))
}

Architecture

Built with Ponder, an event indexing framework, the application:

  • Listens to ComposableCoW:ConditionalOrderCreated events
  • Computes and stores the conditional order hash
  • Decodes signatures from order examples to match them back to events
  • Exposes GraphQL and SQL APIs for querying matched orders

Contract Addresses (Ethereum Mainnet)

Contract Address
ComposableCoW 0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74
Perpetual Swap Handler 0x519ba24e959e33b3b6220ca98bd353d8c2d89920

Getting Started

Prerequisites

  • Node.js >= 18.14
  • An Ethereum mainnet RPC URL

Installation

pnpm install

Configuration

Set your RPC URL in the environment:

export MAINNET_RPC_URL="https://your-rpc-url"

Running

Development mode with hot reload:

pnpm dev

Production mode:

pnpm start

API Endpoints

  • GraphQL: http://localhost:42069/graphql
  • SQL: http://localhost:42069/sql

Database Schema

conditionalOrder

Stores all conditional orders indexed from ComposableCoW.

Field Type Description
id text Event ID (primary key)
owner text Order owner address
handler text Handler contract address
salt text Order salt
staticInput text Static input for the handler
hash text keccak256 hash of (handler, salt, staticInput)
txHash text Transaction hash of the creation event

orders

Links CoW Protocol orders to their corresponding conditional orders.

Field Type Description
orderUid text The CoW Protocol order UID (primary key)
conditionalOrderId text Reference to conditional order

Limitations

This is a proof of concept with the following limitations:

  • Uses a hardcoded order example for demonstration purposes
  • Only handles Safe wallet signatures (safeSignature selector)
  • Only indexes a specific block range on mainnet

Why This Approach?

For programmatic orders where on-chain parameters affect the final order (like oracle prices), you cannot simply reconstruct the order UID from stored data. The signature, however, contains:

  1. The exact conditional order params used to create the order
  2. Merkle proofs (for orders using merkle roots)
  3. Off-chain inputs provided at execution time

By decoding the signature, we can trace any ComposableCoW order back to its origin without requiring on-chain calls or storing execution-time data.

Dependencies

  • ponder - Blockchain event indexing framework
  • viem - Ethereum client library (ABI encoding/decoding)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published