# paraswap-dex-lib: adding a DEX to ParaSwap with a pull request

> DexLib is the TypeScript library where an exchange integration lives inside the ParaSwap aggregator's own backend, so supporting a new DEX means writing an adapter and opening a pull request. The integration model is event driven, deliberately avoiding repeated fullnode RPC calls, and the tooling expects a lot from the contributor.

**VeloraDEX/paraswap-dex-lib** — DexLib is a library used by ParaSwap backend to integrate with decentralized exchanges. This library enables external DEX developers to integrate their DEX with ParaSwap by creating pull requests to this repository.

- Repository: https://github.com/VeloraDEX/paraswap-dex-lib
- Stars: 810 · Forks: 390
- Language: TypeScript
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/veloradex-paraswap-dex-lib

## Integration means a pull request into someone else's backend

DexLib is a library used by the ParaSwap backend to integrate with decentralized exchanges, and it enables external DEX developers to integrate their DEX with ParaSwap by creating pull requests to the repository.

That sentence sets the terms of engagement. This is not a client library you install and configure, and it is not an API you register a webhook against. Your pricing logic ends up as code inside ParaSwap's own service, reviewed by their team, running inside their infrastructure.

For the DEX team the payoff is distribution and routing. ParaSwap's main router, known as Augustus, is described as needing only canonical, offchain hints for navigating swaps across different DEXs, and the design means that any liquidity source can be added without any contract change in most cases. In other words, integrating properly means your pools become reachable through the aggregator's routing rather than through a separate market.

The alternative, and the reason teams accept this arrangement, is that an out-of-band integration gets you much less. If your DEX only exposes an HTTP pricing endpoint, you are one more source that the aggregator may or may not call, with none of the state synchronisation that makes routing accurate.

The trade is clear: you give up ownership of the integration code and accept an external review cycle, and in exchange you get your liquidity inside a router that can route across it.

The repository is TypeScript, the default branch is master, and the last push was on 2026-10-19. There are no GitHub releases, so the package on npm is the reference point rather than a tag.

## Pricing from events and in-memory state, not from RPC calls

The walkthrough describes ParaSwap's pricing architecture in one paragraph, and it is the design your adapter has to fit into.

ParaSwap optimizes price serving through an event-based approach, bypassing the need for frequent fullnode RPC calls by utilizing smart contract events and in-memory state for pricing. This method, abstracted for ease of implementation, requires DEXs to initially fetch on-chain state, subscribe to updates via events, and use the updated in-memory state for efficient pricing.

So the contract with the aggregator is a state subscription. Your adapter loads the pool state once, keeps it current by listening for events, and answers price requests from memory. The alternative design, calling the chain for every quote, is exactly what this avoids, because RPC calls are the expensive part.

The rest of the walkthrough is a five step sequence, and the first three are documented in detail: initialising the pool state, keeping it in sync, and calculating rates for a token pair and specific amount ranges.

Step three is where the real work is, and the documentation is blunt about why. To ensure that you always provide correct pricing and rates when constructing a transaction, the best approach is to replicate the contract's behaviour and calculations. The excerpt is cut off mid-sentence at exactly the point where it warns about a mistake in the number manipulation, and that warning is the substance of the whole step: your adapter has to reproduce the pool's own arithmetic, including the rounding and the edge cases, or the prices it returns will not match what the transaction does.

## Step one: fetching initial state through a Multicall

There are two ways to initialise your pool state, and the documentation is clear about which one it prefers.

You can do it greedily, initialising when the backend services start, by overriding the initializePricing function in your DEX. Or you can do it lazily, initialising on receiving a first price request involving an asset your DEX can handle, as part of the getPricesVolume function. The latter is the most preferred option.

The lazy option is the better engineering choice as well as the documented one. A greedy initialisation has to walk every pool your DEX supports at startup, whether or not anyone trades that pair today, and on a large DEX that is a lot of chain calls for state nobody asked for. Lazy initialisation pays the cost only when there is a request that needs it.

The template code for the greedy path looks like this:

```ts
async initializePricing(blockNumber: number) {
    const poolState = await getOnChainState(
      this.dexHelper.multiContract,
      this.swETHAddress,
      this.swETHInterface,
      blockNumber,
    );

    await this.eventPool.initialize(blockNumber, {
      state: poolState,
    });
}
```

The example shows how the state of the swETH contract is obtained, in this case the swETHToEthRate, and the getOnChainState call is executing a Multicall contract call to the swETHAddress using the swETH ABI.

The Multicall detail is called out separately and matters for cost. When interacting with smart contracts on any blockchain, you should try to be mindful of the cost of RPC calls, thus the best approach is to use Multicall, and the Multicall contract can be accessed via this.dexHelper.multiContract from your DEX.

Batching several reads into one call is what keeps a per-pair state refresh affordable, and since your state has to be reconstructible at a specific block, you will be doing this again every time a pool is initialised lazily.

## Step two: the event subscriber keeps state fresh

Initialising the state is only the first half. The documentation's second step is to keep it in sync, and the tool for that is the Stateful Event Subscriber.

You override the processLog method in the StatefulEventSubscriber declared by your DEX. This method is called when an event which the subscriber is listening to is emitted. The state will be modified after the function is called, only if a state is returned, and returning null will be ignored and the state will not be altered.

That contract is simple and important. The subscriber owns the state, your function only proposes a new value, and the null return is how you say that this particular log does not concern you. The example implementation follows the swETH pool, listening for the Reprice event which is emitted when the swETH to ETH rate changes:

```ts
  decoder = (log: Log) => this.poolInterface.parseLog(log);

  protected processLog(
      state: DeepReadonly<SWETHPoolState>,
      log: Readonly<Log>,
  ): AsyncOrSync<DeepReadonly<SWETHPoolState> | null> {
    const event = this.decoder(log);
    if (event.name === 'Reprice')
      return {
        swETHToETHRateFixed: BigInt(event.args.newSwETHToETHRate),
      };

    return null;
  }
```

There is a documented alternative when events are not enough. If you require RPC calls, you can implement the StatefulRpcPoller, however using this may result in undesired charges as doing RPC calls is far more expensive. The warning about charges is the real constraint here: a poller that runs on a schedule burns RPC quota whether or not anyone is trading, which is precisely the cost the event driven model was built to avoid.

For reference, the documentation points at three existing implementations worth reading before you write yours: Uniswap V3, Nerve, and Curve V1, which is marked as complex because it has multiple pools such as 3pool and EURSPool.

## The scaffolding and the test expectations

The contribution path is scripted, which removes most of the guesswork from starting an integration.

Fork the repository to your organisation or personal account, clone it locally and create a branch with an appropriate name, for example feature/super-dex. Install the dependencies:

```bash
pnpm install
```

Then initialise the integration, with the DEX name in param-case:

```bash
pnpm init-integration <your-dex-name>
```

That creates template code in src/dex/<your-dex-name>, which the documentation describes as highly documented and which you are expected to fill in by implementing the functions. The instruction to look into existing DEX implementations in src/dex to understand the interfaces is the practical part: the interfaces are inferred from the code rather than from a specification document.

Then you add the name to the Dexes list in src/dex/index.ts, and you complete the test templates, all files matching src/dex/<your-dex-name>/*.test.ts. The documentation states that each DEX implementation should have thorough testing, that there are multiple kinds of tests each DEX must have, and that the tests can be run with:

```bash
pnpm test-integration <your-dex-name>
```

Finally, the pull request goes from your feature branch to DexLib master, and it must contain a brief explanation about the DEX background, the pricing logic, links to existing documentation, important contract addresses, and anything that would help the reviewers get through the code faster.

The contract addresses and the pricing logic in the description are a request for reviewability rather than a formality. A reviewer who cannot follow your arithmetic or find your contract will not approve the adapter, which is why the request to replicate the contract's behaviour exactly is paired with a request to explain it in the pull request.

## The tooling around the library

The package manifest describes a repository that is built like a library rather than a script, and the details matter if you are contributing.

The package is published as @paraswap/dex-lib at version 5.1.28, with the CommonJS entry at build/index.js and the type definitions at build/index.d.ts, marked as publicly publishable. The engines field requires Node 22 or newer and pnpm 11.0.0 or newer, which is worth noting before you clone, because the lockfile is a pnpm lockfile and there is a pnpm workspace configuration.

The scripts are shaped around the contributor workflow. init-integration and test-integration both call the same script, scripts/dex-integration.ts, with an init or a test argument. The build runs the formatting check, the lint check and then tsc, and the prepare hook installs husky and runs the build, so the git hooks are in place as soon as you install.

The checks are split into three named scripts. check:pq is pretty-quick on staged files, check:tsc is a plain type check, and check:es runs eslint over src with the test files excluded, using an airbnb-base configuration with the typescript plugin. There is a combined checks script that runs all three.

The environment file is a good indication of what a DEX integration needs. It defines three HTTP providers, one per chain id, plus Tenderly tokens and account and project identifiers for transaction tracing, and a set of API key tokens for several named liquidity sources.

The repository also carries a dex-template/ directory, a CLAUDE.md file, a funding.json, jest as the test runner with ts-jest, and both .husky/ and .prettierrc, so formatting and hooks are part of the contract rather than optional courtesy.

## Two licences, and the question they leave open

There is a discrepancy in the licensing information, and it is the kind of thing a careful reader should notice before building on the library.

The repository's own licence field lists GPL-3.0, and the repository has a LICENSE file at its root. But the package manifest that is actually published to npm declares the licence as MIT, with the author as dev@paraswap.io and the package marked as not private with public publish access.

That is a real ambiguity rather than a technicality, and the direction of it favours you. The MIT declaration in the manifest is the licence under which the package is distributed on npm, and MIT is the permissive choice. If your organisation checks licences automatically against the manifest, it will read MIT. If your legal process reads the repository licence file, it will read GPL-3.0.

For a contributor this matters less, since you are adding code to a GPL-3.0 repository and your contribution will be under that licence unless ParaSwap says otherwise, and their contributor terms would govern. For a consumer of the published package it matters more, because the two documents point in different directions. The safe step is to ask the maintainers which applies to the npm artefact before you depend on it commercially, and this is a note on what the two files say rather than legal advice about which one binds.

Beyond the licence question, the practical facts are favourable for a contributor. The package version is 5.1.28, so the library has been through several major iterations, the repository is pushed to regularly with a last push on 2026-10-19, and the integration workflow is documented to the point of naming the files you have to edit.

## Conclusion

paraswap-dex-lib suits a DEX team that wants its liquidity visible inside ParaSwap's router and is prepared to maintain an adapter inside another company's repository, with tests and a review process that has to be passed. It is the wrong choice if you want to keep your pricing logic private, because the adapter and its pricing calculation live in the open in ParaSwap's tree, and it is the wrong choice for a DEX that cannot expose the events its pool needs. Verify three things before you start: that your pool emits events a subscriber can consume rather than only a mutable price, that your state can be reconstructed from a Multicall at a given block, and that your contribution meets the repository's own test requirements, since a DEX without the expected tests will not pass review.

## FAQ

### What is paraswap-dex-lib?

DexLib is the library used by the ParaSwap backend to integrate with decentralized exchanges. It enables external DEX developers to integrate their DEX with ParaSwap by creating pull requests to the repository, so the adapter and its pricing logic live inside ParaSwap's own backend.

### How do I add a DEX to ParaSwap?

Fork the repository, create a branch, run pnpm install, then pnpm init-integration with the DEX name in param-case to generate the template in src/dex. Fill in the template, add the name to the Dexes list in src/dex/index.ts, complete the tests, run pnpm test-integration, and open a pull request against DexLib master with an explanation of the background, pricing logic, documentation links and contract addresses.

### Should I initialise pool state eagerly or lazily?

The documentation prefers the lazy option: initialise on receiving a first price request involving an asset your DEX can handle, as part of getPricesVolume, rather than overriding initializePricing to initialise on backend start. Lazy initialisation avoids reading state for pools nobody is trading.

### Why does the DexLib integration use Multicall?

Because the cost of RPC calls is the thing the whole design is trying to avoid. The documentation asks you to be mindful of the cost of RPC calls and says the best approach is to use Multicall, accessed from your DEX through this.dexHelper.multiContract.

### When should I use the StatefulRpcPoller instead of the event subscriber?

Only when you require RPC calls. The Stateful Event Subscriber is the documented default, and the documentation warns that using the poller may result in undesired charges, since doing RPC calls is far more expensive than consuming events.

### What licence applies to paraswap-dex-lib?

The repository lists GPL-3.0 with a LICENSE file at the root, while the published package manifest for @paraswap/dex-lib declares the licence as MIT. The project is published with public access and the manifest requires Node 22 or newer and pnpm 11 or newer.

## Sources

- [Issues](https://github.com/VeloraDEX/paraswap-dex-lib/issues)
- [License: GPL-3.0](https://github.com/VeloraDEX/paraswap-dex-lib/blob/master/LICENSE)
- [README](https://github.com/VeloraDEX/paraswap-dex-lib/blob/master/README.md)
- [VeloraDEX/paraswap-dex-lib on GitHub](https://github.com/VeloraDEX/paraswap-dex-lib)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/veloradex-paraswap-dex-lib
