Skip to content

feat(pricing): add CoinPaprika pricing implementation#413

Open
donbagger wants to merge 2 commits into
openintentsframework:mainfrom
donbagger:feat/coinpaprika-pricing
Open

feat(pricing): add CoinPaprika pricing implementation#413
donbagger wants to merge 2 commits into
openintentsframework:mainfrom
donbagger:feat/coinpaprika-pricing

Conversation

@donbagger

@donbagger donbagger commented Jul 2, 2026

Copy link
Copy Markdown

Summary

Adds a CoinPaprika-backed PricingInterface implementation alongside the existing CoinGecko and DefiLlama sources, registered as "coinpaprika".

Why CoinPaprika: the ticker API is free with no API key and no sign-up, which makes it a practical primary or fallback feed for permissionless solver operators - one more independent source to chain in PricingService fallbacks. An optional api_key switches to the api-pro tier (higher limits) automatically.

Design notes:

  • Mirrors coingecko.rs one-to-one so the shape is familiar: TTL price cache + short negative cache, in-flight fetch deduplication, schedule-based rate limiter with a bounded sleep cap, request timeout, custom_prices, and a token_id_map override.
  • CoinPaprika ids are {symbol}-{name} shaped, so the source carries its own COINPAPRIKA_TOKEN_MAPPINGS (ETH -> eth-ethereum, USDC -> usdc-usd-coin, including a real WETH id) instead of reusing the CoinGecko-shaped DEFAULT_TOKEN_MAPPINGS.
  • USD-only parity with the existing sources is kept (non-USD requests return PriceNotAvailable, same as CoinGecko).
  • The ticker endpoint is per-coin (GET /v1/tickers/{coin_id}?quotes=USD), which matches how get_price already fetches - one id per call.
  • Helpers are self-contained in the file rather than factored into shared infra, following the existing convention (defillama.rs does the same). Happy to extract shared plumbing in a follow-up if you'd prefer.

I work on developer relations for CoinPaprika, so flagging that interest openly. The implementation only touches the pricing crate and adds no default behavior change - nothing selects it unless configured.

Testing Process

  • cargo fmt --check, cargo clippy -p solver-pricing --all-targets -- -D warnings, cargo build -p solver-pricing all clean
  • cargo test -p solver-pricing: 122 passed, 0 failed (30 new tests, all offline via wiremock local servers - same-asset conversion, unsupported pairs, custom base_url retrieval, non-USD rejection, unknown token, invalid amounts, cache TTL and negative cache, in-flight dedup, rate-limit sleep cap, timeout bounds, api-pro key routing)
  • Verified end-to-end against the live API with the default config before opening this PR: convert_asset("ETH","USD","1.0") -> 1642.13, wei_to_currency("1000000000000000000","USD") -> 1642.13, currency_to_wei("3000","USD") -> 1826895156733445020, and ETH/SOL correctly rejected as non-USD

Checklist

  • Add a reference to related issues in the PR description. (No existing issue - this adds a new pricing source; happy to open one if you track features that way.)
  • Add unit tests if applicable.

Summary by CodeRabbit

  • New Features
    • Added a new CoinPaprika-based pricing provider using real-time USD quotes.
    • Enabled custom fixed per-token prices and enhanced conversion support (USD-based and wei-to-fiat via ETH/USD).
    • Included caching and concurrent request sharing to reduce redundant upstream requests.
  • Bug Fixes
    • Improved behavior for unsupported pairs, unavailable conversions, and failure/timeout handling (including safer wait behavior).
  • Tests
    • Added extensive coverage for configuration validation, caching/deduplication, timeouts, and conversion edge cases.
  • Chores
    • Registered the new provider so it appears in the available implementations list.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d73b7b70-b91e-4a75-8c84-adcbf68db088

📥 Commits

Reviewing files that changed from the base of the PR and between ea26106 and ad6ab36.

📒 Files selected for processing (1)
  • crates/solver-pricing/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/solver-pricing/src/lib.rs

📝 Walkthrough

Walkthrough

This PR adds a CoinPaprika pricing provider with HTTP price fetching, caching, rate limiting, USD-only conversion rules, config validation, registry wiring, and tests. The solver-pricing library now exports and registers the provider.

Changes

CoinPaprika Pricing Provider

Layer / File(s) Summary
Core types and shared utilities
crates/solver-pricing/src/implementations/coinpaprika.rs
Adds token-symbol to coin-ID mapping constants, ticker response parsing types, time helpers, and an error-cloning helper.
Pricing logic, caching, rate limiting, dedup
crates/solver-pricing/src/implementations/coinpaprika.rs
Implements CoinPaprikaPricing::new, rate limiting, cached price lookup with fresh/negative caching, per-key in-flight deduplication, HTTP ticker fetching with timeout, and get_price/get_pair_price with custom-price and USD-inversion handling.
PricingInterface implementation and wei conversion
crates/solver-pricing/src/implementations/coinpaprika.rs
Implements PricingInterface including supported-pair enumeration, asset conversion, and wei/USD/Ether conversion using ETH as a bridge.
Config schema validation and registry wiring
crates/solver-pricing/src/implementations/coinpaprika.rs
Adds CoinPaprikaConfigSchema validation for all config fields, CoinPaprikaPricingRegistry, and the create_coinpaprika_pricing factory.
Tests and library registration
crates/solver-pricing/src/implementations/coinpaprika.rs, crates/solver-pricing/src/lib.rs
Adds tests covering config, pricing logic, caching, dedup, rate limiting, and timeouts; exports the coinpaprika module and registers CoinPaprikaPricingRegistry in get_all_implementations(), updating the related count assertion.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant CoinPaprikaPricing
  participant Cache
  participant CoinPaprikaAPI

  Caller->>CoinPaprikaPricing: get_pair_price(base, quote)
  CoinPaprikaPricing->>Cache: get_cached_price_if_fresh(key)
  alt cache hit
    Cache-->>CoinPaprikaPricing: cached price
  else cache miss
    CoinPaprikaPricing->>CoinPaprikaPricing: apply_rate_limit()
    CoinPaprikaPricing->>CoinPaprikaAPI: fetch ticker (with timeout)
    CoinPaprikaAPI-->>CoinPaprikaPricing: price or error
    CoinPaprikaPricing->>Cache: write success/failure result
  end
  CoinPaprikaPricing-->>Caller: price or PriceNotAvailable
Loading

Possibly related PRs

  • openintentsframework/oif-solver#278: Also changes crates/solver-pricing/src/lib.rs implementation registration by adding a new pricing provider to get_all_implementations().

Suggested reviewers: shahnami, pepebndc, NicoMolinaOZ

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly states the main change: adding a CoinPaprika pricing implementation.
Description check ✅ Passed The PR description matches the required template and includes summary, testing, and checklist items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nahimterrazas nahimterrazas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contributions @donbagger!

Approving it.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.04268% with 95 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../solver-pricing/src/implementations/coinpaprika.rs 88.9% 95 Missing ⚠️

📢 Thoughts on this report? Let us know!

@nahimterrazas

Copy link
Copy Markdown
Collaborator

@donbagger, Commits must have verified signatures to merge the PR. Please rebase your commits so we can merge it. Thanks!

Add a CoinPaprika-backed PricingInterface implementation alongside the
existing CoinGecko and DefiLlama sources. CoinPaprika's ticker API is free
with no API key required, which makes it a practical primary or fallback
feed for permissionless solvers.

The implementation mirrors the CoinGecko source one-to-one: TTL price cache
plus short negative cache, in-flight fetch deduplication, schedule-based
rate limiting with a bounded sleep cap, request timeouts, custom price
overrides, and a token id map override. USD-only parity with the existing
sources is kept. An optional api_key switches the base URL to the
api-pro tier.

Registered as "coinpaprika" in get_all_implementations, with a 30-test
offline suite (wiremock) matching the conventions of the existing
implementations.
@donbagger donbagger force-pushed the feat/coinpaprika-pricing branch from fa46864 to ea26106 Compare July 8, 2026 08:12
@donbagger

Copy link
Copy Markdown
Author

Done! Rebased onto latest main as a single signed commit (ea26106, signature shows verified). The tree is byte-identical to the previously green CI state, so it should go clean. Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants