|
// SPDX-License-Identifier: GPL-3.0 |
|
pragma solidity ^0.6.10; |
|
|
|
interface V5IICherryPair { |
|
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); |
|
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; |
|
} |
|
|
|
interface IERC20 { |
|
function balanceOf(address owner) external view returns (uint); |
|
function transfer(address to, uint value) external returns (bool); |
|
} |
|
|
|
library SSV5SafeMath { |
|
function add(uint256 a, uint256 b) internal pure returns (uint256) { |
|
uint256 c = a + b; |
|
require(c >= a, "SSV5-SafeMath: addition overflow"); |
|
|
|
return c; |
|
} |
|
function sub(uint256 a, uint256 b) internal pure returns (uint256) { |
|
return sub(a, b, "SSV5-SafeMath: subtraction overflow"); |
|
} |
|
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b <= a, errorMessage); |
|
uint256 c = a - b; |
|
|
|
return c; |
|
} |
|
function mul(uint256 a, uint256 b) internal pure returns (uint256) { |
|
if (a == 0) { |
|
return 0; |
|
} |
|
|
|
uint256 c = a * b; |
|
require(c / a == b, "SSV5-SafeMath: multiplication overflow"); |
|
|
|
return c; |
|
} |
|
function div(uint256 a, uint256 b) internal pure returns (uint256) { |
|
return div(a, b, "SSV5-SafeMath: division by zero"); |
|
} |
|
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b > 0, errorMessage); |
|
uint256 c = a / b; |
|
|
|
return c; |
|
} |
|
function mod(uint256 a, uint256 b) internal pure returns (uint256) { |
|
return mod(a, b, "SSV5-SafeMath: modulo by zero"); |
|
} |
|
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { |
|
require(b != 0, errorMessage); |
|
return a % b; |
|
} |
|
} |
|
|
|
contract SSV5 { |
|
using SSV5SafeMath for uint; |
|
|
|
// 输出数量 |
|
uint gx; |
|
uint gy; |
|
|
|
// // todo 生产删除 |
|
// uint public gmintenTime; |
|
|
|
constructor() public {} |
|
|
|
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { |
|
// require(amountIn > 0, 'getOut: INSUFFICIENT_INPUT_AMOUNT'); |
|
// require(reserveIn > 0 && reserveOut > 0, 'getOut: 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, 'getIn: INSUFFICIENT_OUTPUT_AMOUNT'); |
|
// require(reserveIn > 0 && reserveOut > 0, 'getIn: INSUFFICIENT_LIQUIDITY'); |
|
|
|
uint numerator = reserveIn.mul(amountOut).mul(1000); |
|
uint denominator = reserveOut.sub(amountOut).mul(997); |
|
|
|
amountIn = (numerator / denominator).add(1); |
|
} |
|
|
|
function sortTokens(address tokenA, address tokenB) internal pure returns (address tokens0, address tokens1) { |
|
// require(tokenA != tokenB, 'CherryLibrary: IDENTICAL_ADDRESSES'); |
|
(tokens0, tokens1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); |
|
// require(tokens0 != address(0), 'CherryLibrary: ZERO_ADDRESS'); |
|
} |
|
|
|
function getRestY(uint a, uint b, uint c, uint d) internal pure returns (uint y) { |
|
// const y = (997 * 997 * c * b - 1000 * 1000 * a * d) / (997 * 1000 * a + 997 * 997 * c); |
|
uint dividedBy = uint(997).mul(1000).mul(a).add(uint(997).mul(997).mul(c)); |
|
uint subFrom = uint(997).mul(997).mul(c).mul(b); |
|
uint subBy = uint(1000).mul(1000).mul(a).mul(d); |
|
if (subFrom > subBy) { |
|
y = subFrom.sub(subBy).div(dividedBy); |
|
// 这个时候取一半作为利润点吧。 |
|
y = y.div(2); |
|
} |
|
else { |
|
y = 0; |
|
} |
|
// uint rest = 997yc / (1000d + 997y) - 1000ay / 997(b - y) + 1; |
|
// z = uint(997).mul(y).mul(c).div(uint(1000).mul(d).add(uint(997).mul(y))); |
|
// x = uint(1000).mul(a).mul(y).div(uint(997).mul(uint(b).sub(y))); |
|
} |
|
|
|
// function uint2str(uint256 _i) internal pure returns (string memory str) |
|
// { |
|
// if (_i == 0) { |
|
// return "0"; |
|
// } |
|
// uint256 j = _i; |
|
// uint256 length; |
|
// while (j != 0) { |
|
// length++; |
|
// j /= 10; |
|
// } |
|
// bytes memory bstr = new bytes(length); |
|
// uint256 k = length; |
|
// j = _i; |
|
// while (j != 0) { |
|
// bstr[--k] = bytes1(uint8(48 + j % 10)); |
|
// j /= 10; |
|
// } |
|
// str = string(bstr); |
|
// } |
|
|
|
function swapCallback(address sender, uint amount0, uint amount1, bytes calldata data) |
|
internal { |
|
// address pairFrom = 0xB742e08FF92178B9c45e342b7D4235E126300777; // gas saving |
|
uint _y = gy; // gas saving |
|
bool reverse = false; |
|
bytes1 data0 = data[0]; |
|
if (data0 == bytes1('1')) { |
|
reverse = true; |
|
} |
|
else if (data0 == bytes1('0')) { |
|
reverse = false; |
|
} |
|
// require(data.length == 0, uint2str(data.length)); |
|
// require(data.length != 0, uint2str(data.length)); |
|
|
|
bytes calldata bytesPairFrom = data[1:21]; |
|
address pairFrom = bytesToAddress(bytesPairFrom); |
|
|
|
bytes calldata bytesInput = data[21:41]; |
|
address input = bytesToAddress(bytesInput); |
|
// 回调第1步,将闪电借的币种给第1池子。 |
|
{ |
|
bool transfered = IERC20(input).transfer(pairFrom, uint(gx).add(1)); |
|
require(transfered, 'swapCallback 1'); |
|
// // bytes4(keccak256(bytes('transfer(address,uint256)'))); |
|
// // address(input).call(abi.encodeWithSelector(0xa9059cbb, pairFrom, x)); |
|
// (bool success, bytes memory data1) = address(input).call(abi.encodeWithSelector(0xa9059cbb, pairFrom, x)); |
|
// require(success && (data1.length == 0 || abi.decode(data1, (bool))), 'swapCallback 1'); |
|
} |
|
|
|
// 回调第2步,从第1个池子拿钱还给2 |
|
{ |
|
// (uint amount0OutB, uint amount1OutB) = (token0 == input) ? (uint(0), uint(_y)) : (uint(_y), uint(0)); |
|
(uint amount0OutB, uint amount1OutB) = reverse ? (uint(_y), uint(0)) : (uint(0), uint(_y)); |
|
// 回调第三部,从另一个池子拿钱 |
|
V5IICherryPair(pairFrom).swap(amount0OutB, amount1OutB, msg.sender, new bytes(0)); |
|
} |
|
} |
|
|
|
function lottoswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function ogeeswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function flyCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function xfswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function joinswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function hubDaoCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function QkswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function YouSwapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function complusV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function swapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function DepthswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function hdexV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function LavaSwapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function butterCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function makiswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function pancakeCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function MdisCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function elkCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function PHOswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function hswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function kisSwapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function myswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function PippiCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function KswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function islandCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function jwapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function goswapCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function UnoxCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
function cherryCall(address sender, uint amount0, uint amount1, bytes calldata data) |
|
external |
|
{ |
|
swapCallback(sender, amount0, amount1, data); |
|
} |
|
|
|
// Copies 'len' bytes from 'self' into a new 'bytes memory', starting at index '0'. |
|
// Returns the newly created 'bytes memory' |
|
// The returned bytes will be of length 'len'. |
|
function toBytes(bytes32 self, uint8 len) internal pure returns (bytes memory bts) { |
|
require(len <= 32); |
|
bts = new bytes(len); |
|
// Even though the bytes will allocate a full word, we don't want |
|
// any potential garbage bytes in there. |
|
uint data = uint(self) & ~uint(0) << (32 - len)*8; |
|
assembly { |
|
mstore(add(bts, /*BYTES_HEADER_SIZE*/32), data) |
|
} |
|
} |
|
|
|
function addressToBytes(address self) internal pure returns (bytes memory bts) { |
|
bts = toBytes(bytes32(uint(self) << 96), 20); |
|
} |
|
|
|
function bytesToAddress(bytes memory _bytes) internal pure returns (address) { |
|
address tempAddress; |
|
|
|
assembly { |
|
tempAddress := div(mload(add(add(_bytes, 0x20), 0)), 0x1000000000000000000000000) |
|
} |
|
|
|
return tempAddress; |
|
} |
|
|
|
function concat(bytes memory a, bytes memory b) |
|
internal pure returns (bytes memory) { |
|
return abi.encodePacked(a, b); |
|
} |
|
|
|
// function uintToBytes0(uint _num) public returns (bytes memory _ret) { |
|
// assembly { |
|
// _ret := mload(0x10) |
|
// mstore(_ret, 0x20) |
|
// mstore(add(_ret, 0x20), _num) |
|
// } |
|
// } |
|
|
|
function buildSwapBytes(bool reverse, address pairFrom, address input, uint x, uint y) internal returns (bytes memory) { |
|
bytes memory bytesReverse = new bytes(1); |
|
bytesReverse[0] = reverse ? bytes1('1') : bytes1('0'); |
|
|
|
bytes memory bytesPairFrom = addressToBytes(pairFrom); |
|
bytes memory bytesInput = addressToBytes(input); |
|
|
|
bytes memory allBytes = concat(concat(bytesReverse, bytesPairFrom), bytesInput); |
|
return allBytes; |
|
} |
|
|
|
function checkAndMint(bool reverse, uint minRest, address input, address pairFrom, address pairTo) internal returns (bool) { |
|
uint112 a; |
|
uint112 b; |
|
uint112 c; |
|
uint112 d; |
|
if (reverse) { |
|
(b, a,) = V5IICherryPair(pairFrom).getReserves(); |
|
(d, c,) = V5IICherryPair(pairTo).getReserves(); |
|
} |
|
else { |
|
(a, b,) = V5IICherryPair(pairFrom).getReserves(); |
|
(c, d,) = V5IICherryPair(pairTo).getReserves(); |
|
} |
|
|
|
uint y = getRestY(uint(a), uint(b), uint(c), uint(d)); |
|
if (y <= 0) { |
|
return false; |
|
} |
|
|
|
uint x = getAmountIn(y, a, b); |
|
uint z = getAmountOut(y, d, c); |
|
|
|
if (z > x) { |
|
if (z.sub(x) > minRest) { |
|
bytes memory databytes = buildSwapBytes(reverse, pairFrom, input, x, y); |
|
|
|
(uint amount0Out, uint amount1Out) = reverse ? (uint(0), uint(z)) : (uint(z), uint(0)) ; |
|
// bytes memory databytes = new bytes(1); |
|
// databytes[0] = reverse ? bytes1('1') : bytes1('0'); |
|
// // bytes allBytes = databytes = bytesConcat(databytes, ) |
|
|
|
|
|
// todo: 将信息存储到回调函数,避免读取内存消耗gas。但是这个后期再弄看看。 |
|
// bytes memory data = bytes32(uint256(uint160(addr)) << 96); |
|
// 第一步,从第二个池子里面闪电借出来。 |
|
// require(amount0Out > 0 || amount1Out > 0, 'need amount0Out or amount1Out > 0'); |
|
gx = x; |
|
gy = y; |
|
|
|
// 这里应该加锁的。还得判断是否成功,不然reverse,但是谁会乱搞? |
|
V5IICherryPair(pairTo).swap(amount0Out, amount1Out, address(this), databytes); |
|
// pairFrom = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
function mint(bool reverse, uint minRest, address input, address[] calldata pairs) external { |
|
uint allLength = pairs.length; |
|
// uint mintenTime = 0; |
|
for (uint i = 0;i < allLength - 1; i++) { |
|
address pairFrom = pairs[i]; |
|
address pairTo = pairs[i + 1]; |
|
bool minted = checkAndMint(reverse, minRest, input, pairFrom, pairTo); |
|
// // 看看反过来有没有差价 |
|
if (!minted) { |
|
minted = checkAndMint(reverse, minRest, input, pairTo, pairFrom); |
|
} |
|
|
|
// 已经参与过了,调出循环 |
|
if (minted) { |
|
i = allLength; |
|
} |
|
|
|
// 如果已经有差价了,那就重新进行计算。拿到最大的利润 |
|
// if (minted) { |
|
// i = 0; |
|
// minted = false; |
|
// mintenTime += 1; |
|
// } |
|
// // todo 生产需要去掉 |
|
// uint balance = IERC20(input).balanceOf(address(this)); |
|
// if (balance > 0) { |
|
// address owner = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
// IERC20(input).transfer(owner, balance); |
|
// } |
|
} |
|
// gmintenTime = mintenTime; |
|
} |
|
|
|
// 不要判断,直接进行钱的输出,但是只输出到 god |
|
function transferAll(address token) external { |
|
address owner = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
IERC20(token).transfer(owner, IERC20(token).balanceOf(address(this))); |
|
} |
|
|
|
// 不要判断,直接进行钱的输出,但是只输出到 god |
|
function transfer(address token, uint256 amount) external { |
|
address owner = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
IERC20(token).transfer(owner, amount); |
|
// // bytes4(keccak256(bytes('transfer(address,uint256)'))); |
|
// token.call(abi.encodeWithSelector(0xa9059cbb, owner, amount)); |
|
|
|
// (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, owner, amount)); |
|
// require(success && (data.length == 0 || abi.decode(data, (bool))), 'send1: TRANSFER_FAILED'); |
|
} |
|
|
|
// 不要判断,直接进行钱的输出,但是只输出到 god |
|
function send() external { |
|
address payable owner = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
owner.transfer(address(this).balance); |
|
} |
|
|
|
receive() external payable { |
|
address payable owner = 0xB742e08FF92178B9c45e342b7D4235E126300777; |
|
owner.transfer(address(this).balance); |
|
} |
|
} |