编译器
0.8.19+commit.7dd6d404
文件 1 的 4:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Approval(address, address, uint256);
event Transfer(address, address, uint256);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
function transferFrom(address, address, uint256) external returns (bool);
function allowance(address, address) external view returns (uint256);
function approve(address, uint256) external returns (bool);
function transfer(address, uint256) external returns (bool);
function balanceOf(address) external view returns (uint256);
}
文件 2 的 4:IWETH.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface IWETH is IERC20 {
function withdraw(uint256 amount) external;
function deposit() external payable;
}
文件 3 的 4:MeowlRouter.sol
pragma solidity ^0.8.19;
import {IERC20} from "./interfaces/IERC20.sol";
import {SafeTransfer} from "./lib/SafeTransfer.sol";
import {IWETH} from "./interfaces/IWETH.sol";
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;
}
contract MeowlRouter {
using SafeTransfer for IERC20;
using SafeTransfer for IWETH;
address internal immutable feeAddress;
address internal constant WETH9 =
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint32 internal constant FEE_NUMERATOR = 875;
uint32 internal constant FEE_DENOMINATOR = 100000;
event Swap(
address tokenIn,
address tokenOut,
uint actualAmountIn,
uint actualAmountOut,
uint feeAmount
);
constructor() {
feeAddress = msg.sender;
}
receive() external payable {}
function recover(address token) public {
require(msg.sender == feeAddress, "shoo");
if (token == address(0)) {
SafeTransfer.safeTransferETH(msg.sender, address(this).balance);
return;
} else {
IERC20(token).safeTransfer(
msg.sender,
IERC20(token).balanceOf(address(this))
);
}
}
fallback() external payable {
address tokenIn;
address tokenOut;
address pair;
uint minAmountOut;
uint amountIn;
address receiver;
uint feeAmount;
assembly {
tokenIn := shr(96, calldataload(0))
tokenOut := shr(96, calldataload(20))
pair := shr(96, calldataload(40))
minAmountOut := shr(128, calldataload(60))
}
if (address(tokenIn) == WETH9 && msg.value > 0) {
feeAmount = (msg.value * FEE_NUMERATOR) / FEE_DENOMINATOR;
amountIn = msg.value - feeAmount;
IWETH weth = IWETH(WETH9);
weth.deposit{value: amountIn}();
weth.safeTransfer(pair, amountIn);
receiver = msg.sender;
} else {
assembly {
amountIn := shr(128, calldataload(76))
}
IERC20(tokenIn).safeTransferFrom(msg.sender, pair, amountIn);
receiver = address(this);
}
uint reserveIn;
uint reserveOut;
{
(uint reserve0, uint reserve1, ) = IUniswapV2Pair(pair)
.getReserves();
if (tokenIn < tokenOut) {
reserveIn = reserve0;
reserveOut = reserve1;
} else {
reserveIn = reserve1;
reserveOut = reserve0;
}
}
uint actualAmountIn = IERC20(tokenIn).balanceOf(address(pair)) -
reserveIn;
uint amountOut = _getAmountOut(actualAmountIn, reserveIn, reserveOut);
(uint amount0Out, uint amount1Out) = tokenIn < tokenOut
? (uint(0), amountOut)
: (amountOut, uint(0));
uint balBefore = IERC20(tokenOut).balanceOf(address(receiver));
IUniswapV2Pair(pair).swap(
amount0Out,
amount1Out,
receiver,
new bytes(0)
);
uint actualAmountOut = IERC20(tokenOut).balanceOf(address(receiver)) -
balBefore;
require(actualAmountOut >= minAmountOut, "Too little received");
if (receiver == address(this)) {
if (tokenOut == WETH9) {
IWETH(WETH9).withdraw(amountOut);
feeAmount = (actualAmountOut * FEE_NUMERATOR) / FEE_DENOMINATOR;
SafeTransfer.safeTransferETH(msg.sender, amountOut - feeAmount);
} else {
feeAmount = (actualAmountOut * FEE_NUMERATOR) / FEE_DENOMINATOR;
IERC20(tokenOut).safeTransfer(
msg.sender,
actualAmountOut - feeAmount
);
}
}
emit Swap(
tokenIn,
tokenOut,
actualAmountIn,
actualAmountOut,
feeAmount
);
}
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 * 997;
uint numerator = amountInWithFee * reserveOut;
uint denominator = reserveIn * 1000 + amountInWithFee;
amountOut = numerator / denominator;
}
}
文件 4 的 4:SafeTransfer.sol
pragma solidity >=0.8.0;
import "../interfaces/IERC20.sol";
library SafeTransfer {
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
(bool s, ) = address(token).call(
abi.encodeWithSelector(
IERC20.transferFrom.selector,
from,
to,
value
)
);
require(s, "safeTransferFrom failed");
}
function safeTransfer(IERC20 token, address to, uint256 value) internal {
(bool s, ) = address(token).call(
abi.encodeWithSelector(IERC20.transfer.selector, to, value)
);
require(s, "safeTransfer failed");
}
function safeApprove(IERC20 token, address to, uint256 value) internal {
(bool s, ) = address(token).call(
abi.encodeWithSelector(IERC20.approve.selector, to, value)
);
require(s, "safeApprove failed");
}
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
}
{
"compilationTarget": {
"contracts/MeowlRouter.sol": "MeowlRouter"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"actualAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualAmountOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"Swap","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]