Request form
Cyfrin Security / 5-t-swap-audit
    Docs
    Source
    ChefGPT

    This project is meant to be a permissionless way for users to swap assets between each other at a fair price. You can think of T-Swap as a decentralized asset/token exchange (DEX). T-Swap is known as an Automated Market Maker (AMM) because it doesn't use a normal "order book" style exchange, instead it uses "Pools" of an asset. It is similar to Uniswap.

    test.sol
    Base.sol
    Script.sol
    StdAssertions.sol
    StdChains.sol
    StdCheats.sol
    StdError.sol
    StdInvariant.sol
    StdJson.sol
    StdMath.sol
    StdStorage.sol
    StdStyle.sol
    StdUtils.sol
    Test.sol
    Vm.sol
    console.sol
    console2.sol
    IERC20.sol
    IMulticall3.sol
    safeconsole.sol
    IERC20.sol
    draft-IERC6093.sol
    ERC20Mock.sol
    ERC20.sol
    IERC20.sol
    IERC20Metadata.sol
    IERC20Permit.sol
    SafeERC20.sol
    Address.sol
    Context.sol
    DeployTSwap.t.sol
    PoolFactory.sol
    TSwapPool.sol
    PoolFactoryTest.t.sol
    TSwapPool.t.sol

    Chains

    Authors

    Cyfrin Security / 5-t-swap-audit
      Info
      Source
      ChefGPT
      Expand
      Share

      Get Cookin'

      Authors

      t-swap

      TSwap

      This project is meant to be a permissionless way for users to swap assets between each other at a fair price. You can think of T-Swap as a decentralized asset/token exchange (DEX). T-Swap is known as an Automated Market Maker (AMM) because it doesn't use a normal "order book" style exchange, instead it uses "Pools" of an asset. It is similar to Uniswap. To understand Uniswap, please watch this video: Uniswap Explained

      TSwap Pools

      The protocol starts as simply a PoolFactory contract. This contract is used to create new "pools" of tokens. It helps make sure every pool token uses the correct logic. But all the magic is in each TSwapPool contract.

      You can think of each TSwapPool contract as it's own exchange between exactly 2 assets. Any ERC20 and the WETH token. These pools allow users to permissionlessly swap between an ERC20 that has a pool and WETH. Once enough pools are created, users can easily "hop" between supported ERC20s.

      For example:

      1. User A has 10 USDC
      2. They want to use it to buy DAI
      3. They swap their 10 USDC -> WETH in the USDC/WETH pool
      4. Then they swap their WETH -> DAI in the DAI/WETH pool

      Every pool is a pair of TOKEN X & WETH.

      There are 2 functions users can call to swap tokens in the pool.

      • swapExactInput
      • swapExactOutput

      We will talk about what those do in a little.

      Liquidity Providers

      In order for the system to work, users have to provide liquidity, aka, "add tokens into the pool".

      Why would I want to add tokens to the pool?

      The TSwap protocol accrues fees from users who make swaps. Every swap has a 0.3 fee, represented in getInputAmountBasedOnOutput and getOutputAmountBasedOnInput. Each applies a 997 out of 1000 multiplier. That fee stays in the protocol.

      When you deposit tokens into the protocol, you are rewarded with an LP token. You'll notice TSwapPool inherits the ERC20 contract. This is because the TSwapPool gives out an ERC20 when Liquidity Providers (LP)s deposit tokens. This represents their share of the pool, how much they put in. When users swap funds, 0.03% of the swap stays in the pool, netting LPs a small profit.

      LP Example

      1. LP A adds 1,000 WETH & 1,000 USDC to the USDC/WETH pool
        1. They gain 1,000 LP tokens
      2. LP B adds 500 WETH & 500 USDC to the USDC/WETH pool
        1. They gain 500 LP tokens
      3. There are now 1,500 WETH & 1,500 USDC in the pool
      4. User A swaps 100 USDC -> 100 WETH.
        1. The pool takes 0.3%, aka 0.3 USDC.
        2. The pool balance is now 1,400.3 WETH & 1,600 USDC
        3. aka: They send the pool 100 USDC, and the pool sends them 99.7 WETH

      Note, in practice, the pool would have slightly different values than 1,400.3 WETH & 1,600 USDC due to the math below.

      Core Invariant

      Our system works because the ratio of Token A & WETH will always stay the same. Well, for the most part. Since we add fees, our invariant technially increases.

      x * y = k

      • x = Token Balance X
      • y = Token Balance Y
      • k = The constant ratio between X & Y
      y = Token Balance Y
      x = Token Balance X
      x * y = k
      x * y = (x + ∆x) * (y − ∆y)
      ∆x = Change of token balance X
      ∆y = Change of token balance Y
      β = (∆y / y)
      α = (∆x / x)
      
      Final invariant equation without fees:
      ∆x = (β/(1-β)) * x
      ∆y = (α/(1+α)) * y
      
      Invariant with fees
      ρ = fee (between 0 & 1, aka a percentage)
      γ = (1 - p) (pronounced gamma)
      ∆x = (β/(1-β)) * (1/γ) * x
      ∆y = (αγ/1+αγ) * y
      

      Our protocol should always follow this invariant in order to keep swapping correctly!

      Make a swap

      After a pool has liquidity, there are 2 functions users can call to swap tokens in the pool.

      • swapExactInput
      • swapExactOutput

      A user can either choose exactly how much to input (ie: I want to use 10 USDC to get however much WETH the market says it is), or they can choose exactly how much they want to get out (ie: I want to get 10 WETH from however much USDC the market says it is.

      This codebase is based loosely on Uniswap v1

      Getting Started

      Requirements

      • git
        • You'll know you did it right if you can run git --version and you see a response like git version x.x.x
      • foundry
        • You'll know you did it right if you can run forge --version and you see a response like forge 0.2.0 (816e00b 2023-03-16T00:05:26.396218Z)

      Quickstart

      git clone https://github.com/Cyfrin/5-t-swap-audit
      cd 5-t-swap-audit
      make 
      

      Usage

      Testing

      forge test
      

      Test Coverage

      forge coverage
      

      and for coverage based testing:

      forge coverage --report debug
      

      Audit Scope Details

      • Commit Hash: e643a8d4c2c802490976b538dd009b351b1c8dda
      • In Scope:
      ./src/
      #-- PoolFactory.sol
      #-- TSwapPool.sol
      
      • Solc Version: 0.8.20
      • Chain(s) to deploy contract to: Ethereum
      • Tokens:
        • Any ERC20 token

      Actors / Roles

      • Liquidity Providers: Users who have liquidity deposited into the pools. Their shares are represented by the LP ERC20 tokens. They gain a 0.3% fee every time a swap is made.
      • Users: Users who want to swap tokens.

      Known Issues

      • None
      This project is meant to be a permissionless way for users to swap assets between each other at a fair price. You can think of T-Swap as a decentralized asset/token exchange (DEX). T-Swap is known as an Automated Market Maker (AMM) because it doesn't use a normal "order book" style exchange, instead it uses "Pools" of an asset. It is similar to Uniswap.
      test.sol
      Base.sol
      Script.sol
      StdAssertions.sol
      StdChains.sol
      StdCheats.sol
      StdError.sol
      StdInvariant.sol
      StdJson.sol
      StdMath.sol
      StdStorage.sol
      StdStyle.sol
      StdUtils.sol
      Test.sol
      Vm.sol
      console.sol
      console2.sol
      IERC20.sol
      IMulticall3.sol
      safeconsole.sol
      IERC20.sol
      draft-IERC6093.sol
      ERC20Mock.sol
      ERC20.sol
      IERC20.sol
      IERC20Metadata.sol
      IERC20Permit.sol
      SafeERC20.sol
      Address.sol
      Context.sol
      DeployTSwap.t.sol
      PoolFactory.sol
      TSwapPool.sol
      PoolFactoryTest.t.sol
      TSwapPool.t.sol