// SPDX-License-Identifier: WTFPL
pragma solidity >=0.8.0;
// ██████╗ ███████╗███╗ ███╗███████╗██╗ ██╗ █████╗ ██████╗
// ██╔════╝ ██╔════╝████╗ ████║██╔════╝██║ ██║██╔══██╗██╔══██╗
// ██║ ███╗█████╗ ██╔████╔██║███████╗██║ █╗ ██║███████║██████╔╝
// ██║ ██║██╔══╝ ██║╚██╔╝██║╚════██║██║███╗██║██╔══██║██╔═══╝
// ╚██████╔╝███████╗██║ ╚═╝ ██║███████║╚███╔███╔╝██║ ██║██║
// ╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IGemswapPair {
function getReserves() external view returns (
uint112 baseReserves,
uint112 quoteReserves,
uint32 lastUpdate
);
}
library GemswapLibrary {
uint256 internal constant BIPS_DIVISOR = 10_000;
function uDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {assembly {z := div(x, y)}}
// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
}
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
error NONEXISTENT_PAIR();
// calculates the clone address for a pair without making any external calls
function pairFor(
address factory,
address implementation,
address tokenA,
address tokenB
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = predictDeterministicAddress(implementation, keccak256(abi.encodePacked(token0, token1, uint256(1))), factory);
}
// fetches and sorts the reserves for a pair
function getReserves(
address factory,
address implementation,
address tokenA,
address tokenB
) internal view returns (uint256 reserveA, uint256 reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint256 baseReserves, uint256 quoteReserves,) = IGemswapPair(pairFor(factory, implementation, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (baseReserves, quoteReserves) : (quoteReserves, baseReserves);
}
// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 amountB) {
amountB = uDiv(amountA * reserveB, reserveA);
}
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
uint256 amountInWithFee = amountIn * 9975;
amountOut = uDiv(amountInWithFee * reserveOut, reserveIn * BIPS_DIVISOR + amountInWithFee);
}
// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountIn) {
amountIn = uDiv(reserveIn * amountOut * BIPS_DIVISOR, reserveOut - amountOut * 9975) + 1;
}
/* -------------------------------------------------------------------------- */
/* SHOULD PROB BE UNCHECKED VVV */
/* -------------------------------------------------------------------------- */
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(
address factory,
address implementation,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
unchecked {
uint256 pathLength = path.length; // save gas
amounts = new uint256[](pathLength);
amounts[0] = amountIn;
for (uint256 i; i < pathLength - 1; ++i) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, implementation, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
}
// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(
address factory,
address implementation,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
unchecked {
uint256 pathLength = path.length; // save gas
amounts = new uint256[](pathLength);
amounts[pathLength - 1] = amountOut;
for (uint256 i = pathLength - 1; i > 0; --i) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, implementation, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
}
interface IERC20PermitAllowed {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
contract GemswapRouter {
address public immutable factory;
address public immutable implementation;
address public immutable WETH;
modifier ensure(uint256 deadline) {
require(deadline >= block.timestamp, "EXPIRED");
_;
}
constructor(
address _factory,
address _implementation,
address _WETH
) {
factory = _factory;
implementation = _implementation;
WETH = _WETH;
}
receive() external payable {
// only accept ETH via fallback from the WETH contract
assert(msg.sender == WETH);
}
/* -------------------------------------------------------------------------- */
/* ADD LIQUIDITY LOGIC */
/* -------------------------------------------------------------------------- */
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) private returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
(uint reserveA, uint reserveB) = GemswapLibrary.getReserves(factory, implementation, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = GemswapLibrary.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'Gemswap: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = GemswapLibrary.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'Gemswap: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = GemswapLibrary.pairFor(factory, implementation, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IUniswapV2Pair(pair).mint(to);
}
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable ensure(deadline) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = GemswapLibrary.pairFor(factory, implementation, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256 amountA, uint256 amountB) {
address pair = GemswapLibrary.pairFor(factory, implementation, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = GemswapLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, "INSUFFICIENT_A_AMOUNT");
require(amountB >= amountBMin, "INSUFFICIENT_B_AMOUNT");
}
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint256 amountA, uint256 amountB) {
IUniswapV2Pair(GemswapLibrary.pairFor(factory, implementation, tokenA, tokenB)).permit(
msg.sender,
address(this),
approveMax ? type(uint256).max : liquidity,
deadline,
v,
r,
s
);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint256 amountToken, uint256 amountETH) {
address pair = GemswapLibrary.pairFor(factory, implementation, token, WETH);
uint256 value = approveMax ? type(uint256).max : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256 amountETH) {
(, amountETH) = removeLiquidity(token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint256 amountETH) {
address pair = GemswapLibrary.pairFor(factory, implementation, token, WETH);
uint256 value = approveMax ? type(uint256).max : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
/* -------------------------------------------------------------------------- */
/* SWAP LOGIC */
/* -------------------------------------------------------------------------- */
// requires the initial amount to have already been sent to the first pair
function _swap(
uint256[] memory amounts,
address[] memory path,
address _to
) internal virtual {
// unchecked orginally
unchecked {
uint256 pathLength = path.length;
address _implementation = implementation;
for (uint256 i; i < pathLength - 1; ++i) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = GemswapLibrary.sortTokens(input, output);
uint256 amountOut = amounts[i + 1];
(uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0));
address to = i < path.length - 2 ? GemswapLibrary.pairFor(factory, _implementation, output, path[i + 2]) : _to;
IUniswapV2Pair(GemswapLibrary.pairFor(factory, _implementation, input, output)).swap(
amount0Out,
amount1Out,
to,
new bytes(0)
);
}
}
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256[] memory amounts) {
unchecked {
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsOut(factory, _implementation, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
GemswapLibrary.pairFor(factory, _implementation, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
}
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256[] memory amounts) {
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsIn(factory, implementation, amountOut, path);
require(amounts[0] <= amountInMax, "EXCESSIVE_INPUT_AMOUNT");
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
GemswapLibrary.pairFor(factory, _implementation, path[0], path[1]),
amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable ensure(deadline) returns (uint256[] memory amounts) {
require(path[0] == WETH, "INVALID_PATH");
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsOut(factory, _implementation, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(GemswapLibrary.pairFor(factory, _implementation, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256[] memory amounts) {
require(path[path.length - 1] == WETH, "INVALID_PATH");
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsIn(factory, _implementation, amountOut, path);
require(amounts[0] <= amountInMax, "EXCESSIVE_INPUT_AMOUNT");
TransferHelper.safeTransferFrom(path[0], msg.sender, GemswapLibrary.pairFor(
factory,
_implementation,
path[0],
path[1]),
amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) public ensure(deadline) returns (uint256[] memory amounts) {
require(path[path.length - 1] == WETH, "INVALID_PATH");
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsOut(factory, _implementation, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
GemswapLibrary.pairFor(factory, _implementation, path[0], path[1]),
amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable ensure(deadline) returns (uint256[] memory amounts) {
require(path[0] == WETH, "INVALID_PATH");
address _implementation = implementation;
amounts = GemswapLibrary.getAmountsIn(factory, _implementation, amountOut, path);
require(amounts[0] <= msg.value, "EXCESSIVE_INPUT_AMOUNT");
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(GemswapLibrary.pairFor(factory, _implementation, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
/* -------------------------------------------------------------------------- */
/* PERMIT SWAP LOGIC */
/* -------------------------------------------------------------------------- */
function swapExactTokensForTokensUsingPermit(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20Permit(path[0]).permit(msg.sender, address(this), amountIn, deadline, v, r, s);
amounts = swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline);
}
function swapExactTokensForTokensUsingPermitAllowed(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline, uint256 nonce, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20PermitAllowed(path[0]).permit(msg.sender, address(this), nonce, deadline, true, v, r, s);
amounts = swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline);
}
function swapTokensForExactTokensUsingPermit(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20Permit(path[0]).permit(msg.sender, address(this), amountInMax, deadline, v, r, s);
amounts = swapTokensForExactTokens(amountOut, amountInMax, path, to, deadline);
}
function swapTokensForExactTokensUsingPermitAllowed(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline, uint256 nonce, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20PermitAllowed(path[0]).permit(msg.sender, address(this), nonce, deadline, true, v, r, s);
amounts = swapTokensForExactTokens(amountOut, amountInMax, path, to, deadline);
}
function swapTokensForExactETHUsingPermit(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20Permit(path[0]).permit(msg.sender, address(this), amountInMax, deadline, v, r, s);
amounts = swapTokensForExactETH(amountOut, amountInMax, path, to, deadline);
}
function swapTokensForExactETHUsingPermitAllowed(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline, uint256 nonce, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20PermitAllowed(path[0]).permit(msg.sender, address(this), nonce, deadline, true, v, r, s);
amounts = swapTokensForExactETH(amountOut, amountInMax, path, to, deadline);
}
function swapExactTokensForETHUsingPermit(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20Permit(path[0]).permit(msg.sender, address(this), amountIn, deadline, v, r, s);
amounts = swapExactTokensForETH(amountIn, amountOutMin, path, to, deadline);
}
function swapExactTokensForETHUsingPermitAllowed(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline, uint256 nonce, uint8 v, bytes32 r, bytes32 s
) external returns (uint256[] memory amounts) {
IERC20PermitAllowed(path[0]).permit(msg.sender, address(this), nonce, deadline, true, v, r, s);
amounts = swapExactTokensForETH(amountIn, amountOutMin, path, to, deadline);
}
/* -------------------------------------------------------------------------- */
/* SWAP (supporting fee-on-transfer tokens) LOGIC */
/* -------------------------------------------------------------------------- */
// requires the initial amount to have already been sent to the first pair
function _swapSupportingFeeOnTransferTokens(
address[] memory path,
address _to
) internal virtual {
address _implementation = implementation;
// uint256 pathLength = path.length; // removed to avoid stack too deep :(
for (uint256 i; i < path.length - 1; ++i) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = GemswapLibrary.sortTokens(input, output);
IUniswapV2Pair pair = IUniswapV2Pair(GemswapLibrary.pairFor(factory, _implementation, input, output));
uint256 amountOutput;
{ // scope to avoid stack too deep errors
(uint256 reserve0, uint256 reserve1,) = pair.getReserves();
(uint256 reserveInput, uint256 reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountOutput = GemswapLibrary.getAmountOut(
IERC20(input).balanceOf(address(pair)) - reserveInput,
reserveInput,
reserveOutput
);
}
(uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0));
address to = i < path.length - 2 ? GemswapLibrary.pairFor(factory, _implementation, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external ensure(deadline) {
TransferHelper.safeTransferFrom(path[0], msg.sender, GemswapLibrary.pairFor(factory, implementation,path[0], path[1]), amountIn);
uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(IERC20(path[path.length - 1]).balanceOf(to) - (balanceBefore) >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable ensure(deadline) {
require(path[0] == WETH, "INVALID_PATH");
uint256 amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(GemswapLibrary.pairFor(factory, implementation, path[0], path[1]), amountIn));
uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(IERC20(path[path.length - 1]).balanceOf(to) - (balanceBefore) >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external ensure(deadline) {
require(path[path.length - 1] == WETH, "INVALID_PATH");
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
GemswapLibrary.pairFor(factory, implementation, path[0], path[1]),
amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint256 amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
/* -------------------------------------------------------------------------- */
/* LIBRARY FUNCTIONS */
/* -------------------------------------------------------------------------- */
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) public pure returns (uint256 amountB) {
return GemswapLibrary.quote(amountA, reserveA, reserveB);
}
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256 amountOut) {
return GemswapLibrary.getAmountOut(amountIn, reserveIn, reserveOut);
}
function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256 amountIn) {
return GemswapLibrary.getAmountIn(amountOut, reserveIn, reserveOut);
}
function getAmountsOut(uint256 amountIn, address[] memory path) public view returns (uint256[] memory amounts) {
return GemswapLibrary.getAmountsOut(factory, implementation, amountIn, path);
}
function getAmountsIn(uint256 amountOut, address[] memory path) public view returns (uint256[] memory amounts) {
return GemswapLibrary.getAmountsIn(factory, implementation, amountOut, path);
}
}
{
"compilationTarget": {
"GemswapRouter.sol": "GemswapRouter"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_implementation","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapExactTokensForETHUsingPermit","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapExactTokensForETHUsingPermitAllowed","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapExactTokensForTokensUsingPermit","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapExactTokensForTokensUsingPermitAllowed","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapTokensForExactETHUsingPermit","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapTokensForExactETHUsingPermitAllowed","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapTokensForExactTokensUsingPermit","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"swapTokensForExactTokensUsingPermitAllowed","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]