Smart Contracts

The contracts are published in the Liquidswap GitHub repository at https://github.com/pontem-network/liquidswap.

Liquidswap uses smart contracts written in the Move language and executed by Move VM. The core contracts containing the protocol's logic and safety guarantees and are separated from the periphery contracts, allowing for a well-tested, reasonably small core layer and multiple versions of the periphery that can work with the core utilizing their own custom logic.

For example, the basic

`Router.move`

, used by Liquidswap's frontend, proxys all Liquidity Pool module methods with additional safety and price checks. At the same time, traders who want to minimize gas usage can write their own custom routers or call the core contracts directly.Branches and versions

The current

`main`

branch is the development branch and always contains the latest changes.Release branches contain the latest changes created for the specific release.

The current

`release-v0.3`

and release tags `v0.3*`

are designed for the mainnet release.Not all features from the

`main`

branch will necessarily be present in the upcoming releases - for example, flash loans will probably become available only in the future major releases.Addresses

All liquidity pools resources and LP coins currently placed on the following resource account:

0x385068db10693e06512ed54b1e6e8f1fb9945bb7a78c28a45585939ce953f99e

Integrations

This document explains how Liquidswap contracts are organized at the top level.

Liquidity Pool

The Liquidity Pool module implements all swap logic, LP logic, math (constant product formula), and core checks.

The core part of the Liquidity Pool contract is a resource that describes the liquidity pools themselves and contains all the required information:

1

struct LiquidityPool<phantom X, phantom Y, phantom Curve> has key {

2

coin_x_reserve: Coin<X>,

3

coin_y_reserve: Coin<Y>,

4

last_block_timestamp: u64,

5

last_price_x_cumulative: u128,

6

last_price_y_cumulative: u128,

7

lp_mint_cap: coin::MintCapability<LP<X, Y, Curve>>,

8

lp_burn_cap: coin::BurnCapability<LP<X, Y, Curve>>,

9

// Scales are pow(10, token_decimals).

10

x_scale: u64,

11

y_scale: u64,

12

}

- Reserves of both tokens
`X`

and`Y`

. - Curve type:
`phantom Curve`

. - Cumulative price information.
- Mint and burn capabilities for
`LP`

coins. - Token decimal scales (used for stable swaps).
- If a pool is locked (needed for the flash loan feature).

New liquidity pools are created on the registrar account, and the corresponding resource is placed in that account's storage.

Almost like Uniswap the Liquidswap creates pools on the reserved address:

0x385068db10693e06512ed54b1e6e8f1fb9945bb7a78c28a45585939ce953f99e

All pools are unique, so there can't be two pools containing the same coins, and it also works for LP and LP generics.

To avoid confusion, Liquidswap uses a frontend interface with a list of pools already pre-filled and a pools registry to show the users mostly verified pools.

Generics

A set of

`(X, Y, Curve)`

uniquely identifies a liquidity pool on the blockchain.Because of that, all functions that refer to pools have three generic parameters:

public entry fun swap<X, Y, Curve>(...) {}

`X, Y`

- the tokens to be swapped in a pool, for example,`0x1::aptos_coin::AptosCoin`

and`test_coins::coins::USDT`

(wrapped USDT)`Curve`

- type of the Curve corresponding to the pool, explained below.

Functions

`LiquidityPool`

`Router`

`LiquidityPool`

Operations with liquidity:

`register<X, Y, Curve>`

- creates fora new liquidity pool on reserved account.`mint<X, Y, Curve>`

- mints new LP coins in exchange for`Coin<X>`

and`Coin<Y>`

.`burn<X, Y, Curve>`

- burns some LP coins in exchange for`Coin<X>`

and`Coin<Y>`

.`swap<X, Y, Curve>`

- swaps`Coin<X>`

or`Coin<Y>`

or both to get`Coin<X>`

or`Coin<Y>`

or both in exchange.

Getters:

`is_pool_locked<X, Y, Curve>`

- returns bool determining if the pool is locked (flashloaned).`get_reserves_size<X, Y, Curve>`

- returns the current reserves size for both`Coin<X>`

and`Coin<Y>`

.`get_curve_type<X, Y, Curve>`

- returns the curve type for the pool.`get_decimals_scales<X, Y, Curve>`

- returns the decimal scales for both`Coin<X>`

and`Coin<Y> - but`

correct values are returned only for stable pools.`pool_exists_at<X, Y, Curve>`

- returns bool determining if the pool exists.`get_fees_config<X, Y, Curve>`

- returns fees config for the pool.`get_cumulative_prices<X, Y, Curve>`

- return cumulative prices and the last block's timestamp.

Coin Sorting

To work with Liquidity Pool module functions, you must sort the coins you pass on as generics.

Sorting is important as it brings in the rules for creating liquidity pools. All functions in the Liquidity Pool module accept only sorted generics; otherwise, it reverts.

For the Router and Scripts modules, **only part** of the functions requires generics to be sorted.

The current sorting algorithm takes the types of provided coins, e.g.,

`address::module::struct_name`

, and compares the struct name of both coins. If it's equal, it continues with the module name and, in the end, with the address.Other languages:

Curve types

When creating a pool, the curve type can be provided; it's as simple as using a generic to determine the pool type.

The types themself:

/// For pairs like BTC, Aptos, ETH.

struct Uncorrelated {}

/// For stablecoins like USDC, USDT.

struct Stable {}

`liquidswap::curves::Uncorrelated`

- Uncorrelated curve type.`liquidswap::curves::Curve`

- Stable curve type.

The following types can be imported into code and should be used as the last generic argument in almost all modules functions.

LP coins

The

`LP`

coins type for pairs `X`

and `Y`

is represented as `LP<X, Y, Curve>`

and deployed on the following resource account:0x385068db10693e06512ed54b1e6e8f1fb9945bb7a78c28a45585939ce953f99e

The LP coin registers automatically for each new liquidity pool, and generics are always sorted.

For

`APT/BTC`

uncorrelated pool, the LP coin would look so:

0x385068db10693e06512ed54b1e6e8f1fb9945bb7a78c28a45585939ce953f99e::lp_coin::LP<

0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC,

0x1::aptos_coin::AptosCoin,

0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::curves::Uncorrelated,

>

Router

The Router module is a periphery layer on top of the Liquidity Pool module.

The Router contains additional checks to verify that the amount that a developer, trader, or liquidity provider wants to exchange/mint/burn is reasonable.

Also, the module sorts tokens or coins automatically for **part of functions** and has several useful getters that help estimating the swap price.

In most cases, we recommend using a Router if you want to work with the Liquidity Pool module.

Third-party teams can provide their own routers, but Liquidswap's standard Router should be enough for most cases. An added advantage is that it's already audited.

Functions

The router functions accept the resources

`Coin<X>,`

`Coin<Y>`

, `Curve`

similar to Liquidity Pool module. However, the functions cannot be called directly from a transaction; if you need entry points, refer to Scripts.

Developers interacting with **swap functions and getters** can order generics in any way they wish. For example, if one wants to swap

`aptos_framework::aptos_coin::AptosCoin`

to `test_coins::coins::USDT, one`

can just use the function:router::swap_exact_coin_for_coin<

aptos_framework::aptos_coin::AptosCoin,

test_coins::coins::USDT,

curves::Uncorrelated,

>

A reverse swap (

`USDT`

-> `APTOS`

) can be done by reordering the generics:router::swap_exact_coin_for_coin<

test_coins::coins::USDT,

aptos_framework::aptos_coin::AptosCoin,

curves::Uncorrelated,

>

`register_pool`

,`add_liquidity`

, `remove_liquidity`

) requires Liquidity operations:

**Requires sorted generics:**`register_pool<X, Y, Curve>`

- register a new pool with`Coin<X>`

and`Coin<Y>`

as reserves and provided curve.`add_liquidity<X, Y, Curve>`

- add liquidity (`Coin<X>`

and`Coin<Y>`

) to an existing pool.`remove_liquidity<X, Y, Curve>`

- burn`Coin<LP<X ,Y, Curve>>`

and get`Coin<X>`

and`Coin<Y>`

back with checks.

**Generics can be sorted in any way:**`swap_exact_coin_for_coin`

- swap an exact amount of`Coin<X>`

to get no less than the specified amount of`Coin<Y>`

.`swap_coin_for_exact_coin`

- swap no more than the specified maximum amount of`Coin<X>`

to get an exact amount of`Coin<Y>`

.`swap_coin_for_coin_unchecked`

- simply swaps tokens without any checks.

`get_amount_out<X, Y, Curve>`

- estimate the amount of`Y`

tokens resulting from a swap of a specified amount in`X`

tokens. Can consume a lot of gas when used for stable pools.`get_amount_in<X, Y, Curve>`

- estimate the amount of`X`

tokens needed to get a specified amount in`Y`

tokens.`calc_optimal_coin_values<X, Y, Curve>`

- calculates the optimal amounts of`Coin<X>`

and`Coin<Y>`

needed to add liquidity and get a fair amount of LP coins.`get_reserves_size<X, Y, Curve>`

- returns the reserves for both coin X and coin Y held by the pool.`pool_exists_at<X, Y, Curve>`

- returns bool determining if the pool exists.`get_decimals_scales<X, Y, Curve>`

- returns the pool's decimals scale. The resulting values will be correct only for stable pools.`get_cumulative_prices<X, Y, Curve>`

- returns cumulative prices and the last block's timestamp.`get_reserves_for_lp_coins<X, Y, Curve>`

- returns the amounts in`Coin<X>`

and`Coin<Y>`

that a user will receive after burning LP coins.

Scripts

The top-level module contains the entry functions that users can execute directly by sending transactions and that third-party modules can use via

`&signer`

.Summary:

- Requires a signer;
- Accepts numbers as arguments representing coins' values;
- Extracts coins/tokens directly from the signer account;
- Registers a LP token on the account if it's not registered;

This is the optimal way to interact with Liquidswap if you want to call a swap from the CLI or the UI using the standard router.

Functions

All the functions have 'slippage' amount arguments, like

`coin_x_val_min`

, `coin_y_val_min`

or `min_x_out_val`

, etc.

**Requires sorted generics:**`register_pool<X, Y, Curve>`

- register a pool with the specified curve type.`register_pool_and_add_liquidity<X, Y, Curve>`

- register a pool with the specified curve type and add liquidity immediately (extracted from the signer's balance), with the resulting LP tokens deposited to the signer.`add_liquidity<X, Y, LP>`

- add liquidity to an existing pool, with the resulting LP coins deposited to the signer's address.`remove_liquidity<X, Y, Curve>`

- burns users LP coins and deposit received coin X and coin Y on user account.

**Generics can be sorted in any way:**`swap<X, Y, Curve>`

- swap`Coin<X>`

for`Coin<Y>;`

the developer has to provide the amount of`X`

coins`coin_val`

to get the minimum amount`coin_out_min_val`

of Y.`swap_into<X, Y, LP>`

- swap no more than the specified maximum amount of`Coin<X>`

for an exact amount in`Coin<Y>`

. The remainder of`Coin<X>`

will be deposited back to the account.

Helpers

The helpers library improves code readability by extracting parts of the math, token interactions, and other things to separate files.

Coin Helper

Mostly helpers on top of

`aptos_framework::coin`

.Functions

`assert_is_coin<CoinType>`

- aborts if the provided`CoinType`

is not a coin/token.`compare<X, Y>`

- compares`X`

coin symbols and`Y`

coin symbols.`is_sorted<X, Y>`

- returns bool determining if`X`

and`Y`

tokens are sorted.`supply<CoinType>`

- extracts supply from`LP`

, ignoring`Option`

.`generate_lp_name<X, Y, Curve>`

- generates a name and symbol for the`LP`

token from`X`

and`Y`

symbols and`Curve`

.

Math

Implements basic math helpers.

Functions

`overflow_add`

- adding two`u128`

and just overflowing the numbers if needed without aborting.`mul_div`

-`x * y / z`

for`u64`

numbers.`mul_div_u128`

-`x * y / z`

for`u128`

numbers but returns`u64`

.`mul_to_u128`

- muls two`u64`

to`u128`

.`sqrt`

- get the square root using the Babylonian method.`pow_10`

- returns`10^degree`

.

Deps libraries

The smart contracts utilize the following math libraries created by the Pontem team:

Advanced topics

Flashloans

Flashloans have been implemented in the

`main`

branch as a concept, but there is no set timeline for actually implementing them in the AMM protocol.The implementation is based on Move's loan concept, where a Move object containing the loan data is issued but cannot be stored, copied, cloned or dropped, the only available action being to return the object back to the

`pay_flashloan`

function, which will verify the resulting constant product function.VE(3,3)

The

`ve(3,3)`

logic is currently under active development and can undergo significant changes; stay tuned.Oracle

Liquidswap's oracle model is based on the cumulative price algorithm used by Uniswap v2. For this reason, token price variables on Liquidswap can overflow, just like on Uniswap.

The following fields in the Liquidity Pool resource are responsible for storing prices:

last_block_timestamp: u64,

last_price_x_cumulative: u128,

last_price_y_cumulative: u128,

Meanwhile, the Liquidity Pool module's function

`get_cumulative_prices<X, Y, Curve>`

extracts prices from the pool.Treasury

The DAO Treasury receives a 0.1% fee from each swap transaction in every liquidity pool on the protocol. A reminder: Liquidswap's total fee is 0.3%, out of which 0.2% go to the liquidity providers and 0.1% to the treasury.

The treasury is currently managed by an admin multisig and will be eventually transfered to a full-fledged Pontem DAO.

Dynamic fees

With dynamic fees currently controlled by admin multisig and later by Pontem DAO, the number of fees can be changed but not greater than the maximum.

Emergency

Can be used to pause/resume all swaps via an emergency account.

The contract itself can be disabled forever once the team can verifies that the protocol is fully stable and will not be derailed by any liquidity event, attack etc.

Last modified 10d ago

Copy link

On this page

Branches and versions

Addresses

Integrations

Liquidity Pool

Generics

Functions

Curve types

LP coins

Router

Functions

Scripts

Functions

Helpers

Coin Helper

Math

Deps libraries

Advanced topics