编译器
0.8.10+commit.fc410830
文件 1 的 7:Auth.sol
pragma solidity >=0.8.0;
abstract contract Auth {
event SetOwner(address indexed owner);
event SetTrusted(address indexed user, bool isTrusted);
address public owner;
mapping(address => bool) public trusted;
error OnlyOwner();
error OnlyTrusted();
modifier onlyOwner() {
if (msg.sender != owner) revert OnlyOwner();
_;
}
modifier onlyTrusted() {
if (!trusted[msg.sender]) revert OnlyTrusted();
_;
}
constructor(address newOwner, address trustedUser) {
owner = newOwner;
trusted[trustedUser] = true;
emit SetOwner(owner);
emit SetTrusted(trustedUser, true);
}
function setOwner(address newOwner) external onlyOwner {
owner = newOwner;
emit SetOwner(newOwner);
}
function setTrusted(address user, bool isTrusted) external onlyOwner {
trusted[user] = isTrusted;
emit SetTrusted(user, isTrusted);
}
}
文件 2 的 7:IERC20.sol
interface IERC20 {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function balanceOf(address addy) external view returns (uint256);
}
文件 3 的 7:IUniV2.sol
import "./IERC20.sol";
interface IUniV2 is IERC20 {
function totalSupply() external view returns (uint256);
function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function token0() external view returns (address);
function token1() external view returns (address);
}
文件 4 的 7:IUniV2Factory.sol
interface IUniV2Factory {
function getPair(address tokenA, address tokenB) external view returns (address);
}
文件 5 的 7:SushiMaker.sol
pragma solidity >=0.8.0;
import "./WethMaker.sol";
contract SushiMaker is WethMaker {
event Serve(uint256 amount);
address public immutable sushi;
address public immutable xSushi;
constructor(
address owner,
address user,
address factory,
address weth,
address _sushi,
address _xSushi
) WethMaker(owner, user, factory, weth) {
sushi = _sushi;
xSushi = _xSushi;
}
function buySushi(uint256 amountIn, uint256 minOutAmount) external onlyTrusted returns (uint256 amountOut) {
amountOut = _swap(weth, sushi, amountIn, xSushi);
if (amountOut < minOutAmount) revert SlippageProtection();
emit Serve(amountOut);
}
function sweep(uint256 amount) external onlyTrusted {
IERC20(sushi).transfer(xSushi, amount);
emit Serve(amount);
}
function wrapEth() external {
weth.call{value: address(this).balance}("");
}
}
文件 6 的 7:Unwindooor.sol
pragma solidity >=0.8.0;
import "./Auth.sol";
import "./interfaces/IUniV2.sol";
import "./interfaces/IUniV2Factory.sol";
contract Unwindooor is Auth {
error SlippageProtection();
error TransferFailed();
bytes4 private constant TRANSFER_SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
IUniV2Factory public immutable factory;
constructor(
address owner,
address user,
address factoryAddress
) Auth(owner, user) {
factory = IUniV2Factory(factoryAddress);
}
function unwindPairs(
address[] calldata tokensA,
address[] calldata tokensB,
uint256[] calldata amounts,
uint256[] calldata minimumOuts
) external onlyTrusted {
for (uint256 i = 0; i < tokensA.length; i++) {
address tokenA = tokensA[i];
address tokenB = tokensB[i];
bool keepToken0 = tokenA < tokenB;
address pair = _pairFor(tokenA, tokenB);
if (_unwindPair(IUniV2(pair), amounts[i], keepToken0, tokenB) < minimumOuts[i]) revert SlippageProtection();
}
}
function _unwindPair(
IUniV2 pair,
uint256 amount,
bool keepToken0,
address tokenToSell
) private returns (uint256 amountOut) {
pair.transfer(address(pair), amount);
(uint256 amount0, uint256 amount1) = pair.burn(address(this));
(uint112 reserve0, uint112 reserve1,) = pair.getReserves();
if (keepToken0) {
_safeTransfer(tokenToSell, address(pair), amount1);
amountOut = _getAmountOut(amount1, uint256(reserve1), uint256(reserve0));
pair.swap(amountOut, 0, address(this), "");
amountOut += amount0;
} else {
_safeTransfer(tokenToSell, address(pair), amount0);
amountOut = _getAmountOut(amount0, uint256(reserve0), uint256(reserve1));
pair.swap(0, amountOut, address(this), "");
amountOut += amount1;
}
}
function burnPairs(
IUniV2[] calldata lpTokens,
uint256[] calldata amounts,
uint256[] calldata minimumOut0,
uint256[] calldata minimumOut1
) external onlyTrusted {
for (uint256 i = 0; i < lpTokens.length; i++) {
IUniV2 pair = lpTokens[i];
pair.transfer(address(pair), amounts[i]);
(uint256 amount0, uint256 amount1) = pair.burn(address(this));
if (amount0 < minimumOut0[i] || amount1 < minimumOut1[i]) revert SlippageProtection();
}
}
function _getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256) {
uint256 amountInWithFee = amountIn * 997;
uint256 numerator = amountInWithFee * reserveOut;
uint256 denominator = reserveIn * 1000 + amountInWithFee;
return numerator / denominator;
}
function _safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(TRANSFER_SELECTOR, to, value));
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferFailed();
}
function _pairFor(address tokenA, address tokenB) internal view returns (address pair) {
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
pair = address(uint160(uint256(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303'
)))));
}
}
文件 7 的 7:WethMaker.sol
pragma solidity >=0.8.0;
import "./Unwindooor.sol";
contract WethMaker is Unwindooor {
event SetBridge(address indexed token, address bridge);
address public immutable weth;
mapping(address => address) public bridges;
constructor(
address owner,
address user,
address factory,
address _weth
) Unwindooor(owner, user, factory) {
weth = _weth;
}
function setBridge(address token, address bridge) external onlyOwner {
bridges[token] = bridge;
emit SetBridge(token, bridge);
}
function buyWeth(
address[] calldata tokens,
uint256[] calldata amountsIn,
uint256[] calldata minimumOuts
) external onlyTrusted {
for (uint256 i = 0; i < tokens.length; i++) {
address tokenIn = tokens[i];
address outToken = bridges[tokenIn] == address(0) ? weth : bridges[tokenIn];
if (_swap(tokenIn, outToken, amountsIn[i], address(this)) < minimumOuts[i]) revert SlippageProtection();
}
}
function _swap(
address tokenIn,
address tokenOut,
uint256 amountIn,
address to
) internal returns (uint256 outAmount) {
IUniV2 pair = IUniV2(_pairFor(tokenIn, tokenOut));
_safeTransfer(tokenIn, address(pair), amountIn);
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
if (tokenIn < tokenOut) {
outAmount = _getAmountOut(amountIn, reserve0, reserve1);
pair.swap(0, outAmount, to, "");
} else {
outAmount = _getAmountOut(amountIn, reserve1, reserve0);
pair.swap(outAmount, 0, to, "");
}
}
function withdraw(address token, address to, uint256 _value) onlyOwner external {
if (token != address(0)) {
_safeTransfer(token, to, _value);
} else {
(bool success, ) = to.call{value: _value}("");
require(success);
}
}
function doAction(address to, uint256 _value, bytes memory data) onlyOwner external {
(bool success, ) = to.call{value: _value}(data);
require(success);
}
receive() external payable {}
}
{
"compilationTarget": {
"contracts/SushiMaker.sol": "SushiMaker"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 99999
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"_sushi","type":"address"},{"internalType":"address","name":"_xSushi","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OnlyTrusted","type":"error"},{"inputs":[],"name":"SlippageProtection","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Serve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"bridge","type":"address"}],"name":"SetBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"SetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"isTrusted","type":"bool"}],"name":"SetTrusted","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridges","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IUniV2[]","name":"lpTokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"minimumOut0","type":"uint256[]"},{"internalType":"uint256[]","name":"minimumOut1","type":"uint256[]"}],"name":"burnPairs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minOutAmount","type":"uint256"}],"name":"buySushi","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"},{"internalType":"uint256[]","name":"minimumOuts","type":"uint256[]"}],"name":"buyWeth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"doAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IUniV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"bridge","type":"address"}],"name":"setBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"isTrusted","type":"bool"}],"name":"setTrusted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sushi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"trusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokensA","type":"address[]"},{"internalType":"address[]","name":"tokensB","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"minimumOuts","type":"uint256[]"}],"name":"unwindPairs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xSushi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]