编译器
0.8.20+commit.a1b79de6
文件 1 的 10:DecimalMath.sol
pragma solidity >=0.8.0;
import {Math} from "/mimswap/libraries/Math.sol";
library DecimalMath {
using Math for uint256;
uint256 internal constant ONE = 10 ** 18;
uint256 internal constant ONE2 = 10 ** 36;
function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return (target * d) / ONE;
}
function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return (target * d).divCeil(ONE);
}
function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return (target * ONE) / d;
}
function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return (target * ONE).divCeil(d);
}
function reciprocalFloor(uint256 target) internal pure returns (uint256) {
return ONE2 / target;
}
function reciprocalCeil(uint256 target) internal pure returns (uint256) {
return ONE2.divCeil(target);
}
function powFloor(uint256 target, uint256 e) internal pure returns (uint256) {
if (e == 0) {
return 10 ** 18;
} else if (e == 1) {
return target;
} else {
uint p = powFloor(target, e / 2);
p = (p * p) / ONE;
if (e % 2 == 1) {
p = (p * target) / ONE;
}
return p;
}
}
}
文件 2 的 10:IERC20.sol
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
文件 3 的 10:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 4 的 10:IFactory.sol
pragma solidity >=0.8.0;
interface IFactory {
function predictDeterministicAddress(
address creator,
address baseToken_,
address quoteToken_,
uint256 lpFeeRate_,
uint256 i_,
uint256 k_
) external view returns (address);
function maintainerFeeRateModel() external view returns (address);
function create(
address baseToken_,
address quoteToken_,
uint256 lpFeeRate_,
uint256 i_,
uint256 k_,
bool protocolOwnedPool_
) external returns (address clone);
function poolExists(address pool) external view returns (bool);
function addPool(address creator, address baseToken, address quoteToken, address pool) external;
}
文件 5 的 10:IMagicLP.sol
pragma solidity >=0.8.0;
interface IMagicLP {
function _BASE_TOKEN_() external view returns (address);
function _QUOTE_TOKEN_() external view returns (address);
function _BASE_RESERVE_() external view returns (uint112);
function _QUOTE_RESERVE_() external view returns (uint112);
function _BASE_TARGET_() external view returns (uint112);
function _QUOTE_TARGET_() external view returns (uint112);
function _I_() external view returns (uint256);
function getReserves() external view returns (uint256 baseReserve, uint256 quoteReserve);
function totalSupply() external view returns (uint256 totalSupply);
function init(
address baseTokenAddress,
address quoteTokenAddress,
uint256 lpFeeRate,
address mtFeeRateModel,
uint256 i,
uint256 k,
bool protocolOwnedPool
) external;
function sellBase(address to) external returns (uint256 receiveQuoteAmount);
function sellQuote(address to) external returns (uint256 receiveBaseAmount);
function flashLoan(uint256 baseAmount, uint256 quoteAmount, address assetTo, bytes calldata data) external;
function buyShares(address to) external returns (uint256 shares, uint256 baseInput, uint256 quoteInput);
function sellShares(
uint256 shareAmount,
address to,
uint256 baseMinAmount,
uint256 quoteMinAmount,
bytes calldata data,
uint256 deadline
) external returns (uint256 baseAmount, uint256 quoteAmount);
function MIN_LP_FEE_RATE() external view returns (uint256);
function MAX_LP_FEE_RATE() external view returns (uint256);
function _PAUSED_() external view returns (bool);
function setPaused(bool paused) external;
}
文件 6 的 10:IWETH.sol
pragma solidity >=0.8.0;
import {IERC20} from "BoringSolidity/interfaces/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
interface IWETHAlike is IWETH {}
文件 7 的 10:Math.sol
pragma solidity >=0.8.0;
import {DecimalMath} from "/mimswap/libraries/DecimalMath.sol";
library Math {
error ErrIsZero();
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 quotient = a / b;
uint256 remainder = a - quotient * b;
if (remainder > 0) {
return quotient + 1;
} else {
return quotient;
}
}
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
function _GeneralIntegrate(uint256 V0, uint256 V1, uint256 V2, uint256 i, uint256 k) internal pure returns (uint256) {
if (V0 == 0) {
revert ErrIsZero();
}
uint256 fairAmount = i * (V1 - V2);
if (k == 0) {
return fairAmount / DecimalMath.ONE;
}
uint256 V0V0V1V2 = DecimalMath.divFloor((V0 * V0) / V1, V2);
uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2);
return (((DecimalMath.ONE - k) + penalty) * fairAmount) / DecimalMath.ONE2;
}
function _SolveQuadraticFunctionForTarget(uint256 V1, uint256 delta, uint256 i, uint256 k) internal pure returns (uint256) {
if (k == 0) {
return V1 + DecimalMath.mulFloor(i, delta);
}
if (V1 == 0) {
return 0;
}
uint256 _sqrt;
uint256 ki = (4 * k) * i;
if (ki == 0) {
_sqrt = DecimalMath.ONE;
} else if ((ki * delta) / ki == delta) {
_sqrt = sqrt(((ki * delta) / V1) + DecimalMath.ONE2);
} else {
_sqrt = sqrt(((ki / V1) * delta) + DecimalMath.ONE2);
}
uint256 premium = DecimalMath.divFloor(_sqrt - DecimalMath.ONE, k * 2) + DecimalMath.ONE;
return DecimalMath.mulFloor(V1, premium);
}
function _SolveQuadraticFunctionForTrade(uint256 V0, uint256 V1, uint256 delta, uint256 i, uint256 k) internal pure returns (uint256) {
if (V0 == 0) {
revert ErrIsZero();
}
if (delta == 0) {
return 0;
}
if (k == 0) {
return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta);
}
if (k == DecimalMath.ONE) {
uint256 temp;
uint256 idelta = i * delta;
if (idelta == 0) {
temp = 0;
} else if ((idelta * V1) / idelta == V1) {
temp = (idelta * V1) / (V0 * V0);
} else {
temp = (((delta * V1) / V0) * i) / V0;
}
return (V1 * temp) / (temp + DecimalMath.ONE);
}
uint256 part2 = (((k * V0) / V1) * V0) + (i * delta);
uint256 bAbs = (DecimalMath.ONE - k) * V1;
bool bSig;
if (bAbs >= part2) {
bAbs = bAbs - part2;
bSig = false;
} else {
bAbs = part2 - bAbs;
bSig = true;
}
bAbs = bAbs / DecimalMath.ONE;
uint256 squareRoot = DecimalMath.mulFloor((DecimalMath.ONE - k) * 4, DecimalMath.mulFloor(k, V0) * V0);
squareRoot = sqrt((bAbs * bAbs) + squareRoot);
uint256 denominator = (DecimalMath.ONE - k) * 2;
uint256 numerator;
if (bSig) {
numerator = squareRoot - bAbs;
if (numerator == 0) {
revert ErrIsZero();
}
} else {
numerator = bAbs + squareRoot;
}
uint256 V2 = DecimalMath.divCeil(numerator, denominator);
if (V2 > V1) {
return 0;
} else {
return V1 - V2;
}
}
}
文件 8 的 10:ReentrancyGuard.sol
pragma solidity ^0.8.4;
abstract contract ReentrancyGuard {
error Reentrancy();
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;
modifier nonReentrant() virtual {
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06)
revert(0x1c, 0x04)
}
sstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
assembly {
sstore(_REENTRANCY_GUARD_SLOT, codesize())
}
}
modifier nonReadReentrant() virtual {
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06)
revert(0x1c, 0x04)
}
}
_;
}
}
文件 9 的 10:Router.sol
pragma solidity >=0.8.0;
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {IERC20} from "openzeppelin-contracts/interfaces/IERC20.sol";
import {Math} from "/mimswap/libraries/Math.sol";
import {DecimalMath} from "/mimswap/libraries/DecimalMath.sol";
import {IWETH} from "interfaces/IWETH.sol";
import {IMagicLP} from "/mimswap/interfaces/IMagicLP.sol";
import {IFactory} from "/mimswap/interfaces/IFactory.sol";
import {IERC20Metadata} from "openzeppelin-contracts/interfaces/IERC20Metadata.sol";
import {ReentrancyGuard} from "solady/utils/ReentrancyGuard.sol";
struct AddLiquidityImbalancedParams {
address lp;
address to;
uint256 baseInAmount;
uint256 quoteInAmount;
bool remainingAmountToSwapIsBase;
uint256 remainingAmountToSwap;
uint256 minimumShares;
uint256 deadline;
}
contract Router is ReentrancyGuard {
using SafeTransferLib for address;
using SafeTransferLib for address payable;
error ErrNotETHLP();
error ErrExpired();
error ErrZeroAddress();
error ErrPathTooLong();
error ErrEmptyPath();
error ErrBadPath();
error ErrTooHighSlippage(uint256 amountOut);
error ErrInvalidBaseToken();
error ErrInvalidQuoteToken();
error ErrInTokenNotETH();
error ErrOutTokenNotETH();
error ErrInvalidQuoteTarget();
error ErrZeroDecimals();
error ErrTooLargeDecimals();
error ErrDecimalsDifferenceTooLarge();
error ErrUnknownPool();
uint256 public constant MAX_BASE_QUOTE_DECIMALS_DIFFERENCE = 12;
IWETH public immutable weth;
IFactory public immutable factory;
receive() external payable {}
constructor(IWETH weth_, IFactory factory_) {
if (address(weth_) == address(0) || address(factory_) == address(0)) {
revert ErrZeroAddress();
}
weth = weth_;
factory = factory_;
}
modifier ensureDeadline(uint256 deadline) {
if (block.timestamp > deadline) {
revert ErrExpired();
}
_;
}
modifier onlyKnownPool(address pool) {
if (!factory.poolExists(pool)) {
revert ErrUnknownPool();
}
_;
}
function createPool(
address baseToken,
address quoteToken,
uint256 lpFeeRate,
uint256 i,
uint256 k,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
bool protocolOwnedPool
) public virtual returns (address clone, uint256 shares) {
_validateDecimals(IERC20Metadata(baseToken).decimals(), IERC20Metadata(quoteToken).decimals());
clone = IFactory(factory).create(baseToken, quoteToken, lpFeeRate, i, k, protocolOwnedPool);
baseToken.safeTransferFrom(msg.sender, clone, baseInAmount);
quoteToken.safeTransferFrom(msg.sender, clone, quoteInAmount);
(shares, , ) = IMagicLP(clone).buyShares(to);
}
function createPoolETH(
address token,
bool useTokenAsQuote,
uint256 lpFeeRate,
uint256 i,
uint256 k,
address to,
uint256 tokenInAmount,
bool protocolOwnedPool
) public payable virtual returns (address clone, uint256 shares) {
if (useTokenAsQuote) {
_validateDecimals(18, IERC20Metadata(token).decimals());
} else {
_validateDecimals(IERC20Metadata(token).decimals(), 18);
}
clone = IFactory(factory).create(
useTokenAsQuote ? address(weth) : token,
useTokenAsQuote ? token : address(weth),
lpFeeRate,
i,
k,
protocolOwnedPool
);
weth.deposit{value: msg.value}();
token.safeTransferFrom(msg.sender, clone, tokenInAmount);
address(weth).safeTransfer(clone, msg.value);
(shares, , ) = IMagicLP(clone).buyShares(to);
}
function previewCreatePool(
uint256 i,
uint256 baseInAmount,
uint256 quoteInAmount
) external pure returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares) {
shares = quoteInAmount < DecimalMath.mulFloor(baseInAmount, i) ? DecimalMath.divFloor(quoteInAmount, i) : baseInAmount;
baseAdjustedInAmount = shares;
quoteAdjustedInAmount = DecimalMath.mulFloor(shares, i);
if (shares <= 2001) {
return (0, 0, 0);
}
shares -= 1001;
}
function addLiquidity(
address lp,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 minimumShares,
uint256 deadline
)
public
virtual
ensureDeadline(deadline)
onlyKnownPool(lp)
returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
{
(baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, baseInAmount, quoteInAmount);
IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, baseAdjustedInAmount);
IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, quoteAdjustedInAmount);
shares = _addLiquidity(lp, to, minimumShares);
}
function addLiquidityUnsafe(
address lp,
address to,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 minimumShares,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 shares) {
IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, baseInAmount);
IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, quoteInAmount);
return _addLiquidity(lp, to, minimumShares);
}
function addLiquidityETH(
address lp,
address to,
address payable refundTo,
uint256 tokenInAmount,
uint256 minimumShares,
uint256 deadline
)
public
payable
virtual
nonReentrant
ensureDeadline(deadline)
onlyKnownPool(lp)
returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
{
uint256 wethAdjustedAmount;
uint256 tokenAdjustedAmount;
address token = IMagicLP(lp)._BASE_TOKEN_();
if (token == address(weth)) {
token = IMagicLP(lp)._QUOTE_TOKEN_();
(baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, msg.value, tokenInAmount);
wethAdjustedAmount = baseAdjustedInAmount;
tokenAdjustedAmount = quoteAdjustedInAmount;
} else if (IMagicLP(lp)._QUOTE_TOKEN_() == address(weth)) {
(baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, tokenInAmount, msg.value);
wethAdjustedAmount = quoteAdjustedInAmount;
tokenAdjustedAmount = baseAdjustedInAmount;
} else {
revert ErrNotETHLP();
}
weth.deposit{value: wethAdjustedAmount}();
address(weth).safeTransfer(lp, wethAdjustedAmount);
if (msg.value > wethAdjustedAmount) {
refundTo.safeTransferETH(msg.value - wethAdjustedAmount);
}
token.safeTransferFrom(msg.sender, lp, tokenAdjustedAmount);
shares = _addLiquidity(lp, to, minimumShares);
}
function addLiquidityETHUnsafe(
address lp,
address to,
uint256 tokenInAmount,
uint256 minimumShares,
uint256 deadline
) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 shares) {
address token = IMagicLP(lp)._BASE_TOKEN_();
if (token == address(weth)) {
token = IMagicLP(lp)._QUOTE_TOKEN_();
} else if (IMagicLP(lp)._QUOTE_TOKEN_() != address(weth)) {
revert ErrNotETHLP();
}
weth.deposit{value: msg.value}();
address(weth).safeTransfer(lp, msg.value);
token.safeTransferFrom(msg.sender, lp, tokenInAmount);
return _addLiquidity(lp, to, minimumShares);
}
function previewRemoveLiquidity(
address lp,
uint256 sharesIn
) external view nonReadReentrant onlyKnownPool(lp) returns (uint256 baseAmountOut, uint256 quoteAmountOut) {
uint256 baseBalance = IMagicLP(lp)._BASE_TOKEN_().balanceOf(address(lp));
uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp));
uint256 totalShares = IERC20(lp).totalSupply();
baseAmountOut = (baseBalance * sharesIn) / totalShares;
quoteAmountOut = (quoteBalance * sharesIn) / totalShares;
}
function removeLiquidity(
address lp,
address to,
uint256 sharesIn,
uint256 minimumBaseAmount,
uint256 minimumQuoteAmount,
uint256 deadline
) public virtual onlyKnownPool(lp) returns (uint256 baseAmountOut, uint256 quoteAmountOut) {
lp.safeTransferFrom(msg.sender, address(this), sharesIn);
return IMagicLP(lp).sellShares(sharesIn, to, minimumBaseAmount, minimumQuoteAmount, "", deadline);
}
function removeLiquidityETH(
address lp,
address to,
uint256 sharesIn,
uint256 minimumETHAmount,
uint256 minimumTokenAmount,
uint256 deadline
) public virtual onlyKnownPool(lp) returns (uint256 ethAmountOut, uint256 tokenAmountOut) {
lp.safeTransferFrom(msg.sender, address(this), sharesIn);
address token = IMagicLP(lp)._BASE_TOKEN_();
if (token == address(weth)) {
token = IMagicLP(lp)._QUOTE_TOKEN_();
(ethAmountOut, tokenAmountOut) = IMagicLP(lp).sellShares(
sharesIn,
address(this),
minimumETHAmount,
minimumTokenAmount,
"",
deadline
);
} else if (IMagicLP(lp)._QUOTE_TOKEN_() == address(weth)) {
(tokenAmountOut, ethAmountOut) = IMagicLP(lp).sellShares(
sharesIn,
address(this),
minimumTokenAmount,
minimumETHAmount,
"",
deadline
);
} else {
revert ErrNotETHLP();
}
weth.withdraw(ethAmountOut);
to.safeTransferETH(ethAmountOut);
token.safeTransfer(to, tokenAmountOut);
}
function swapTokensForTokens(
address to,
uint256 amountIn,
address[] calldata path,
uint256 directions,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) returns (uint256 amountOut) {
_validatePath(path);
address firstLp = path[0];
if (directions & 1 == 0) {
IMagicLP(firstLp)._BASE_TOKEN_().safeTransferFrom(msg.sender, address(firstLp), amountIn);
} else {
IMagicLP(firstLp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, address(firstLp), amountIn);
}
return _swap(to, path, directions, minimumOut);
}
function swapETHForTokens(
address to,
address[] calldata path,
uint256 directions,
uint256 minimumOut,
uint256 deadline
) public payable virtual ensureDeadline(deadline) returns (uint256 amountOut) {
_validatePath(path);
address firstLp = path[0];
address inToken;
if (directions & 1 == 0) {
inToken = IMagicLP(firstLp)._BASE_TOKEN_();
} else {
inToken = IMagicLP(firstLp)._QUOTE_TOKEN_();
}
if (inToken != address(weth)) {
revert ErrInTokenNotETH();
}
weth.deposit{value: msg.value}();
inToken.safeTransfer(address(firstLp), msg.value);
return _swap(to, path, directions, minimumOut);
}
function swapTokensForETH(
address to,
uint256 amountIn,
address[] calldata path,
uint256 directions,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) returns (uint256 amountOut) {
_validatePath(path);
uint256 lastLpIndex = path.length - 1;
address lastLp = path[lastLpIndex];
address outToken;
if ((directions >> lastLpIndex) & 1 == 0) {
outToken = IMagicLP(lastLp)._QUOTE_TOKEN_();
} else {
outToken = IMagicLP(lastLp)._BASE_TOKEN_();
}
if (outToken != address(weth)) {
revert ErrOutTokenNotETH();
}
address firstLp = path[0];
if (directions & 1 == 0) {
IMagicLP(firstLp)._BASE_TOKEN_().safeTransferFrom(msg.sender, firstLp, amountIn);
} else {
IMagicLP(firstLp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, firstLp, amountIn);
}
amountOut = _swap(address(this), path, directions, minimumOut);
weth.withdraw(amountOut);
to.safeTransferETH(amountOut);
}
function sellBaseTokensForTokens(
address lp,
address to,
uint256 amountIn,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
return _sellBase(lp, to, minimumOut);
}
function sellBaseETHForTokens(
address lp,
address to,
uint256 minimumOut,
uint256 deadline
) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
address baseToken = IMagicLP(lp)._BASE_TOKEN_();
if (baseToken != address(weth)) {
revert ErrInvalidBaseToken();
}
weth.deposit{value: msg.value}();
baseToken.safeTransfer(lp, msg.value);
return _sellBase(lp, to, minimumOut);
}
function sellBaseTokensForETH(
address lp,
address to,
uint256 amountIn,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
if (IMagicLP(lp)._QUOTE_TOKEN_() != address(weth)) {
revert ErrInvalidQuoteToken();
}
IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
amountOut = _sellBase(lp, address(this), minimumOut);
weth.withdraw(amountOut);
to.safeTransferETH(amountOut);
}
function sellQuoteTokensForTokens(
address lp,
address to,
uint256 amountIn,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
return _sellQuote(lp, to, minimumOut);
}
function sellQuoteETHForTokens(
address lp,
address to,
uint256 minimumOut,
uint256 deadline
) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();
if (quoteToken != address(weth)) {
revert ErrInvalidQuoteToken();
}
weth.deposit{value: msg.value}();
quoteToken.safeTransfer(lp, msg.value);
return _sellQuote(lp, to, minimumOut);
}
function sellQuoteTokensForETH(
address lp,
address to,
uint256 amountIn,
uint256 minimumOut,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
if (IMagicLP(lp)._BASE_TOKEN_() != address(weth)) {
revert ErrInvalidBaseToken();
}
IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
amountOut = _sellQuote(lp, address(this), minimumOut);
weth.withdraw(amountOut);
to.safeTransferETH(amountOut);
}
function addLiquidityOneSide(
address lp,
address to,
bool inAmountIsBase,
uint256 inAmount,
uint256 inAmountToSwap,
uint256 minimumShares,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 baseAmount, uint256 quoteAmount, uint256 shares) {
address baseToken = IMagicLP(lp)._BASE_TOKEN_();
address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();
if (inAmountIsBase) {
baseToken.safeTransferFrom(msg.sender, address(this), inAmount);
baseAmount = inAmount - inAmountToSwap;
baseToken.safeTransfer(lp, inAmountToSwap);
quoteAmount = IMagicLP(lp).sellBase(address(this));
}
else {
quoteToken.safeTransferFrom(msg.sender, address(this), inAmount);
quoteAmount = inAmount - inAmountToSwap;
quoteToken.safeTransfer(lp, inAmountToSwap);
baseAmount = IMagicLP(lp).sellQuote(address(this));
}
(baseAmount, quoteAmount) = _adjustAddLiquidity(lp, baseAmount, quoteAmount);
baseToken.safeTransfer(lp, baseAmount);
quoteToken.safeTransfer(lp, quoteAmount);
shares = _addLiquidity(lp, to, minimumShares);
uint256 remaining = baseToken.balanceOf(address(this));
if (remaining > 0) {
baseToken.safeTransfer(msg.sender, remaining);
}
remaining = quoteToken.balanceOf(address(this));
if (remaining > 0) {
quoteToken.safeTransfer(msg.sender, remaining);
}
}
function removeLiquidityOneSide(
address lp,
address to,
bool withdrawBase,
uint256 sharesIn,
uint256 minAmountOut,
uint256 deadline
) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
address baseToken = IMagicLP(lp)._BASE_TOKEN_();
address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();
lp.safeTransferFrom(msg.sender, address(this), sharesIn);
(uint256 baseAmount, uint256 quoteAmount) = IMagicLP(lp).sellShares(sharesIn, address(this), 0, 0, "", deadline);
if (withdrawBase) {
quoteToken.safeTransfer(lp, quoteAmount);
amountOut = baseAmount + IMagicLP(lp).sellQuote(address(this));
if (amountOut > 0) {
baseToken.safeTransfer(to, amountOut);
}
}
else {
baseToken.safeTransfer(lp, baseAmount);
amountOut = quoteAmount + IMagicLP(lp).sellBase(address(this));
if (amountOut > 0) {
quoteToken.safeTransfer(to, amountOut);
}
}
if (amountOut < minAmountOut) {
revert ErrTooHighSlippage(amountOut);
}
}
function addLiquidityImbalanced(
AddLiquidityImbalancedParams calldata params
)
public
virtual
ensureDeadline(params.deadline)
onlyKnownPool(params.lp)
returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
{
address baseToken = IMagicLP(params.lp)._BASE_TOKEN_();
address quoteToken = IMagicLP(params.lp)._QUOTE_TOKEN_();
baseToken.safeTransferFrom(msg.sender, address(this), params.baseInAmount);
quoteToken.safeTransferFrom(msg.sender, address(this), params.quoteInAmount);
(baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(params.lp, params.baseInAmount, params.quoteInAmount);
if (params.remainingAmountToSwapIsBase) {
baseToken.safeTransfer(params.lp, params.remainingAmountToSwap);
baseAdjustedInAmount += (params.baseInAmount - baseAdjustedInAmount) - params.remainingAmountToSwap;
quoteAdjustedInAmount += IMagicLP(params.lp).sellBase(address(this));
}
else {
quoteToken.safeTransfer(params.lp, params.remainingAmountToSwap);
baseAdjustedInAmount += IMagicLP(params.lp).sellQuote(address(this));
quoteAdjustedInAmount += (params.quoteInAmount - quoteAdjustedInAmount) - params.remainingAmountToSwap;
}
(baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(params.lp, baseAdjustedInAmount, quoteAdjustedInAmount);
baseToken.safeTransfer(params.lp, baseAdjustedInAmount);
quoteToken.safeTransfer(params.lp, quoteAdjustedInAmount);
shares = _addLiquidity(params.lp, params.to, params.minimumShares);
uint256 remaining = baseToken.balanceOf(address(this));
if (remaining > 0) {
baseToken.safeTransfer(msg.sender, remaining);
}
remaining = quoteToken.balanceOf(address(this));
if (remaining > 0) {
quoteToken.safeTransfer(msg.sender, remaining);
}
}
function _addLiquidity(address lp, address to, uint256 minimumShares) internal returns (uint256 shares) {
(shares, , ) = IMagicLP(lp).buyShares(to);
if (shares < minimumShares) {
revert ErrTooHighSlippage(shares);
}
}
function _adjustAddLiquidity(
address lp,
uint256 baseInAmount,
uint256 quoteInAmount
) internal view returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount) {
if (IERC20(lp).totalSupply() == 0) {
uint256 i = IMagicLP(lp)._I_();
uint256 shares = quoteInAmount < DecimalMath.mulFloor(baseInAmount, i) ? DecimalMath.divFloor(quoteInAmount, i) : baseInAmount;
baseAdjustedInAmount = shares;
quoteAdjustedInAmount = DecimalMath.mulFloor(shares, i);
} else {
(uint256 baseReserve, uint256 quoteReserve) = IMagicLP(lp).getReserves();
if (quoteReserve > 0 && baseReserve > 0) {
uint256 baseIncreaseRatio = DecimalMath.divFloor(baseInAmount, baseReserve);
uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteInAmount, quoteReserve);
if (baseIncreaseRatio <= quoteIncreaseRatio) {
baseAdjustedInAmount = baseInAmount;
quoteAdjustedInAmount = DecimalMath.mulFloor(quoteReserve, baseIncreaseRatio);
} else {
quoteAdjustedInAmount = quoteInAmount;
baseAdjustedInAmount = DecimalMath.mulFloor(baseReserve, quoteIncreaseRatio);
}
}
}
}
function _swap(address to, address[] calldata path, uint256 directions, uint256 minimumOut) internal returns (uint256 amountOut) {
uint256 iterations = path.length - 1;
for (uint256 i = 0; i < iterations; ) {
address lp = path[i];
if (!factory.poolExists(lp)) {
revert ErrUnknownPool();
}
if (directions & 1 == 0) {
IMagicLP(lp).sellBase(address(path[i + 1]));
} else {
IMagicLP(lp).sellQuote(address(path[i + 1]));
}
directions >>= 1;
unchecked {
++i;
}
}
if ((directions & 1 == 0)) {
amountOut = IMagicLP(path[iterations]).sellBase(to);
} else {
amountOut = IMagicLP(path[iterations]).sellQuote(to);
}
if (amountOut < minimumOut) {
revert ErrTooHighSlippage(amountOut);
}
}
function _sellBase(address lp, address to, uint256 minimumOut) internal returns (uint256 amountOut) {
amountOut = IMagicLP(lp).sellBase(to);
if (amountOut < minimumOut) {
revert ErrTooHighSlippage(amountOut);
}
}
function _sellQuote(address lp, address to, uint256 minimumOut) internal returns (uint256 amountOut) {
amountOut = IMagicLP(lp).sellQuote(to);
if (amountOut < minimumOut) {
revert ErrTooHighSlippage(amountOut);
}
}
function _validatePath(address[] calldata path) internal pure {
uint256 pathLength = path.length;
if (pathLength > 256) {
revert ErrPathTooLong();
}
if (pathLength <= 0) {
revert ErrEmptyPath();
}
}
function _validateDecimals(uint8 baseDecimals, uint8 quoteDecimals) internal pure {
if (baseDecimals == 0 || quoteDecimals == 0) {
revert ErrZeroDecimals();
}
if (baseDecimals > 18 || quoteDecimals > 18) {
revert ErrTooLargeDecimals();
}
uint256 deltaDecimals = baseDecimals > quoteDecimals ? baseDecimals - quoteDecimals : quoteDecimals - baseDecimals;
if (deltaDecimals > MAX_BASE_QUOTE_DECIMALS_DIFFERENCE) {
revert ErrDecimalsDifferenceTooLarge();
}
}
}
文件 10 的 10:SafeTransferLib.sol
pragma solidity ^0.8.4;
library SafeTransferLib {
error ETHTransferFailed();
error TransferFromFailed();
error TransferFailed();
error ApproveFailed();
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
function safeTransferETH(address to, uint256 amount) internal {
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function safeTransferAllETH(address to) internal {
assembly {
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferETH(address to, uint256 amount) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferAllETH(address to) internal {
assembly {
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
assembly {
let m := mload(0x40)
mstore(0x60, amount)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x23b872dd000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
assembly {
let m := mload(0x40)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x70a08231000000000000000000000000)
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd)
amount := mload(0x60)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransfer(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
assembly {
mstore(0x00, 0x70a08231)
mstore(0x20, address())
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x14, to)
amount := mload(0x34)
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeApprove(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0)
mstore(0x00, 0x095ea7b3000000000000000000000000)
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00))
mstore(0x34, amount)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function balanceOf(address token, address account) internal view returns (uint256 amount) {
assembly {
mstore(0x14, account)
mstore(0x00, 0x70a08231000000000000000000000000)
amount :=
mul(
mload(0x20),
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}
{
"compilationTarget": {
"src/mimswap/periphery/Router.sol": "Router"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 400
},
"remappings": [
":/=src/",
":BoringSolidity/=lib/BoringSolidity/contracts/",
":ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
":cauldrons/=src/cauldrons/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-deploy/=lib/forge-deploy/contracts/",
":forge-std/=lib/forge-std/src/",
":fuzzlib/=lib/fuzzlib/src/",
":interfaces/=src/interfaces/",
":lenses/=src/lenses/",
":libraries/=src/libraries/",
":mixins/=src/mixins/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
":oracles/=src/oracles/",
":periphery/=src/periphery/",
":safe-contracts/=lib/safe-contracts/contracts/",
":solady/=lib/solady/src/",
":solmate/=lib/solmate/src/",
":staking/=src/staking/",
":strategies/=src/strategies/",
":surl/=lib/surl/src/",
":swappers/=src/swappers/",
":tokens/=src/tokens/",
":utils/=utils/"
]
}
[{"inputs":[{"internalType":"contract IWETH","name":"weth_","type":"address"},{"internalType":"contract IFactory","name":"factory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ErrBadPath","type":"error"},{"inputs":[],"name":"ErrDecimalsDifferenceTooLarge","type":"error"},{"inputs":[],"name":"ErrEmptyPath","type":"error"},{"inputs":[],"name":"ErrExpired","type":"error"},{"inputs":[],"name":"ErrInTokenNotETH","type":"error"},{"inputs":[],"name":"ErrInvalidBaseToken","type":"error"},{"inputs":[],"name":"ErrInvalidQuoteTarget","type":"error"},{"inputs":[],"name":"ErrInvalidQuoteToken","type":"error"},{"inputs":[],"name":"ErrNotETHLP","type":"error"},{"inputs":[],"name":"ErrOutTokenNotETH","type":"error"},{"inputs":[],"name":"ErrPathTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"ErrTooHighSlippage","type":"error"},{"inputs":[],"name":"ErrTooLargeDecimals","type":"error"},{"inputs":[],"name":"ErrUnknownPool","type":"error"},{"inputs":[],"name":"ErrZeroAddress","type":"error"},{"inputs":[],"name":"ErrZeroDecimals","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"MAX_BASE_QUOTE_DECIMALS_DIFFERENCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"refundTo","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETHUnsafe","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"bool","name":"remainingAmountToSwapIsBase","type":"bool"},{"internalType":"uint256","name":"remainingAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct AddLiquidityImbalancedParams","name":"params","type":"tuple"}],"name":"addLiquidityImbalanced","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"inAmountIsBase","type":"bool"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"inAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityOneSide","outputs":[{"internalType":"uint256","name":"baseAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityUnsafe","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint256","name":"lpFeeRate","type":"uint256"},{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"bool","name":"protocolOwnedPool","type":"bool"}],"name":"createPool","outputs":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"useTokenAsQuote","type":"bool"},{"internalType":"uint256","name":"lpFeeRate","type":"uint256"},{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"bool","name":"protocolOwnedPool","type":"bool"}],"name":"createPoolETH","outputs":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"}],"name":"previewCreatePool","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"}],"name":"previewRemoveLiquidity","outputs":[{"internalType":"uint256","name":"baseAmountOut","type":"uint256"},{"internalType":"uint256","name":"quoteAmountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minimumBaseAmount","type":"uint256"},{"internalType":"uint256","name":"minimumQuoteAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"baseAmountOut","type":"uint256"},{"internalType":"uint256","name":"quoteAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"},{"internalType":"uint256","name":"minimumTokenAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"ethAmountOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawBase","type":"bool"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityOneSide","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]