區塊鏈積分商城開發運營版丨區塊鏈積分商城系統開發(案例及詳細)

xiaofufu發表於2023-02-25

  “新零售”的核心要義在於推動線上與線下的一體化程式,其關鍵在於使線上的網際網路力量和線下的實體店終端形成真正意義上的合力,從而完成電商平臺和實體零售店面在商業維度上的最佳化升級。同時,促成價格消費時代向價值消費時代的全面轉型。


  pragma solidity=0.5.16;


  import'./interfaces/IUniswapV2Pair.sol';


  import'./UniswapV2ERC20.sol';


  import'./libraries/Math.sol';


  import'./libraries/UQ112x112.sol';


  import'./interfaces/IERC20.sol';


  import'./interfaces/IUniswapV2Factory.sol';


  import'./interfaces/IUniswapV2Callee.sol';


  contract UniswapV2Pair is IUniswapV2Pair,UniswapV2ERC20{


  using SafeMath for uint;


  using UQ112x112 for uint224;


  //最低流動性


  uint public constant MINIMUM_LIQUIDITY=10**3;


  //獲取transfer方法的bytecode前四個位元組


  bytes4 private constant SELECTOR=bytes4(keccak256(bytes('transfer(address,uint256)')));


  address public factory;


  address public token0;


  address public token1;


  uint112 private reserve0;//uses single storage slot,accessible via getReserves==使用單個儲存槽,可透過getReserves訪問


  uint112 private reserve1;//uses single storage slot,accessible via getReserves


  uint32 private blockTimestampLast;//uses single storage slot,accessible via getReserves


  uint public price0CumulativeLast;//最後價格累計的0價格?


  uint public price1CumulativeLast;

  //緊接最近一次流動性事件之後


  uint public kLast;//reserve0*reserve1,as of immediately after the most recent liquidity event


  uint private unlocked=1;


  //防止遞迴迭代出現問題,所以要上鎖


  //一個鎖,使用該modifier的函式在unlocked==1時才可以進入,


  //第一個呼叫者進入後,會將unlocked置為0,此使第二個呼叫者無法再進入


  //執行完_部分的程式碼後,才會再將unlocked置1,重新將鎖開啟


  modifier lock(){


  require(unlocked==1,'UniswapV2:LOCKED');


  unlocked=0;


  _;


  unlocked=1;


  }


  //獲取儲備:返回:_reserve0,_reserve1,_blockTimestampLast


  //用於獲取兩個token在池子中的數量和最後更新的時間


  function getReserves()public view returns(uint112 _reserve0,uint112 _reserve1,uint32 _blockTimestampLast){


  _reserve0=reserve0;


  _reserve1=reserve1;


  //時間戳


  _blockTimestampLast=blockTimestampLast;


  }


  //轉賬,安全校驗


  function _safeTransfer(address token,address to,uint value)private{


  //呼叫transfer方法,把地址token中的value個coin轉賬給to


  (bool success,bytes memory data)=token.call(abi.encodeWithSelector(SELECTOR,to,value));


  //檢查返回值,必須成功否則報錯


  require(success&&(data.length==0||abi.decode(data,(bool))),'UniswapV2:TRANSFER_FAILED');


  }


  event Mint(address indexed sender,uint amount0,uint amount1);


  event Burn(address indexed sender,uint amount0,uint amount1,address indexed to);


  event Swap(address indexed sender,uint amount0In,uint amount1In,uint amount0Out,uint amount1Out,address indexed to);


  event Sync(uint112 reserve0,uint112 reserve1);


  //部署此合約時將msg.sender設定為factory,後續初始化時會用到這個值


  constructor()public{


  factory=msg.sender;


  }


  //called once by the factory at time of deployment


  //在UniswapV2Factory.sol的createPair中呼叫過


  function initialize(address _token0,address _token1)external{


  require(msg.sender==factory,'UniswapV2:FORBIDDEN');//sufficient check


  token0=_token0;


  token1=_token1;


  }


  //update reserves and,on the first call per block,price accumulators


  //更新儲備,並在每個區塊的第一次呼叫時更新價格累加器


  /**


  更新變數:


  blockTimestampLast


  reserve0


  reserve1


  price0CumulativeLast


  price1CumulativeLast


  */


  //這個函式是用來更新價格oracle的,計算累計價格


  function _update(uint balance0,uint balance1,uint112 _reserve0,uint112 _reserve1)private{


  //溢位校驗


  require(balance0<=uint112(-1)&&balance1<=uint112(-1),'UniswapV2:OVERFLOW');


  uint32 blockTimestamp=uint32(block.timestamp%2**32);


  uint32 timeElapsed=blockTimestamp-blockTimestampLast;//overflow is desired


  //計算時間加權的累計價格,256位中,前112位用來存整數,後112位用來存小數,多的32位用來存溢位的值


  if(timeElapsed>0&&_reserve0!=0&&_reserve1!=0){


  //*never overflows,and+overflow is desired


  price0CumulativeLast+=uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0))*timeElapsed;


  price1CumulativeLast+=uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1))*timeElapsed;


  }


  //更新reserve值


  reserve0=uint112(balance0);


  reserve1=uint112(balance1);


  blockTimestampLast=blockTimestamp;


  emit Sync(reserve0,reserve1);


  }


  //if fee is on,mint liquidity equivalent to 1/6th of the growth in sqrt(k)


  //如果收費,增發流動性相當於sqrt(k)增長的1/6


  function _mintFee(uint112 _reserve0,uint112 _reserve1)private returns(bool feeOn){


  //獲取接收手續費的地址


  address feeTo=IUniswapV2Factory(factory).feeTo();


  //手續費接收者不為0地址


  feeOn=feeTo!=address(0);


  uint _kLast=kLast;//gas savings


  //手續費接收者不為0地址


  if(feeOn){


  if(_kLast!=0){


  uint rootK=Math.sqrt(uint(_reserve0).mul(_reserve1));


  uint rootKLast=Math.sqrt(_kLast);


  if(rootK>rootKLast){


  uint numerator=totalSupply.mul(rootK.sub(rootKLast));


  uint denominator=rootK.mul(5).add(rootKLast);


  uint liquidity=numerator/denominator;


  if(liquidity>0)_mint(feeTo,liquidity);


  }


  }


  }


  //手續費接收者為0,並且kLast不為0


  else if(_kLast!=0){


  kLast=0;


  }


  }


  //this low-level function should be called from a contract which performs important safety checks


  //這個低階函式應該從執行重要安全檢查的合約中呼叫


  function mint(address to)external lock returns(uint liquidity){


  (uint112 _reserve0,uint112 _reserve1,)=getReserves();//gas savings


  //合約裡兩種token的當前的balance


  uint balance0=IERC20(token0).balanceOf(address(this));


  uint balance1=IERC20(token1).balanceOf(address(this));


  //獲得當前balance和上一次快取的餘額的差值


  //因為balance是動態變化的,reserve是靜態變化的


  uint amount0=balance0.sub(_reserve0);


  uint amount1=balance1.sub(_reserve1);


  //計算手續費


  bool feeOn=_mintFee(_reserve0,_reserve1);


  //gas節省,必須在此處定義,因為totalSupply可以在_mintFee中更新


  //totalSupply是pair的憑證


  uint _totalSupply=totalSupply;//gas savings,must be defined here since totalSupply can update in _mintFee


  if(_totalSupply==0){


  //第一次鑄幣,也就是第一次注入流動性,值為根號k減去MINIMUM_LIQUIDITY,防止資料溢位


  liquidity=Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);


  //把MINIMUM_LIQUIDITY賦給地址0,永久鎖住


  _mint(address(0),MINIMUM_LIQUIDITY);//permanently lock the first MINIMUM_LIQUIDITY tokens


  }else{


  //計算增量的token佔總池子的比例,作為新鑄幣的數量


  //木桶法則,按最少的來,按當前投入的佔池子總的比例增發


  liquidity=Math.min(amount0.mul(_totalSupply)/_reserve0,amount1.mul(_totalSupply)/_reserve1);


  }


  require(liquidity>0,'UniswapV2:INSUFFICIENT_LIQUIDITY_MINTED');


  //鑄幣,修改to的token數量及totalsupply


  //給to地址發憑證,同時pair合約的totalSupply增發同等的憑證


  _mint(to,liquidity);


  //更新時間加權平均價格


  _update(balance0,balance1,_reserve0,_reserve1);


  if(feeOn)kLast=uint(reserve0).mul(reserve1);//reserve0 and reserve1 are up-to-date


  emit Mint(msg.sender,amount0,amount1);


  }


  //this low-level function should be called from a contract which performs important safety checks


  function burn(address to)external lock returns(uint amount0,uint amount1){


  (uint112 _reserve0,uint112 _reserve1,)=getReserves();//gas savings


  address _token0=token0;//gas savings


  address _token1=token1;//gas savings


  uint balance0=IERC20(_token0).balanceOf(address(this));


  uint balance1=IERC20(_token1).balanceOf(address(this));


  uint liquidity=balanceOf[address(this)];


  bool feeOn=_mintFee(_reserve0,_reserve1);


  uint _totalSupply=totalSupply;//gas savings,must be defined here since totalSupply can update in _mintFee


  //計算返回的amount0/1


  amount0=liquidity.mul(balance0)/_totalSupply;//using balances ensures pro-rata distribution


  amount1=liquidity.mul(balance1)/_totalSupply;//using balances ensures pro-rata distribution


  require(amount0>0&&amount1>0,'UniswapV2:INSUFFICIENT_LIQUIDITY_BURNED');


  _burn(address(this),liquidity);


  //_token0/1給to轉amount0/1


  _safeTransfer(_token0,to,amount0);


  _safeTransfer(_token1,to,amount1);


  //獲取轉賬後的balance


  balance0=IERC20(_token0).balanceOf(address(this));


  balance1=IERC20(_token1).balanceOf(address(this));


  //更新reserve0,reserve1和時間戳


  _update(balance0,balance1,_reserve0,_reserve1);


  if(feeOn)kLast=uint(reserve0).mul(reserve1);//reserve0 and reserve1 are up-to-date


  emit Burn(msg.sender,amount0,amount1,to);


  }


  //this low-level function should be called from a contract which performs important safety checks


  //交易函式


  //可以是token0-->token1,


  //也可以是token1-->token0


  //但引數中:amount0Out和amount1Out中有一個值是0


  function swap(


  uint amount0Out,


  uint amount1Out,


  address to,


  bytes calldata data


  )external lock


  {


  require(amount0Out>0||amount1Out>0,'UniswapV2:INSUFFICIENT_OUTPUT_AMOUNT');


  (uint112 _reserve0,uint112 _reserve1,)=getReserves();//gas savings


  require(amount0Out<_reserve0&&amount1Out<_reserve1,'UniswapV2:INSUFFICIENT_LIQUIDITY');


  uint balance0;


  uint balance1;


  {//scope for _token{0,1},avoids stack too deep errors


  address _token0=token0;


  address _token1=token1;


  require(to!=_token0&&to!=_token1,'UniswapV2:INVALID_TO');


  //劃轉操作


  if(amount0Out>0)_safeTransfer(_token0,to,amount0Out);//optimistically transfer tokens


  if(amount1Out>0)_safeTransfer(_token1,to,amount1Out);//optimistically transfer tokens


  if(data.length>0)IUniswapV2Callee(to).uniswapV2Call(msg.sender,amount0Out,amount1Out,data);


  balance0=IERC20(_token0).balanceOf(address(this));


  balance1=IERC20(_token1).balanceOf(address(this));


  }


  uint amount0In=balance0>_reserve0-amount0Out?balance0-(_reserve0-amount0Out):0;


  uint amount1In=balance1>_reserve1-amount1Out?balance1-(_reserve1-amount1Out):0;


  require(amount0In>0||amount1In>0,'UniswapV2:INSUFFICIENT_INPUT_AMOUNT');


  {//scope for reserve{0,1}Adjusted,avoids stack too deep errors


  //防止資料溢位校驗


  uint balance0Adjusted=balance0.mul(1000).sub(amount0In.mul(3));


  uint balance1Adjusted=balance1.mul(1000).sub(amount1In.mul(3));


  require(balance0Adjusted.mul(balance1Adjusted)>=uint(_reserve0).mul(_reserve1).mul(1000**2),'UniswapV2:K');


  }


  //更新


  _update(balance0,balance1,_reserve0,_reserve1);


  emit Swap(msg.sender,amount0In,amount1In,amount0Out,amount1Out,to);


  }


  //force balances to match reserves


  //強制balance以匹配儲備


  function skim(address to)external lock{


  address _token0=token0;//gas savings


  address _token1=token1;//gas savings


  _safeTransfer(_token0,to,IERC20(_token0).balanceOf(address(this)).sub(reserve0));


  _safeTransfer(_token1,to,IERC20(_token1).balanceOf(address(this)).sub(reserve1));


  }


  //force reserves to match balances


  //強制儲備以匹配balance


  function sync()external lock{


  _update(IERC20(token0).balanceOf(address(this)),IERC20(token1).balanceOf(address(this)),reserve0,reserve1);


  }


  }


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69956839/viewspace-2937012/,如需轉載,請註明出處,否則將追究法律責任。

相關文章