Protocol

Protocol

Permit2

Signature based transfer use ordered, non-monotonic nonces so that signed permits do not need to be transacted in any particular order.

PermitTransferFrom结构体中amountSignatureTransferDetails结构体中requestAmount设计,为啥需要两个amount。是因为signature只验证PermitTransferFrom.

Custome Witness Data

Batch Transfer

Smart Nonce

Permit2 support erc1271

eth_signTypedData rpc接口

Uniswapv2

uniswapv2是一个AMM DEX协议. 用作两种ERC20代币的交换.

  • how uniswap works

    • UniswapPool
    • LP
    • Trader
    • Other(Flash Swaps and Oracle)

    价格定义

  • Smart Contracts

    • Core

      • Factory

        address public feeTo;
        address public feeToSetter;
        
        mapping(address => mapping(address => address)) public getPair;
        address[] public allPairs;
        
      • Pair

        • mint

          uint balance0 = IERC20(token0).balanceOf(address(this));
          uint amount0 = balance0.sub(_reserve0);
          
          bool feeOn = _mintFee(_reserve0, _reserve1);
          liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
          _mint(to, liquidity);
          

          MINIMUM_LIQUIDITY: 通过累积交易费用或通过向流动性池捐赠,理论上会导致最小流动性份额的value很大,以至于小流动性提供者无法提供任何流动性. 通过增加MINIMUM_LIQUIDITY, 对于任何token pair是微不足道的, 但它极大阻止了上述情况。为了使流动性份额value增加100, 攻击者需要向流动性池捐赠100*1000 = 100,000,它将作为流动性被永久锁定.

          fee收取: 对$\sqrt{K}$值变动收取费用.(0.3%, 0.25%, 0.05%, 1/6).

          oracle: 算术平均数, uint32 timeElapsed = blockTimestamp - blockTimestampLast;

        • burn

          burn是先将burn数值计算出来,然后再进行实际的burn, trnasfer等操作

        • swap

          (uint112 _reserve0, uint112 _reserve1,) = getReserves();
          
          if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
          if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out);
          
          balance0 = IERC20(_token0).balanceOf(address(this));
          balance1 = IERC20(_token1).balanceOf(address(this));
          
        • sync()

          sync()函数是一个恢复机制,用来重新调整交易对价格。 reserve=balanceOf(this)

        • skim()

          skim()也是一个恢复机制,将balance-reserve部分发送给某个地址

    • Periphery

      • router02

        • factory() and WETH()

        • addLiquidity and removeLiquidity

          • addLiquidity

            (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
            address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
            TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
            TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
            liquidity = IUniswapV2Pair(pair).mint(to);
            

            (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);

            if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
                IUniswapV2Factory(factory).createPair(tokenA, tokenB);
            }
            (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
            if (reserveA == 0 && reserveB == 0) {
                (amountA, amountB) = (amountADesired, amountBDesired);
            } else {
                uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
                if (amountBOptimal <= amountBDesired) {
                    require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
                    (amountA, amountB) = (amountADesired, amountBOptimal);
                } else {
                    uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
                    assert(amountAOptimal <= amountADesired);
                    require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
                    (amountA, amountB) = (amountAOptimal, amountBDesired);
                }
            }
            

            permit 移除流动性

          • FeeOnTransfer

          添加流动性没有FeeOn是因为mint的计算是按照pair合约收到的token来计算

          移除流动性amountToken计算按照balanceOf(router/this)计算

        • swap()

          swapExactTokensForTokens(), swapTokensForExactTokens().

          • getAmountOut()

              $\frac {amountIn}{amountOut} = \frac{reserveIn}{reserveOut}$
            
              $ 997 * amountIn = \frac{reserveIn * amountOut * 1000}{reserveOut}$
            
              $ amountOut = \frac{997 * amountIn * reserveOut}{reserveIn * 1000}$
            
              $ amountOut = \frac{997 * amountIn * reserveOut}{reserveIn * 1000 + 997*amountIn}$
            
          • getAmountIn()

            $\frac {amountIn}{amountOut} = \frac{reserveIn}{reserveOut}$

            $ 997 * amountIn = \frac{reserveIn * amountOut * 1000}{reserveOut}$

            $ amountIn = \frac{reserveIn * amountOut * 1000}{reserveOut*997}$

            $ amountIn = \frac{reserveIn * amountOut * 1000}{(reserveOut - amountOut)*997}$

          • swap

            amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
            require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
            TransferHelper.safeTransferFrom(
                path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
            );
            _swap(amounts, path, to);
            

            FeeOn

            TransferHelper.safeTransferFrom(
                path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
            );
            uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
            _swapSupportingFeeOnTransferTokens(path, to);
            require(
                IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
                'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
            );
            

            计算amountOutput时机不一样

            { // scope to avoid stack too deep errors
            (uint reserve0, uint reserve1,) = pair.getReserves();
            (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
            amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
            amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
            }
            (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
            address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
            pair.swap(amount0Out, amount1Out, to, new bytes(0));
            
  • Other

    • 使用safeTransfer而不是IERC20的原因

      如果sucess=false, 调用失败revert
      如果sucess=true且没有返回数据,调用成功
      如果success=true但有数据返回(数据类型解析成bool)
      	数据解析为true, 调用成功
      	数据解析为false, 调用失败
      
    • Flash swap

        ```
        function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
        ```
      
        EIP-3156(Flash Loans): https://eips.ethereum.org/EIPS/eip-3156
      
        借贷callback参数: 
        - msg.sender: 作为认证使用
        - token: 告诉借贷的币种
        - amount: 借贷的数量
        - fee: 借贷手续费
        - data: 闪电贷中执行的其它操作
      
    • Oralce

      算术平均数 A = $ \frac{A_1+A_2+…+A_n}{n} $, 当数据结果是一个和时。

      几何平均数 A = $ \sqrt[n]{A_1 * A_2 * … * A_n} $, 当数据结果是一个积时

      算术平均数 > 几何平均数

      [t1,t2]之间的价格平均数为$P_{t1,t2} = \frac {(A_{t2} - A_{t1})}{(t_2 - t_1)}$

    • 本身交易造成的滑点与池子流动性关系

      x = 100, y = 1000 , k = 100,000; x = 10, y = 100, k = 1,000

      使用x = 1兑换y, 计算兑换后x的价格 x_before = 1000/100 = 10, x_after = 990.099 / 101 = 9.80296; x_before = 100/10 = 10, x_after = 90.90909 / 11 = 8.264;

      显然,池子流动性越大,当前交易造成的滑点越小. 在稳定币交易中,期望在一定范围内滑点趋向于0.

      当滑点=0, 一笔交易对当前价格无影响. 价格 = y/x, 即斜率k不变. 斜率k不变的公式有x+y=k.

    • 价格影响

      价格滑点是指外部大盘走势引起的价格变化(与当前交易无关),价格影响是指当前交易对池子中价格影响`

      Poo info

      USDC = 2,000,000
      ETH = 1,000
      constant = 2,000,000,000
      price = 2,000
      

      10,000 USDC for ETH

      USDC = 2,010,000
      constant = 2,000,000,000
      ETH = 995.024(constat / USDC)
      

      ETH receive = 4.976 price = 2009.64 price impact = 0.48%

    • 无常损失

      impermanent_loss = 2 * sqrt(price_ratio) / (1+price_ratio) -1; prce_ratio > 1

Curve

Curve is an exchange liquidity pool on Ethereum. Curve is designed for extremely efficient stablecoin trading and low risk supplemental fee income for liquidity providers, without an opportunity cost.

  • curve曲线

    Curve引入一因子X, 用来调整恒定总和等式影响占比, 值越大,则曲线更加倾向于零滑点直线;值越小,则曲线更加倾向于高滑点的恒定乘积曲线

  • 池子分类

    • Plain Pools: 两个或多个稳定币交易流动性池,用于交易的流动性池, 目前3CRV和其他稳定币的池子
    • Lending Pools: 这个交易池中,对原生的代币进行了一个再包装(wrapped token),例如用户质押的是DAI,但流动性池里是cDAI,这样做的目的是为了可以将流动性池中的代币再借贷出去赚取利润,而用于交易的流动性池中实际保存的是wrapped token.
    • Meta Pools: 与另外一个流动性池中的流动性代币(LP)组成的流动性池,这样做的目的是为了给用户重新质押的机会,例如用户质押DAI到一个Plain pool获得LP,然后又将LP质押到metapool继续赚取收益,就像是买了一个债券,然后又用另一个债券换了一个理财.
  • veCRV机制

    veCRV = CRV * T/4, 质押CRV的时间越长,收到的veCRV就越多, 选择CRV锁仓4年才能获得1:1的veCRV。该质押锁仓行为不可逆转且veCRV不可流通 `

    • 收取Curve协议50%的交易手续费,收取手续费比例按照veCRV占比均分
    • vote Power. veCRV的投票权机制非常简单,投票权跟锁仓时间成正比,投票权会随着时间衰退的, 所以如果为了保持足够的投票权要一直刷新锁仓的时间
    • Boost机制, 流动性挖矿的基数只有40%, 通过足够量级的veCRV,才能获得boost倍速增加,最高2.5x,是一个线性增加机制.
  • Convex: 解决收益和流动性矛盾

    Convex协议解决的是crv散户无法获取加速的事情.

    Convex的协议token是CVX, 最大供应量1亿, 其中50%分配给Convex平台LP, 25%向CVX/ETH, cvxCRV/CRV提供流动性挖矿奖励(用户质押CRV获取cvxCRV, 1:1).

    Convex本身像一个大银行,用户把钱存在这里,获取比Curve高一点的收益. Convex本身把所有的CRV都锁了四年.

    Convex模式之所以可以良好的运行,本质上无法脱离CVX的价格支撑,因为一旦CVX价格过低,将导致收益率下降。所以Convex需要一些措施来减少CVX与cvxCRV的流通盘–Convex收取加速协议收益的16%作为平台费,并以此为基础,激励CVX与cvxCRV的持有者质押手中的token.

    veCRV资金量少的散户无法获取足够的veCRV用以提高流动性池收益.使得用户不需要锁仓CRV即可享受加速后的收益.

Cow Protocol

Cow Protocol is fully permissionless trading protocol that leverages Batch Auctions as its price finding mechanism.

cow协议和其它AMM交易不一样的是, 用户提交一笔交易是off-chain交易,这笔交易进入一个私有池,由solver去进行提交到链上.

solver通过对链下交易撮合或者从链上dex拿流动性,批量拍卖来减少用户的gas消耗和滑点

Cow Protocol use batch auctions as a core mechanism to facilitate CoWs.

cow面向用户有两种交易方式,一种是swap;一种是limit(price, expiration)

  • Benefits of Cow Protocol

    • First implementation of batch auctions promoting fair uniform clearing prices;
    • Trades are protected from different sorts of MEV
  • Cow协议中一笔完整的交易流程

    • Users need to approve the contract allowance manager to enable trading for a desired token.
    • Users can place limit sell/buy orders off-chain at any time by simply signing a message that contains their trade details. Users don’t pay a gas fee for posting and canceling orders.
    • Off-chain orders are picked up by the solvers who settle them in a batch auction
    • The protocol select the solvers order settlement solution that maximize trader welfare the most and provides the best clearing prices for the orders in that batch
      • All matched orders within a batch can either be settled off-chain via the liquidity found in the coincidence of wants(CoWs) across orders, or on-chain against AMM/aggregator liquidity.
  • Batch Auctions

    The two main reasons behind our development of batch auctions into a trading mechanism are:

    • Give the DeFi space in Ethereum a chance to establish the same price of any token pair in the same block.
    • Improve the DEX trading price offering by combining new economic mechanisms together such as Uniform Clearing Prices and Coincidence of Wants.

    Batch Auctions allow the trades within a batch to have the same uniform clearing price.

Velodrome

velodrome采用ve(3,3)模式: https://news.marsbit.co/20230508164914069116.html

Uniswapv3

Compound

Compound III is an EVM compatible protocol that enables supplying of crypto assets as collateral in order to borrow the base asset. Accounts can also earn interest by supplying the base asset to the protocol.

The initial deployment of Compound III is on Ethereum and the base asset is USDC.

---
这几个如何计算
Oracle Price

Collateral Factor

Liquidation Factor

Compound池子资产隔离吗?借贷利率如何计算,利息如何计算

---
  • CompoundII

    // todo // 抵押借稳定币,稳定币哪里来

    Compound是一个借贷协议,pool to peer。协议基于a floating interest rate. 每一个借贷市场是一个ERC20 token.

    • Supplying Tokens

      不像p2p借贷,需要用户之间进行匹配和利率协商。Compound协议聚合the suply of each user;当用户supplies a token,它变成一个fungible resources.用户可以随时进行提现.

      balances在a money market自然积累利率, 用户可以实时查看balance; update balance in (supply, transfer, withdraw).

    • Borrowing Tokens

      Compound允许用户无摩擦贷款从协议中, using collateralized line of credit.

      collateral ratio = user supply / user borrow

      用户可以全部返还资产或部分返还资产.

    • Risk & Liquidation

      当用户CR低于某一位置,用户的抵押品(supply)可以被purchase.

      清算会有激励给予, 减少协议风险. (清算是全部清算还是部分清算)

    • Use Case

      • 获取被动收入: 满足长期持有数字资产又希望能够产生额外收益的
      • 通过贷eth用户可以为ICO融资
      • 交易者看空某一个token, 融券卖出
    • Leger System

      Cash_a + Borrows_a = Supply_a + Equity_a

      Cash_a : 池子中余额

      资金利用率 = Borrow_a / Cash_a + Borroow_a

      贷款利率 = 10% + Ua*30%

      supply interest Rate_a = 贷款利率 * U_a * (1-S), S 是 代表协议的经济利润

      The history of each interest rate, for money market, is captured by Interest Rate Index

      Index_a,n = Index_a,n-1 * (1 + r * t)

      一个账户拥有的存储变量是(uint256 balance, uint256 index). global index. 每次发生一笔交易时, supply rate 和 borrow rate发生更新

    • 从产品层面的问题

      借贷逻辑如何实现?借款利率和存款利率计算?利息如何计算和分配?如何清算?存取款合约接口?展示的数据从哪里查询?

      supply, 我要知道supply的利率,当前CR率,资金利用率, 协议费

      池子是否隔离(单币资产在一个池,多币资产在同一池)

    • 合约

      • COMP

        一个COMP代币合约,具备delegate功能

      • Timelock

        一个执行交易合约

      • Comptroller

        • 启用抵押: Enter Market(address[])

        eth:0xc2998238000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000004ddc2d193948926d02f9b1fe9e1daa0718270ed5 (CETH)

        dai: 0xc2998238000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643 (CDAI)

      • CToken

      • Governanace

AAVE

Seaport

Aggregator

  • Universal Router

    The Universal Router is an ETH, ERC20, and NFT swap router.

    The flexible command stytle allows us to provide users with:

    • splitting and interleaving of Uniswap trades
    • Purchases of NFTs across 8 marketplaces
    • Partial fills of trades
    • Wrapping and Uniswapping of ETH
    • Time-bound, signature controlled token approvals using Permit2

Resources