Giter VIP home page Giter VIP logo

catalyst's Introduction

Catalyst smart contracts monorepo

This monorepo contains all Catalyst implementations

Catalyst is an implementation of the Unit of Liquidity AMM design. A design which used independent pricing to asynchronously price assets using shared liquidity, supporting both volatile assets and stable assets.

Each implementation is contained within its own folder.

  • /evm : Solidity implementation targeting the Ethereum Virtual Machine.
  • /rust-common : Contains depreciated code
  • /simulator : Simulation of the Catalyst logic.
  • /solana : Rust implementation targeting the Solana Virtual Machine.

The EVM implementation is used as a reference implementation.

On Asset Pricing

For an indepth description of how to price assets, read Unit of Liquidity. The below seciton contains notable equations.

The Catalyst Equation

Let $P_i(w)$ be a decreasing, non-negative marginal price function for a token $i$. The equation which describes a Catalyst swap is then defined as:

$$U = \int_{i_t}^{i_t + \Delta i} P_i(w) \ dw$$

Where $i_t$ is the current balance in the vault, $\Delta i$ is the change in balance caused by the user and $U$ is Units: A measure of the value change by the user. The equation can be used both ways, where a positive change implies a "swap in" and a negative change implies a "swap out". It is implies that when assets are swapped out, $U$ the sign is flipped from positive to negative.

This implies that the full swap from a token $i$ to another token $j$ can be computed as:

$$\int_{i_t}^{i_t + \Delta i} P_i(w) \ dw =- \int_{j_t}^{j_t + \Delta j} P_j(w) \ dw = \int_{j_t + \Delta j}^{j_t} P_j(w) \ dw$$

Notice that even though the full swap is written as a single equation, it can be evaluated in 2 independent slices (based on the previous equation).

Catalyst's Price

Catalyst defines 2 price curves to serve both demand for volatile tokens and tokens with a stable value.

Volatile: $P(w) = \frac{W_i}{w}$

Amplification: $P^\theta(w)= \frac{W_i}{(W_i \cdot w)^\theta} \cdot (1-\theta)$

AMM Terms

Marginal Price: If someone were to buy/sell an infinitesimal in the vault. the marginal price is the price they would pay. The marginal price can generally be derived in 2 + 1 ways: $\lim_{x_\alpha \to 0} y_\beta/x_\alpha$ or $\frac{\mathrm{d}}{\mathrm{d}i_\alpha} solve(Invariant, i_\beta)$. Often they are equal to $\frac{P_\alpha(w)}{P_\beta(w)}$.

sendAsset: The first swap of a Catalyst swap. It is independent of the state of the second leg of the transaction. Within a vault $U$ can be used to transparently purchase any token via receiveAsset.

receiveAsset: The last (and second) leg of a Catalyst swap. It is completely independent of the state of the first leg of the transaction. It requires $U$ which can be acquired by selling any token in the group.

LocalSwap: A combination of sendAsset and receiveAsset executed atomically, often on a single chain.

Invariant: A measure used to measure the vault value. Specific to the invariant measure, is that it is constant whenever a swap is completed. If a vault implements a swap fee, the measure increases as fees accumulate in the vault. The invariant is not invariant to deposits or withdrawals. The invariants can continously be examined if the number of emitted Units is kept track of. In the below equations, this is representated as $\sum U$.

The AMM Equations

Using the Catalyst Equation with the price curves, the mathematical swap equations can be derived.

Volatile Tokens

  • Marginal price: $\lim_{x \to 0} y_j/x_i = \frac{j}{i} \frac{W_i}{W_j}$

  • SwapToUnits: $U = W_i \cdot \log\left(\frac{i_t+x_i}{i_t}\right)$

  • SwapFromUnits: $y_j = j_t \cdot \left(1-\exp\left(-\frac{U}{W_j}\right)\right)$

  • Invariant: $K = \sum_{i \in {\alpha, \beta, \dots}} \ln(i_t) \cdot W_i + \sum U$

Amplified Tokens

  • Marginal price: $\lim_{x \to 0} y_j/x_i = \frac{\left(i_t W_i\right)^\theta}{\left(j_t W_j\right)^\theta} \frac{W_j}{W_i}$

  • SwapToUnits: $U = \left((i_t \cdot W_i + x_i \cdot W_i)^{1-\theta} - \left(i_t \cdot W_i \right)^{1-\theta} \right)$

  • SwapFromUnits: $y_j = j_t \cdot \left(1 -\left(\frac{\left(j_t \cdot W_j\right)^{1-\theta} - U }{\left(j_t \cdot W_j\right)^{1-\theta}}\right)^{\frac{1}{1-\theta}}\right)$

  • Invariant: $K = \sum_{i \in {\alpha, \beta, \dots}} i^{1-\theta} W_i^{1-\theta} + \sum U$

catalyst's People

Contributors

reednaa avatar jsanmigimeno avatar dockercui avatar

Stargazers

0xJiro avatar ImanPJN avatar Shun Kakinoki avatar  avatar Sam avatar bp avatar keyneszeng avatar  avatar 0exo9planet avatar Harsh Patel avatar 0snglx avatar 0srdrxatk avatar Javed Khan avatar Michele avatar  avatar Samir Ettali avatar Yuan avatar  avatar indigo avatar

Watchers

benk10 avatar  avatar 0exo9planet avatar 0snglx avatar 0srdrxatk avatar

catalyst's Issues

`withdrawMixed` ratio implementation does not protect the user from meaningless ratios

Currently, a user can specify non-zero values within the ratio after having used all of the extraction capacity.
Example: Given a pool with 3 assets, the ratio [0.5, 1, 1] extracts:

  • 50% of the pool tokens for the first asset
  • 100% of the remaining pool tokens (i.e. 50% total) for the second asset
  • 100% of the remaining pool tokens (i.e. 0% total) for the third asset

A check should be implemented to prevent such erroneous configurations.

See Audit Issue for the original report of the issue.

Unchecked addition of weighted escrow amount

To both avoid overflow and avoid this call from failing, check whether the addition will overflow, and set _maxUnitCapacity to uint256::MAX in the overflow case. Note that this will also require removing several unchecked blocks of the form

unchecked {
	_maxUnitCapacity -= ...
}

since it may no longer be the case that _maxUnitCapacity is greater than the sum of the weighted asset balances.

by Veridise

`override` specifier missing on `SwapPool...` methods

The override specifier is missing on the following swap pool methods corresponding to the CatalystV1PoolPermissionless interface (for both volatile and amplified implementations):

  • localSwap
  • sendAsset
  • receiveAsset
  • sendLiquidity
  • receiveLiquidity
  • depositMixed
  • withdrawMixed
  • withdrawAll

See (Audit Issue)[https://www.notion.so/veridise/Swap-pool-methods-missing-override-specifiers-5c9d3ca9aee0425998bf2a3e0c1efda0?pvs=4] for the original report.

Unoptimized manual implementation of mulWad

Manual implementations of wad number multiplications should be avoided. Example:
Within receiveLiquidity() (SwapPoolVolatile):
uint256 poolTokens = (_calcPriceCurveLimitShare(U, wsum) * totalSupply)/FixedPointMathLib.WAD;
can be replaced with
uint256 poolTokens = FixedPointMathLib.mulWadDown((_calcPriceCurveLimitShare(U, wsum), totalSupply));

It has to be reviewed and fixed all cases in which this happens.

See Audit Issue for original report.

Frontrunners may extract value form liquidity swaps

When liquidity swapping, the current implementation of minOut is not sufficient to prevent front running attacks, as a third party can devaluate the value of the pool tokens, effectively being able of extracting value from the pool.

onlyFactoryOwner modifier not used consistently

There are functions in which the msg.sender is manually checked to be equal to the factoryOwner by a require statement. The onlyFactoryOwner modifier should always be used for these cases.

Governance fee collection may fail for large swaps

To avoid the use of nonReentrant on sendAsset (contract size/gas optimization), _collectGovernanceFee() occurs before the swap funds are transferred to the pool. This risks _collectGovernanceFee() (which transfers a cut of the input asset balance from the pool to the governance) reverting because of insufficient pool assets.
This design choice should be reverted, as large swaps may fail to execute. It should:

  • Add nonReentrant to sendAsset
  • Flip the order of _collectGovernanceFee() and safeTransferFrom()

See Audit Issue for the original report.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.