1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
| // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {SafeMath} from "@openzeppelin-contracts/contracts/utils/math/SafeMath.sol"; import {IERC20} from "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {IUniswapFactory} from "./interface/IUniswapFactory.sol"; import {IUniSwapExchange} from "./interface/IUniSwapExchange.sol";
contract UniSwapExchange { using SafeMath for uint256;
event EthToTokenPurchase(address indexed buyer,uint256 indexed ethIn,uint256 indexed tokensOut); //Eth 購買token事件通知 event TokenToEthPurchase(address indexed buyer,uint256 indexed tokensIn,uint256 indexed ethOut); //token 兌換 ETH事件通知 event Investment(address indexed liquidityProvider, uint256 indexed sharesPurchase); //添加流動性事件通知 event Divestment(address indexed liquidityProvider, uint256 indexed sharesBurned); //移除流動性事件通知 event InitializeExchange(address indexed token,uint256 indexed initializeAmount);
uint256 constant FEE_RATE = 500; //0.2% 費率
uint256 public ethPool; uint256 public tokenPool; uint256 public invariant; uint256 public totalShares; address public tokenAddress; address public factoryAddress;
mapping(address => uint256) shares;
IERC20 token; IUniswapFactory factory;
modifier exchangeInitialized(){ require(invariant > 0 && totalShares > 0); _; }
constructor(address _tokenAddress){ tokenAddress = _tokenAddress; factoryAddress = msg.sender; token = IERC20(tokenAddress); factory = IUniswapFactory(factoryAddress); }
receive() payable external{ require(msg.value != 0); //TODO ethToToken(msg.sender, msg.sender, msg.value, 1); }
//初始化交易对 function initializeExchange(uint256 _tokenAmount)external payable{ require(invariant == 0 && totalShares == 0); require(msg.value >= 10000 && _tokenAmount >= 10000 && msg.value <= 5 * 10 ** 18);
ethPool = msg.value; tokenPool = _tokenAmount; invariant = ethPool.mul(tokenPool); shares[msg.sender] = 1000; totalShares = 1000; emit InitializeExchange(tokenAddress,_tokenAmount); require(token.transferFrom(payable(msg.sender),address(this),_tokenAmount),"transfer fail!"); }
function ethToTokenSwap(uint256 _minTokens) external payable{ require(msg.value > 0 && _minTokens > 0); ethToToken(msg.sender,msg.sender,msg.value,_minTokens); }
function ethToTokenPayment(uint256 _minTokens, address _recipient) external payable { require(_minTokens > 0 && _recipient != address(0) && _recipient != address(this)); ethToToken(msg.sender,_recipient,msg.value,_minTokens); }
function tokenToEthSwap(uint256 _tokenAmount, uint256 _minEth ) external { require(_tokenAmount > 0 && _minEth > 0); tokenToEth(msg.sender,msg.sender,_tokenAmount,_minEth); }
function tokenToEthPayment(uint256 _tokenAmount ,uint256 _minEth ,address _recipient) external payable{ require(_tokenAmount > 0 && _minEth > 0 && _recipient != address(0) && _recipient != address(this)); tokenToEth(msg.sender,_recipient,_tokenAmount,_minEth); }
function tokenToTokenSwap(address _tokenPurchased,address _recipient,uint256 _tokensSold,uint256 _minTokensReceived) external { require(_tokenPurchased != address(0) && _recipient != address(0) && _recipient != address(this) && _tokensSold > 0 && _minTokensReceived > 0); tokenToTokenOut(_tokenPurchased,msg.sender,_recipient,_tokensSold,_minTokensReceived); }
function tokenTokenIn(address _recipient,uint256 _minTokens) external payable returns(bool){ require(_minTokens > 0); address exchangeToken = factory.exchangeToTokenLookup(msg.sender); require(exchangeToken != address(0)); ethToToken(msg.sender,_recipient, msg.value,_minTokens); return true; }
function investLiquidity(uint256 _minShares) external payable exchangeInitialized{ require(msg.value > 0 && _minShares > 0,"msg.value = 0 && _minShares = 0"); uint256 ethPerShare = ethPool.div(totalShares); require(msg.value >= ethPerShare,"msg.value < ethPerShare"); uint256 sharesPurchased = msg.value.div(ethPerShare); require(sharesPurchased >= _minShares,"sharesPurchased < _minShares"); uint256 tokensPerShare = tokenPool.div(totalShares); uint256 tokensRequired = sharesPurchased.mul(tokensPerShare); shares[msg.sender] = shares[msg.sender].add(sharesPurchased); totalShares = totalShares.add(sharesPurchased); ethPool = ethPool.add(msg.value); tokenPool = tokenPool.add(tokensRequired); invariant = ethPool.mul(tokenPool); emit Investment(msg.sender, sharesPurchased); require(token.transferFrom(msg.sender, address(this), tokensRequired),"Test Fail"); }
function divestLiquidity( uint256 _sharesBurned, uint256 _minEth, uint256 _minTokens ) external { require(_sharesBurned > 0); shares[msg.sender] = shares[msg.sender].sub(_sharesBurned); uint256 ethPerShare = ethPool.div(totalShares); uint256 tokensPerShare = tokenPool.div(totalShares); uint256 ethDivested = ethPerShare.mul(_sharesBurned); uint256 tokensDivested = tokensPerShare.mul(_sharesBurned); require(ethDivested >= _minEth && tokensDivested >= _minTokens); totalShares = totalShares.sub(_sharesBurned); ethPool = ethPool.sub(ethDivested); tokenPool = tokenPool.sub(tokensDivested); if (totalShares == 0) { invariant = 0; } else { invariant = ethPool.mul(tokenPool); } emit Divestment(msg.sender, _sharesBurned); require(token.transfer(msg.sender, tokensDivested)); payable(msg.sender).transfer(ethDivested); }
// View share balance of an address function getShares( address _provider ) external view returns(uint256 _shares) { return shares[_provider]; }
function ethToToken(address buyer,address recipient,uint256 ethIn,uint256 mintTokensOut) internal exchangeInitialized{
uint256 fee = ethIn.div(FEE_RATE); //计算费率 uint256 newEthPool = ethPool.add(ethIn); //计算交易对中最新的ETH流动性总量 uint256 tempEthPool = newEthPool.sub(fee); //减去费率后最新流动池中ETH数量 uint256 newTokenPool = invariant.div(tempEthPool); //公式 x * y = k 那最新的tokenPool y = k / x 10000 = 10 * 1000 10000 / 12 = 833
uint256 tokensOut = tokenPool.sub(newTokenPool); // 为了保持始终 x * y = k 之前的流动池数量 - 重新计算的流动池数量 = 本次买入的token数量
require(tokensOut >= mintTokensOut && tokensOut <= tokenPool);
ethPool = newEthPool; // 更新流动性信息 tokenPool = newTokenPool; invariant = newEthPool.mul(newTokenPool); //计算新的k值
emit EthToTokenPurchase(buyer,ethIn,tokensOut);
require(token.transfer(recipient,tokensOut)); }
function tokenToEth(address buyer,address recipient,uint256 tokensIn,uint256 minEthOut) internal exchangeInitialized {
uint256 fee = tokensIn.div(FEE_RATE); uint256 newTokenPool = tokenPool.add(tokensIn); uint256 tempTokenPool = newTokenPool.sub(fee); uint256 newEthPool = invariant.div(tempTokenPool);
uint256 ethOut = ethPool.sub(newEthPool); require(ethOut >= minEthOut && ethOut <= ethPool); tokenPool = newTokenPool; ethPool = newEthPool; invariant = newEthPool.mul(newTokenPool); emit TokenToEthPurchase(buyer,tokensIn,ethOut); require(token.transferFrom(buyer,address(this),tokensIn),"transfer token fail");
payable(recipient).transfer(ethOut); }
function tokenToTokenOut(address tokenPurchased ,address buyer ,address recipient ,uint256 tokensIn, uint256 minTokensOut) internal exchangeInitialized{
require(tokenPurchased != address(0) && tokenPurchased != address(this)); address exchangeAddress = factory.tokenToExchangeLookup(tokenPurchased); require(exchangeAddress != address(0) && exchangeAddress != address(this));
uint256 fee = tokensIn.div(FEE_RATE); uint256 newTokenPool = tokenPool.add(tokensIn); uint256 tempTokenPool = newTokenPool.sub(fee); uint256 newEthPool = invariant.div(tempTokenPool); uint256 ethOut = ethPool.sub(newEthPool); require(ethOut <= ethPool); IUniSwapExchange exchange = IUniSwapExchange(exchangeAddress);
emit TokenToEthPurchase(buyer,tokensIn,ethOut); tokenPool = newTokenPool; ethPool = newEthPool; invariant = ethPool.mul(tokenPool);
require(token.transferFrom(buyer,address(this),tokensIn)); require(exchange.tokenToTokenIn{value:ethOut}(recipient,minTokensOut));
}
}
|