4 days + 01 06 32

5 day contest

QuickSwap and StellaSwap contest

A concentrated liquidity DEX with dynamic fees.

$50,000 USDC

Total Awards

QuickSwap contest details

Algebra Finance
Tests status Echidna status


Algebra is an innovative DEX engine with concentrated liquidity, dynamic fees, farmings and other features. The work of AMM is based on the most common approach with an invariant described by a constant product function ( x*y = k like) but with significant changes. By dividing the price interval into segments, users are given the opportunity to place liquidity on a limited range of prices, which allows them to multiply the depth of liquidity and the efficiency of capital use. At the same time, Algebra DEX uses a dynamic fee mechanism - this allows us to respond to changing market conditions and ensure a balance between the interests of traders and liquidity providers.

Basic design

Each pool corresponds to two tokens, which can be named token0 and token1, and: address(token0) < address(token1). Then the price can be treated as the ratio of some virtual reserves of these tokens virtual_reserve_token1 / virtual_reserve_token0. Discrete price segments are called ticks, which are the logarithm of price to base 1.0001: price = 1.0001 ^ (tick). Liquidity providers can provide liquidity in price ranges determined by the selected top and bottom ticks.

In practice, it is much more convenient to operate with the square root of the price. Therefore, we use square root of price everywhere in smart contracts. To maintain accuracy, the price is presented in the Q64.96 format. So you can get the price in human readable form with (price / 2^96)^2 (don't forget the decimals).

With each swap, the price moves in one direction or another, depending on which of the tokens the trader wants to buy and which to sell. If the price crosses the tick border, then liquidity of positions that are now inactive can be removed and liquidity of active positions added. With this approach, we can realize concentrated liquidity: tighter positions add more liquidity and can earn a larger share of fees, but may be more likely to become inactive.

Since a change in price may entail risks and losses for liquidity providers (impermanent loss), we change the current fee value in the pool based on price volatility. You can read more details about this in the techpaper. In short, the commission changes according to function, which is a combination of the sigmoids from volatility and the ratio of volume to liquidity.

Each pool records and stores data that provides the ability to obtain a time-weighted average price, volatility and other values. This functionality is placed in a separate contract (DataStorageOperator.sol).


Building and Testing

Setup in one-line

Requires npm >= 8.0.0

You can quickly clone a repository and install and run tests with:

git clone https://github.com/code-423n4/2022-09-quickswap
cd 2022-09-quickswap
npm run bootstrap && cd src/core && npm run compile && npm run test

If necessary, these steps are described in more detail below.


Requires npm >= 8.0.0

To install dependencies, you need to run the command in the root directory:

npm run bootstrap

This will download and install dependencies and set up husky hooks.

To compile, you need to run the following command in the src/core folder:

npm run compile


Tests are run by the following command in the src/core folder:

npm run test

Tests coverage

To get a test coverage, you need to run the following command in the src/core folder:

npm run coverage


Please note that Slither <= 0.8.3 contains a bug that interferes with the analysis of some contracts in the repository. Most likely, until the 0.8.4 slither is released, it will not be possible to analyze src/core/contracts/DataStorageOperator.sol. If necessary, you can try to use the dev version of Slither.


Firstly you need to create .env file in the root directory of project as in env.example.

To deploy in specific network:

node scripts/deployAll.js <network>


Contracts in scope:

Contracts (11)
Abstracts (2)
Total (over 13 files):183398.86%

The rest of the contracts are not in the scope.

Interfaces not included in the scope.

Contracts in the src/core/test folder not included in the scope.

Libraries not listed are not included in the scope.

Contracts purpose


Deploys pools and data storages, manages ownership and dynamic fee configuration


Main contract of pair with concentrated liquidity and dynamical fee. It contains the logic of swaps, liquidity providing, flash loans. Allows you to swap deflationary tokens and has protection from “Just-In-Time” liquidity providing


A contract that constructs a pool must implement this to pass arguments to the pool. This is used to avoid having constructor arguments in the pool contract, which results in the init code hash of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain


This contract is used for interacting with DataStorage library


Calculates fee based on combination of sigmoids


DataStorage provides price, liquidity, volatility data useful for a wide variety of system designs. Mainly used to calculate dynamic fee. Instances of stored dataStorage data, "timepoints", are collected in the dataStorage array Timepoints are overwritten when the full length of the dataStorage array is populated. The most recent timepoint is available by passing 0 to getSingleTimepoint()


Library that used for computing the result of a swap


Library for managing tick processes and relevant calculations


Packed tick initialized state library. Stores a packed mapping of tick index to its initialized state. The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word


TokenDeltaMath contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas

Areas to focus on

Theft or lock of funds

Is it possible to withdraw tokens or get more than the expected output? Can events occur that make it impossible to withdraw tokens from the pool?

Built-in oracle manipulation

Is it possible to provoke incorrect values in the DataStorageOperator.sol?

Calculation correctness

Can there be errors or inaccurate calculations? Could there be overflows or unexpected divisions by zero?

Unexpected behavior in general

Can the pool be in an invalid state?