<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      solidity學習之AMM

      什么是AMM

      AMM即自動做市商(Automated Market Maker,簡稱 AMM),以創建流動性池的形式支持資產的去中心化交易,無需傳統的對手盤訂單匹配,允許用戶隨時進行交易并且成交。

      實現邏輯

      AMM中最流行的模型是恒定乘積自動做市商(CPAMM),即兩種交易標的的乘積是一個固定的k值:k = x*y
      假設當前市場上有10瓶可樂和10美元,那么常數k就是100,可樂的價格為1元每瓶。如果有人拿出10美元交換可樂,此時的計算邏輯為先增加市場中美元的數量為20,那么可樂的數量就是100/20=5,因此這10美元交換到的可樂數為10-5=5,可樂現價為20/5=4美元,而交換得到的可樂均價為10/5=2美元。

      可以看到CPAMM省去了中間價格的計算,而是直接以最終的數量變化來決定單次交易可兌換出的數量。并且隨著數量變少,標的的價格會不斷上升,能夠有效地表現稀缺性的變化。

      流動性池

      在AMM中流動性池是人為添加的,用戶通過向流動性池中發送代幣來提高流動性,流動性越高的池子在相同的交易量下價格波動就會越小,為了鼓勵用戶添加流動性,流動性池會向LP(LIquidity Provider)發放獎勵。

      添加完流動性后會得到一種特殊的代幣,即LP token,用來標識用戶在流動性池中的權益,憑借LP token能夠分享流動性池產生的手續費。用LP token取回一開始添加的流動性資產時,會受到池子本身流動性變化的影響,最終取出的兩種資產的比例可能會發生變化。

      具體實現

      AMM合約本身也是一個ERC20合約,其中的代幣就是LP token,此外定義了兩種token作為交易的兩端,合約支持接收和轉出這兩種token。

      contract simpleSwap is ERC20 {
          IERC20 public token0;
          IERC20 public token1;
      
          uint256 public reserveToken0;
          uint256 public reserveToken1;
      
          constructor(IERC20 _token0, IERC20 _token1) ERC20("SimpleSwap", "SS") {
              token0 = _token0;
              token1 = _token1;
          }
          
          event Mint(address indexed sender, uint amount0, uint amount1);
      	  event Burn(address indexed sender, uint amount0, uint amount1);
          event Swap (
              address indexed sender,
              uint amountIn,
              address tokenIn,
              uint amountOut,
              address tokenOut
          );
      }
      

      首先實現兩個方法用來改變合約的流動性池,添加和取回流動性。

      添加流動性時,LP的計算公式:

      • 如果流動性為0,那么LP = $\sqrt{\Delta x* \Delta y}$
      • 否則LP = $L*min(\frac {\Delta X} {x},\frac {\Delta y}{y})$

      而取出流動性的時候, $\Delta x= \frac{\Delta L}{L}x$, $\Delta y = \frac {\Delta L}{L}y$,即根據當前LP占總LP的比例,取出對應比例的x代幣和y代幣。

      function addLiquidity(uint amountToken0, uint amountToken1) public returns (uint liquidity){
          token0.transferFrom(msg.sender, address(this), amountToken0);
          token1.transferFrom(msg.sender, address(this), amountToken1);
      
          uint _totalSupply = totalSupply();
          if (_totalSupply == 0) {
              liquidity = sqrt(amountToken0*amountToken1);
          } else {
              liquidity = min((amountToken0*_totalSupply)/reserveToken0, (amountToken1*_totalSupply)/reserveToken1);
          }
      
          require(liquidity>0,"insufficient liquidity minted");
      
          reserveToken0 = token0.balanceOf(address(this));
          reserveToken1 = token1.balanceOf(address(this));
      
          _mint(msg.sender, liquidity);
          emit Mint(msg.sender, amountToken0, amountToken1);
      }
      
      function removeLiquidity(uint liquidityAmount) public returns(uint amount0, uint amount1) {
          amount0 = (liquidityAmount * reserveToken0 / totalSupply());
          amount1 = (liquidityAmount * reserveToken1 / totalSupply());
      
          require(amount0>0 && amount1>0, "INSUFFICIENT_LIQUIDITY_BURNED");
      
          _burn(msg.sender, liquidityAmount);
          token0.transfer(msg.sender, amount0);
          token1.transfer(msg.sender, amount1);
      
          reserveToken0 = token0.balanceOf(address(this));
          reserveToken1 = token1.balanceOf(address(this));
      
          emit Burn(msg.sender, amount0, amount1);
      }
      
      

      接下來要實現swap方法,即用流動性池的一種token去交換另一種token,此時不改變LP token的數量,但是改變流動性池的比例分配。

      在swap中,因為$k=x*y$,那么交易后有$k=(x+\Delta x)(y+\Delta y)$,因為交易前后k的值不改變,那么得到$\Delta y = -\frac{\Delta x *y}{x+\Delta x}$。

      根據公式實現一個用來快速計算swap返回token數量的方法,既可以在swap中調用,也可以讓用戶在交易執行前預先知道能夠獲得的token數量。

        function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure returns (uint amountOut) {
            require(amountIn>0, "INSUFFICIENT AMOUNT");
            require(reserveIn >0 && reserveOut>0,"INSUFFICIENT LIQUIDITY");
      
            amountOut = amountIn * reserveOut / (reserveIn + amountIn);
        }
      

      最終swap功能實現如下,支持兩種token的相互轉換,合約得到tokenIn,轉出tokenOut給調用方。

        function swap(uint amountIn, IERC20 tokenIn, uint amountOutMin) external returns(uint amountOut, IERC20 tokenOut) {
            require(amountIn>0, "INSUFFICIENT AMOUNT");
            require(tokenIn==token0||tokenIn==token1, "INVALID TOKEN");
      
            if(tokenIn==token0) {
                amountOut = getAmountOut(amountIn, reserveToken0, reserveToken1);
                tokenOut = token1;
            } else {
                amountOut = getAmountOut(amountIn, reserveToken1, reserveToken0);
                tokenOut = token0;
            }
      
            require(amountOut>=amountOutMin, "INSUFFICIENT OUTPUT AMOUNT");
            tokenIn.transferFrom(msg.sender, address(this), amountIn);
            tokenOut.transfer(msg.sender, amountOut);
      
            reserveToken0 = token0.balanceOf(address(this));
            reserveToken1 = token1.balanceOf(address(this));
      
            emit Swap(msg.sender, amountIn, address(tokenIn), amountOut, address(tokenOut));
      
        }
      
      posted @ 2025-08-21 20:03  Felix07  閱讀(122)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩av一区二区三区精品| 伊人久久大香线蕉AV网| 肉大捧一进一出免费视频| 色老头在线一区二区三区| 亚洲精品无码成人A片九色播放| 欧美一区二区三区久久综合| 色一情一乱一区二区三区码| 广东少妇大战黑人34厘米视频| 人妻av资源先锋影音av资源| 性无码一区二区三区在线观看| 色丁香一区二区黑人巨大| 许昌市| 国产精品一二区在线观看| 亚洲大尺度无码专区尤物| 无码日韩做暖暖大全免费不卡| 亚洲熟少妇一区二区三区| 久久一本人碰碰人碰| 国内免费视频成人精品| 国产成人av电影在线观看第一页| 色综合色天天久久婷婷基地| 亚洲中少妇久久中文字幕| 亚洲熟女精品一区二区| 国产精品乱人伦一区二区| 宅男噜噜噜66在线观看| 久久精品国产亚洲AV瑜伽 | 亚洲欧美日韩在线码| 97久久精品亚洲中文字幕无码 | 在线播放无码后入内射少妇| 亚洲女人的天堂在线观看| 国产四虎永久免费观看| 国产成人久久综合一区| 国产在线精品欧美日韩电影| 国产日产免费高清欧美一区| 亚洲精品国男人在线视频| 国产午夜亚洲精品福利| 欧美不卡无线在线一二三区观| 国产亚洲精品aaaa片app| 精品无码国产日韩制服丝袜| 亚洲国产日韩一区三区| 玩弄放荡人妻少妇系列| 18禁免费无码无遮挡网站|