文件 11 的 12:UniswapV2Library.sol
pragma solidity >=0.5.0;
import 'https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Pair.sol';
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol';
library UniswapV2Library {
using SafeMath for uint;
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
))));
}
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
function computeMaxAmount(int weiReserve, int tokenReserve, int minBuyTokenPerUnit_, int oneUnit_) internal pure returns (int) {
int numerator = 997*tokenReserve*oneUnit_ - 1000*weiReserve*minBuyTokenPerUnit_;
int denominator = 997*minBuyTokenPerUnit_;
return numerator/denominator;
}
}
文件 12 的 12:opendao.sol
pragma solidity >0.6.0 <0.8.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol';
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol';
import 'https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol';
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol';
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol';
import './UniswapV2Library.sol';
contract UniswapBuyer is Ownable {
using SafeMath for uint;
using SafeERC20 for IERC20;
IUniswapV2Router02 internal constant router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
address internal constant factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
uint public oneUnit = 1e18;
uint public buyBlock = 0;
uint public buyAmount = 0;
uint public sellBlock = 0;
uint public weiPoolAmount;
uint public tokenPoolAmount;
address public tokenAddress;
uint public minBuyTokenPerUnit;
uint public maxSellTokenPerUnit;
uint public sellRatio;
modifier onlyIfNoBuy {
require(buyBlock == 0, 'Buy already occurred');
_;
}
modifier onlyIfBuy {
require(buyBlock != 0, 'Buy did not occurr');
_;
}
constructor(address tokenAddress_, uint minBuyTokenPerUnit_, uint maxSellTokenPerUnit_, uint sellRatio_) Ownable() payable public {
tokenAddress = tokenAddress_;
minBuyTokenPerUnit = minBuyTokenPerUnit_;
maxSellTokenPerUnit = maxSellTokenPerUnit_;
sellRatio = sellRatio_;
}
receive() external payable {}
function withdrawEther(uint amount) public onlyOwner {
msg.sender.transfer(amount);
}
function withdrawToken(address tokenAddress_) public onlyOwner {
IERC20 tokenContract = IERC20(tokenAddress_);
uint tokenBalanceAmount = tokenContract.balanceOf(address(this));
tokenContract.safeTransfer(msg.sender, tokenBalanceAmount);
}
function setTokenAddress(address tokenAddress_) public onlyOwner {
tokenAddress = tokenAddress_;
}
function setMinBuyTokenPerUnit(uint minBuyTokenPerUnit_) public onlyOwner {
minBuyTokenPerUnit = minBuyTokenPerUnit_;
}
function setMaxSellTokenPerUnit(uint maxSellTokenPerUnit_) public onlyOwner {
maxSellTokenPerUnit = maxSellTokenPerUnit_;
}
function setSellRatio(uint sellRatio_) public onlyOwner {
sellRatio = sellRatio_;
}
function approve() public onlyOwner {
IERC20(tokenAddress).approve(address(router), uint(-1));
}
function reset() public onlyOwner {
buyBlock = 0;
buyAmount = 0;
sellBlock = 0;
}
function buy() public onlyIfNoBuy {
(uint weiReserve, uint tokenReserve) = UniswapV2Library.getReserves(factory, router.WETH(), tokenAddress);
int maxWeiAmount = UniswapV2Library.computeMaxAmount(int(weiReserve), int(tokenReserve), int(minBuyTokenPerUnit), int(oneUnit));
require(maxWeiAmount > 0, 'Price already too high');
uint effectiveBuyWeiAmount = Math.min(uint(maxWeiAmount), address(this).balance);
address[] memory path = new address[](2);
path[0] = router.WETH();
path[1] = tokenAddress;
router.swapExactETHForTokens{value : effectiveBuyWeiAmount}(1, path, address(this), block.timestamp);
buyBlock = block.number;
weiPoolAmount = weiReserve;
tokenPoolAmount = tokenReserve;
}
function sell() public onlyOwner onlyIfBuy {
require(block.number > buyBlock, 'Another buy occurred in same block number');
require(block.number > sellBlock, 'Another sell occurred in same block number');
IERC20 tokenContract = IERC20(tokenAddress);
uint tokenBalanceAmount = tokenContract.balanceOf(address(this));
require(tokenBalanceAmount > 0, 'Empty token balance');
buyAmount = Math.max(buyAmount, tokenBalanceAmount);
uint effectiveSellTokenAmount = Math.min(tokenBalanceAmount, buyAmount.div(sellRatio) + 1);
uint minWeiAmount = effectiveSellTokenAmount.mul(oneUnit).div(maxSellTokenPerUnit);
address[] memory path = new address[](2);
path[0] = tokenAddress;
path[1] = router.WETH();
router.swapExactTokensForETH(effectiveSellTokenAmount, minWeiAmount, path, address(this), block.timestamp);
sellBlock = block.number;
}
}
{
"compilationTarget": {
"browser/opendao.sol": "UniswapBuyer"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}