Skip to content

feat: add DexPaprika tool node (keyless DEX market data)#6639

Open
donbagger wants to merge 1 commit into
FlowiseAI:mainfrom
donbagger:feature/dexpaprika-tool
Open

feat: add DexPaprika tool node (keyless DEX market data)#6639
donbagger wants to merge 1 commit into
FlowiseAI:mainfrom
donbagger:feature/dexpaprika-tool

Conversation

@donbagger

Copy link
Copy Markdown

What this adds

A new tool node under packages/components/nodes/tools/DexPaprika/ that gives agents onchain DEX market data from the DexPaprika API: 36 blockchain networks, 33M+ tokens, 36M+ pools.

The node needs no credential. The API is free and keyless, so this is one of the few tool nodes in the catalog you can drop on the canvas and use immediately, with zero configuration. If no actions are selected, all three are enabled.

Three actions, each a separate structured tool for the agent:

Tool What it does
dexpaprika_get_token_price Current USD price plus market stats (FDV, liquidity, 24h volume/txns) for a token by contract address
dexpaprika_search_pools Pools on a network ordered by volume/liquidity/txns/price change, optional filter by token address
dexpaprika_get_pool_ohlcv Historical OHLCV candles for a pool (1m to 24h intervals), the keyless way to get DEX price history

Follows the existing multi-action tool pattern (Gmail/Teams style: core.ts with tool classes extending DynamicStructuredTool from OpenAPIToolkit/core, plus a factory), minus the credential handling since there is none.

Why

Crypto agent flows currently need an API key signup for basically every market data tool node. DexPaprika is keyless and free, which makes it a good fit for tutorials, demos and production flows alike. Disclosure: I do DevRel for CoinPaprika/DexPaprika. Happy to keep this node updated as the API evolves.

How I tested it

Co-located unit tests in DexPaprika.test.ts (node init, action filtering, URL building, description stripping, error path, fetch mocked), following the pattern from JSONPathExtractor.test.ts:

$ jest nodes/tools/DexPaprika/DexPaprika.test.ts
Test Suites: 1 passed, 1 total
Tests:       8 passed, 8 total

Lint and build:

$ eslint packages/components/nodes/tools/DexPaprika --ext ts --report-unused-disable-directives --max-warnings 0   # clean
$ cd packages/components && tsc && gulp   # full package typecheck passes, icon lands in dist/nodes/tools/DexPaprika/

I also loaded the compiled node from dist and exercised all three tools through the real tool.call() path against the live API (schema parsing and zod defaults included):

node: DexPaprika | name: dexPaprika | category: Tools | credential: NONE
tools: dexpaprika_get_token_price, dexpaprika_search_pools, dexpaprika_get_pool_ohlcv
LIVE price_usd WETH: 1836.2492440639253 | description stripped: true
LIVE solana pools: PumpSwap 65XqK2yo | Orca Czfq3xZZ | has_next_page: true
LIVE ohlcv candles: 2 | first: {"time_open":"2026-07-15T00:00:00Z",...,"close":1.0002454761710518,"volume":304537032}
schema rejects bad interval OK: Received tool input did not match expected schema

Every endpoint the node calls was verified live against the real API before writing the schemas. The order_by enum, interval enum and limit bounds in the zod schemas are taken from the API's own validation errors, not guessed:

$ curl "https://api.dexpaprika.com/networks/ethereum/pools/search?limit=2&order_by=volume_usd"
{"message":"invalid query parameters: order_by (must be one of [volume_usd_24h volume_usd_7d volume_usd_30d liquidity_usd txns_24h created_at price_usd price_change_percentage_24h])"}

Real response per action:

Token price (/networks/{network}/tokens/{address}):

$ curl "https://api.dexpaprika.com/networks/ethereum/tokens/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
{"id":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","name":"Wrapped Ether","symbol":"WETH","chain":"ethereum","decimals":18,...,"summary":{"price_usd":1840.53,"fdv":4456195578.07,"liquidity_usd":535660889.17,"pools":4687,"24h":{"volume_usd":243032507.73,"txns":153141,...}}}

The tool strips the description field from this response (a multi-paragraph project writeup) so it does not waste agent context.

Pools search (/networks/{network}/pools/search):

$ curl "https://api.dexpaprika.com/networks/ethereum/pools/search?limit=2&order_by=volume_usd_24h&sort=desc"
{"results":[{"id":"0xf6e72db5454dd049d0788e411b06cfaf16853042","dex_id":"makerdao","dex_name":"MakerDAO","chain":"ethereum","volume_usd_24h":882436768.63,"transactions_24h":2969,"price_usd":1.0004,...}],"has_next_page":true,"next_cursor":"..."}

One design note: I tested a free-text query param on this endpoint and the API silently ignores it (the echoed query object in the response does not even include it), so the tool intentionally does not expose one. The token_address filter is exposed instead, verified working.

Pool OHLCV (/networks/{network}/pools/{pool}/ohlcv):

$ curl "https://api.dexpaprika.com/networks/ethereum/pools/0xf6e72db5454dd049d0788e411b06cfaf16853042/ohlcv?start=2026-07-10&interval=1h&limit=2"
[{"time_open":"2026-07-10T00:00:00Z","time_close":"2026-07-10T01:00:00Z","open":1.0000375,"high":1.0005282,"low":0.9998023,"close":1.0004293,"volume":8662667},...]

Also verified the Solana path (non-hex mint addresses):

$ curl "https://api.dexpaprika.com/networks/solana/tokens/So11111111111111111111111111111111111111112"
{"id":"So11111111111111111111111111111111111111112","name":"Wrapped SOL","symbol":"SOL","chain":"solana","decimals":9,...}

Test limits, stated honestly: I ran the full pnpm build locally on node 23.10 (CI uses 24.15). Every TypeScript compile step passed with zero errors across all packages, including the server compiling against the changed components package. The one local failure was the server's gulp email-template copy step, which is a node 23 type-stripping interop quirk when gulp loads gulpfile.ts (SyntaxError: The requested module 'gulp' does not provide an export named 'dest'), unrelated to this change (main's Node CI on node 24 is green as of the commit this branch is based on). I did not run the Cypress e2e suite locally. The repo's pre-commit hooks (pretty-quick and lint-staged) ran and passed on commit.

Icon

dexpaprika.svg is the official DexPaprika brand symbol (2.5 KB, in line with other node icons in the folder).

Adds a new tool node under packages/components/nodes/tools/DexPaprika with
three agent tools backed by the free, keyless DexPaprika API:

- dexpaprika_get_token_price: token price and market stats by contract address
- dexpaprika_search_pools: pools on a network with ordering and token filter
- dexpaprika_get_pool_ohlcv: historical OHLCV candles for a pool

No credential input: the API needs no key, so the node works with zero
configuration. Follows the existing multi-action tool pattern (core.ts with
DynamicStructuredTool subclasses plus a factory). Co-located jest tests
included. All endpoint parameters and enums verified against the live API.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the DexPaprika tool integration, enabling agents to fetch on-chain DEX market data such as token prices, liquidity pools, and historical OHLCV candles across multiple blockchain networks. The implementation includes the tool definitions, core API request handling, unit tests, and an icon. Feedback on the changes highlights a potential runtime issue in GetTokenPriceTool where parsing an unexpected API response format could lead to a TypeError when deleting the description property; it is recommended to validate that the parsed response is a non-null object and throw an error for invalid formats to promote fail-fast behavior.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +96 to +100
try {
const parsed = JSON.parse(data)
// The long-form project description adds noise without market data value
delete parsed.description
return JSON.stringify(parsed)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If JSON.parse(data) returns null or a primitive value (e.g., if the API returns an unexpected response format), attempting to delete a property on it will throw a TypeError in strict mode. When handling potentially invalid data from external sources, we should prefer throwing an error for invalid input types rather than silently returning or bypassing the logic to promote fail-fast behavior. Additionally, use loose equality (== null) to check for nullish values.

        try {
            const parsed = JSON.parse(data)
            if (parsed == null || typeof parsed !== 'object') {
                throw new Error('Invalid response format: expected an object')
            }
            // The long-form project description adds noise without market data value
            delete parsed.description
            return JSON.stringify(parsed)
References
  1. When handling potentially invalid data from external sources (like an API response), prefer throwing an error for invalid input types rather than silently returning a default or empty value. This promotes fail-fast behavior.
  2. In JavaScript/TypeScript, use loose equality (== null) as a standard idiom for a 'nullish' check that covers both null and undefined.

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.

1 participant