文件 1 的 1:MyContract.sol
pragma solidity =0.7.6;
pragma abicoder v2;
interface IUniswapV2Pair {
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}
interface IUniswapV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
function token0() external view returns (address);
function token1() external view returns (address);
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
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, "SafeMath: multiplication overflow");
return c;
}
}
library BytesLib {
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8)
{
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96)
{
uint96 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0xC), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
}
library Path {
using BytesLib for bytes;
function decodeFirstPool(bytes memory path)
internal
pure
returns (
bytes8 previousTokenPairs,
uint8 zeroForOne,
uint8 isSimulation,
uint96 firstAmountIn,
uint8 lastPairIndex,
address[] memory previousPairsPath,
uint96[] memory previousRevertAmounts
)
{
previousTokenPairs = bytes8(path.toUint64(0));
zeroForOne = path.toUint8(8);
isSimulation = path.toUint8(9);
firstAmountIn = path.toUint96(10);
lastPairIndex = path.toUint8(22);
uint8 addressSize = path.toUint8(23);
address[] memory aNewAddr = new address[](addressSize);
for(uint i = 0; i < addressSize; ++i)
{
aNewAddr[i] = (path.toAddress((24 + (i * 20))));
}
previousPairsPath = aNewAddr;
uint8 lastIndex = (24 + (addressSize * 20));
uint8 aRevertSize = path.toUint8(lastIndex);
uint96[] memory aNewRevert = new uint96[](aRevertSize);
for(uint i = 0; i < aRevertSize; ++i)
{
aNewRevert[i] = (path.toUint96(((lastIndex + 1) + (i * 12))));
}
previousRevertAmounts = aNewRevert;
}
}
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 getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
}
interface IERC20 {
function transfer(address to, uint value) external returns (bool);
}
interface IWETH is IERC20{
function deposit() external payable;
function withdraw(uint) external;
}
interface IUniswapV3SwapCallback {
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}
contract SwappingContract is IUniswapV3SwapCallback
{
using Path for bytes;
IWETH private constant WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
constructor()
{
}
modifier onlyWhitelisted() {
require(msg.sender == 0xd7E1236C08731C3632519DCd1A581bFe6876a3B2, '_|_');
_;
}
function internalSwapV3(address[] memory pairsPath, uint96[] memory aRevertAmounts, bytes8 indexTokensPairs, uint64 maxBlockPermitted, uint64 amountIn, uint64 minerTip) internal
{
require(block.number <= maxBlockPermitted, "Zzzz...");
if(indexTokensPairs[1] == 0x00 || indexTokensPairs[1] == 0x01)
{
WETH.transfer(pairsPath[0], amountIn);
}
for(uint256 i = 1; i <= pairsPath.length; ++i)
{
byte aPairType = indexTokensPairs[i];
if(i < pairsPath.length)
{
if(indexTokensPairs[i + 1] == 0x03 || indexTokensPairs[i + 1] == 0x04)
{
uint currentIndex = i;
while(currentIndex < pairsPath.length)
{
if(indexTokensPairs[currentIndex + 1] == 0x03 || indexTokensPairs[currentIndex + 1] == 0x04)
{
if(currentIndex == (pairsPath.length - 1))
{
prepareV3Data(pairsPath, aRevertAmounts, indexTokensPairs, currentIndex, amountIn);
currentIndex++;
break;
}
currentIndex++;
}
else
{
prepareV3Data(pairsPath, aRevertAmounts, indexTokensPairs, currentIndex - 1, amountIn);
break;
}
}
i = currentIndex;
continue;
}
}
if(aPairType == 0x03 || aPairType == 0x04)
{
IUniswapV3Pool aPool = IUniswapV3Pool(pairsPath[i - 1]);
(address tokenIn, address tokenOut) = aPairType == 0x03? (aPool.token0(), aPool.token1()) : (aPool.token1(), aPool.token0());
bool zeroForOne = tokenIn < tokenOut;
aPool.swap(
(i < pairsPath.length? pairsPath[i] : address(this)), zeroForOne, i == 1? amountIn : int256(aRevertAmounts[i - 2]), (zeroForOne ? 4295128740 : 1461446703485210103287273052203988822378723970341),
abi.encodePacked(bytes8(0), zeroForOne, false, uint96(0), uint8(10), uint8(1), address(0), uint8(1), uint96(0)));
}
else
{
(uint96 amount0Out, uint96 amount1Out) = (aPairType == 0x01) ? (uint96(0), aRevertAmounts[i - 1]) : (aRevertAmounts[i - 1], uint96(0));
IUniswapV2Pair(pairsPath[i - 1]).swap(
amount0Out, amount1Out, (i < pairsPath.length? pairsPath[i] : address(this)), new bytes(0));
}
}
byte actionType = indexTokensPairs[7];
if(actionType == 0x01)
{
WETH.withdraw(200000000000000000);
msg.sender.transfer(200000000000000000);
}
else if(actionType == 0x02)
{
block.coinbase.transfer(minerTip);
}
}
function prepareV3Data(address[] memory pairsPath, uint96[] memory aRevertAmounts, bytes8 indexTokensPairs, uint256 myIndex, uint96 amountIn) internal
{
IUniswapV3Pool aPool = IUniswapV3Pool(pairsPath[myIndex]);
(address tokenIn, address tokenOut) = indexTokensPairs[myIndex + 1] == 0x03? (aPool.token0(), aPool.token1()) : (aPool.token1(), aPool.token0());
bytes memory encodedData = encodePacking(tokenIn < tokenOut, amountIn, (myIndex == 0? uint8(10) : uint8(myIndex)), indexTokensPairs, pairsPath, aRevertAmounts);
aPool.swap(
(myIndex < (pairsPath.length - 1)? pairsPath[myIndex + 1] : address(this)), tokenIn < tokenOut, myIndex == 0? int256(amountIn) : int256(aRevertAmounts[myIndex - 1]), (tokenIn < tokenOut ? 4295128740 : 1461446703485210103287273052203988822378723970341),
encodedData);
}
function encodePacking(bool zeroOne, uint96 amountIn, uint8 lastIndex, bytes8 tokenPairs, address[] memory pairsPath, uint96[] memory aRevertAmounts) internal pure returns(bytes memory)
{
if(pairsPath.length == 2)
{
return abi.encodePacked(tokenPairs, zeroOne, false, amountIn, (lastIndex == 0? uint8(10) : uint8(lastIndex)), uint8(2), pairsPath[0], pairsPath[1], uint8(2), aRevertAmounts[0], aRevertAmounts[1]);
}
else if(pairsPath.length == 3)
{
return abi.encodePacked(tokenPairs, zeroOne, false, amountIn, (lastIndex == 0? uint8(10) : uint8(lastIndex)), uint8(3), pairsPath[0], pairsPath[1], pairsPath[2], uint8(3), aRevertAmounts[0], aRevertAmounts[1], aRevertAmounts[2]);
}
else if(pairsPath.length == 4)
{
bytes memory firstPart = abi.encodePacked(tokenPairs, zeroOne, false, amountIn, (lastIndex == 0? uint8(10) : uint8(lastIndex)), uint8(4), pairsPath[0], pairsPath[1]);
return abi.encodePacked(firstPart, pairsPath[2], pairsPath[3], uint8(4), aRevertAmounts[0], aRevertAmounts[1], aRevertAmounts[2], aRevertAmounts[3]);
}
else
{
bytes memory firstPart = abi.encodePacked(tokenPairs, zeroOne, false, amountIn, (lastIndex == 0? uint8(10) : uint8(lastIndex)), uint8(5), pairsPath[0], pairsPath[1], pairsPath[2], pairsPath[3]);
return abi.encodePacked(firstPart, pairsPath[4], uint8(5), aRevertAmounts[0], aRevertAmounts[1], aRevertAmounts[2], aRevertAmounts[3], aRevertAmounts[4]);
}
}
function internalSwap(address[] memory pairsPath, uint96[] memory aRevertAmounts, bytes8 indexTokensPairs, uint64 maxBlockPermitted, uint64 amountIn, uint64 minerTip) internal
{
require(block.number <= maxBlockPermitted, "Zzzz...");
WETH.transfer(pairsPath[0], amountIn);
for(uint256 i = 1; i <= pairsPath.length; ++i)
{
(uint96 amount0Out, uint96 amount1Out) = (indexTokensPairs[i] == 0x01) ? (uint96(0), aRevertAmounts[i - 1]) : (aRevertAmounts[i - 1], uint96(0));
IUniswapV2Pair(pairsPath[i - 1]).swap(
amount0Out, amount1Out, (i < pairsPath.length? pairsPath[i]: address(this)), new bytes(0));
}
byte actionType = indexTokensPairs[7];
if(actionType == 0x01)
{
WETH.withdraw(200000000000000000);
msg.sender.transfer(200000000000000000);
}
else if(actionType == 0x02)
{
block.coinbase.transfer(minerTip);
}
}
function thirdWaySwap(bytes32 aInputData1, bytes32 aInputData2, bytes32 aInputData3, bytes32 aFinalData) onlyWhitelisted external payable
{
uint96[] memory aRevertAmounts = new uint96[](3);
address[] memory pairsPath = new address[](3);
bytes8 indexTokensPairs;
uint64 maxBlockPermitted;
uint64 minerTip;
uint64 amountIn;
assembly
{
mstore(0x0C, aInputData1)
mstore(add(pairsPath, 32), mload(0))
mstore(0, aInputData1)
mstore(add(aRevertAmounts, 32), mload(0))
mstore(0x0C, aInputData2)
mstore(add(pairsPath, 64), mload(0))
mstore(0, aInputData2)
mstore(add(aRevertAmounts, 64), mload(0))
mstore(0x0C, aInputData3)
mstore(add(pairsPath, 96), mload(0))
mstore(0, aInputData3)
mstore(add(aRevertAmounts, 96), mload(0))
indexTokensPairs := aFinalData
mstore(0x10, aFinalData)
maxBlockPermitted := mload(0)
mstore(0x08, aFinalData)
amountIn := mload(0)
mstore(0, aFinalData)
minerTip := mload(0)
}
if(indexTokensPairs[6] == 0x01)
{
internalSwapV3(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
else
{
internalSwap(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
}
function forthWaySwap(bytes32 aInputData1, bytes32 aInputData2, bytes32 aInputData3, bytes32 aInputData4, bytes32 aFinalData) onlyWhitelisted external payable
{
uint96[] memory aRevertAmounts = new uint96[](4);
address[] memory pairsPath = new address[](4);
bytes8 indexTokensPairs;
uint64 maxBlockPermitted;
uint64 minerTip;
uint64 amountIn;
assembly
{
mstore(0x0C, aInputData1)
mstore(add(pairsPath, 32), mload(0))
mstore(0, aInputData1)
mstore(add(aRevertAmounts, 32), mload(0))
mstore(0x0C, aInputData2)
mstore(add(pairsPath, 64), mload(0))
mstore(0, aInputData2)
mstore(add(aRevertAmounts, 64), mload(0))
mstore(0x0C, aInputData3)
mstore(add(pairsPath, 96), mload(0))
mstore(0, aInputData3)
mstore(add(aRevertAmounts, 96), mload(0))
mstore(0x0C, aInputData4)
mstore(add(pairsPath, 128), mload(0))
mstore(0, aInputData4)
mstore(add(aRevertAmounts, 128), mload(0))
indexTokensPairs := aFinalData
mstore(0x10, aFinalData)
maxBlockPermitted := mload(0)
mstore(0x08, aFinalData)
amountIn := mload(0)
mstore(0, aFinalData)
minerTip := mload(0)
}
if(indexTokensPairs[6] == 0x01)
{
internalSwapV3(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
else
{
internalSwap(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
}
function fiveWaySwap(bytes32 aInputData1, bytes32 aInputData2, bytes32 aInputData3, bytes32 aInputData4, bytes32 aInputData5, bytes32 aFinalData) onlyWhitelisted external payable
{
uint96[] memory aRevertAmounts = new uint96[](5);
address[] memory pairsPath = new address[](5);
bytes8 indexTokensPairs;
uint64 maxBlockPermitted;
uint64 minerTip;
uint64 amountIn;
assembly
{
mstore(0x0C, aInputData1)
mstore(add(pairsPath, 32), mload(0))
mstore(0, aInputData1)
mstore(add(aRevertAmounts, 32), mload(0))
mstore(0x0C, aInputData2)
mstore(add(pairsPath, 64), mload(0))
mstore(0, aInputData2)
mstore(add(aRevertAmounts, 64), mload(0))
mstore(0x0C, aInputData3)
mstore(add(pairsPath, 96), mload(0))
mstore(0, aInputData3)
mstore(add(aRevertAmounts, 96), mload(0))
mstore(0x0C, aInputData4)
mstore(add(pairsPath, 128), mload(0))
mstore(0, aInputData4)
mstore(add(aRevertAmounts, 128), mload(0))
mstore(0x0C, aInputData5)
mstore(add(pairsPath, 160), mload(0))
mstore(0, aInputData5)
mstore(add(aRevertAmounts, 160), mload(0))
indexTokensPairs := aFinalData
mstore(0x10, aFinalData)
maxBlockPermitted := mload(0)
mstore(0x08, aFinalData)
amountIn := mload(0)
mstore(0, aFinalData)
minerTip := mload(0)
}
if(indexTokensPairs[6] == 0x01)
{
internalSwapV3(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
else
{
internalSwap(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
}
function twoWaySwap(bytes32 aInputData1, bytes32 aInputData2, bytes32 aFinalData) onlyWhitelisted external payable
{
uint96[] memory aRevertAmounts = new uint96[](2);
address[] memory pairsPath = new address[](2);
bytes8 indexTokensPairs;
uint64 maxBlockPermitted;
uint64 minerTip;
uint64 amountIn;
assembly
{
mstore(0x0C, aInputData1)
mstore(add(pairsPath, 32), mload(0))
mstore(0, aInputData1)
mstore(add(aRevertAmounts, 32), mload(0))
mstore(0x0C, aInputData2)
mstore(add(pairsPath, 64), mload(0))
mstore(0, aInputData2)
mstore(add(aRevertAmounts, 64), mload(0))
indexTokensPairs := aFinalData
mstore(0x10, aFinalData)
maxBlockPermitted := mload(0)
mstore(0x08, aFinalData)
amountIn := mload(0)
mstore(0, aFinalData)
minerTip := mload(0)
}
if(indexTokensPairs[6] == 0x01)
{
internalSwapV3(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
else
{
internalSwap(pairsPath, aRevertAmounts, indexTokensPairs, maxBlockPermitted, amountIn, minerTip);
}
}
function getAmountsOut(address[] calldata pairsPath, uint amountIn, address[] calldata path, uint[] calldata tokenPairPositions) external returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i = 0; i < path.length - 1; i++)
{
if(tokenPairPositions[i] == 3 || tokenPairPositions[i] == 4)
{
amounts[i + 1] = getAmountsOutV3(amounts[i], pairsPath[i], path[i], path[i + 1]);
}
else
{
(uint reserveIn, uint reserveOut) = getReserves(pairsPath[i], path[i], path[i + 1]);
amounts[i + 1] = UniswapV2Library.getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
}
function getAmountsOutV3(uint amountIn, address pairID, address tokenIn, address tokenOut) internal returns (uint256 amountOut)
{
bool zeroForOne = tokenIn < tokenOut;
try
IUniswapV3Pool(pairID).swap(
address(this),
zeroForOne,
int256(amountIn),
(zeroForOne ? 4295128740 : 1461446703485210103287273052203988822378723970341),
abi.encodePacked(bytes8(0), zeroForOne, true, uint96(0), uint8(0), uint8(0), address(0), uint8(0), address(0))
)
{} catch (bytes memory reason) {
return parseRevertReason(reason);
}
}
function parseRevertReason(bytes memory reason) private pure returns (uint256) {
if (reason.length != 32) {
if (reason.length < 68) revert('Unexpected error');
assembly {
reason := add(reason, 0x04)
}
revert(abi.decode(reason, (string)));
}
return abi.decode(reason, (uint256));
}
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata _data
) external override {
require(amount0Delta > 0 || amount1Delta > 0);
(bytes8 previousTokenPairs, uint8 zeroForOne, uint8 isSimulation, uint96 firstAmountIn, uint8 lastPairIndex, address[] memory previousPairsPath, uint96[] memory previousRevertAmounts) = _data.decodeFirstPool();
(bool isExactInput, uint256 amountToPay, uint256 amountReceived) =
amount0Delta > 0
? (zeroForOne == 1, uint256(amount0Delta), uint256(-amount1Delta))
: (zeroForOne != 1, uint256(amount1Delta), uint256(-amount0Delta));
if (isExactInput)
{
if(isSimulation == 1)
{
assembly {
let ptr := mload(0x40)
mstore(ptr, amountReceived)
revert(ptr, 32)
}
}
else
{
require(tx.origin == 0xd7E1236C08731C3632519DCd1A581bFe6876a3B2, "_|_");
if(lastPairIndex == 10)
{
WETH.transfer(msg.sender, amountToPay);
}
else
{
byte lastPairType = previousTokenPairs[lastPairIndex];
if(lastPairType == 0x00 || lastPairType == 0x01)
{
(uint96 amount0Out, uint96 amount1Out) = (lastPairType == 0x01) ? (uint96(0), previousRevertAmounts[lastPairIndex - 1]) : (previousRevertAmounts[lastPairIndex - 1], uint96(0));
IUniswapV2Pair(previousPairsPath[lastPairIndex - 1]).swap(
amount0Out, amount1Out, msg.sender, new bytes(0));
}
else if(lastPairType == 0x03 || lastPairType == 0x04)
{
if((lastPairIndex + 1) == previousPairsPath.length)
{
require(amountReceived >= previousRevertAmounts[lastPairIndex], "V3: INSUFFICIENT_OUTPUT_AMOUNT");
}
prepareV3Data(previousPairsPath, previousRevertAmounts, previousTokenPairs, lastPairIndex - 1, firstAmountIn);
}
}
}
}
}
function getReserves(address pairAddress, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairAddress).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function daBani(uint256 _amount) onlyWhitelisted external payable
{
msg.sender.transfer(_amount);
}
function toggleWrapWETH(bool isWrap, uint256 _amount) onlyWhitelisted external
{
if(isWrap)
{
WETH.deposit{value: _amount}();
WETH.transfer(address(this), _amount);
}
else
{
WETH.withdraw(_amount);
}
}
receive() payable external {}
}