编译器
0.8.17+commit.8df45f5f
文件 1 的 23:BytesLib.sol
pragma solidity ^0.8.0;
library BytesLib {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, "toAddress_overflow");
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, "toUint24_overflow");
require(_bytes.length >= _start + 3, "toUint24_outOfBounds");
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
}
文件 2 的 23:Deadline.sol
pragma solidity ^0.8.0;
abstract contract Deadline {
modifier checkDeadline(uint256 deadline) {
require(block.timestamp <= deadline, "Transaction too old");
_;
}
}
文件 3 的 23:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 4 的 23:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 5 的 23:IERC20PermitAllowed.sol
pragma solidity >=0.5.0;
interface IERC20PermitAllowed {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 6 的 23:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 7 的 23:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 8 的 23:IFactory.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IPool.sol";
import "../interfaces/IPosition.sol";
interface IFactory {
event PoolCreated(
address poolAddress,
uint256 fee,
uint256 tickSpacing,
int32 activeTick,
int256 lookback,
uint64 protocolFeeRatio,
IERC20 tokenA,
IERC20 tokenB
);
event SetFactoryProtocolFeeRatio(uint64 protocolFeeRatio);
event SetFactoryOwner(address owner);
function create(
uint256 _fee,
uint256 _tickSpacing,
int256 _lookback,
int32 _activeTick,
IERC20 _tokenA,
IERC20 _tokenB
) external returns (IPool);
function lookup(
uint256 fee,
uint256 tickSpacing,
int256 lookback,
IERC20 tokenA,
IERC20 tokenB
) external view returns (IPool);
function owner() external view returns (address);
function position() external view returns (IPosition);
function protocolFeeRatio() external view returns (uint64);
function isFactoryPool(IPool pool) external view returns (bool);
}
文件 9 的 23:IMulticall.sol
pragma solidity >=0.7.5;
pragma abicoder v2;
interface IMulticall {
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}
文件 10 的 23:IPool.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IFactory.sol";
interface IPool {
event Swap(
address sender,
address recipient,
bool tokenAIn,
bool exactOutput,
uint256 amountIn,
uint256 amountOut,
int32 activeTick
);
event AddLiquidity(address indexed sender, uint256 indexed tokenId, BinDelta[] binDeltas);
event MigrateBinsUpStack(address indexed sender, uint128 binId, uint32 maxRecursion);
event TransferLiquidity(uint256 fromTokenId, uint256 toTokenId, RemoveLiquidityParams[] params);
event RemoveLiquidity(
address indexed sender,
address indexed recipient,
uint256 indexed tokenId,
BinDelta[] binDeltas
);
event BinMerged(uint128 indexed binId, uint128 reserveA, uint128 reserveB, uint128 mergeId);
event BinMoved(uint128 indexed binId, int128 previousTick, int128 newTick);
event ProtocolFeeCollected(uint256 protocolFee, bool isTokenA);
event SetProtocolFeeRatio(uint256 protocolFee);
struct BinDelta {
uint128 deltaA;
uint128 deltaB;
uint256 deltaLpBalance;
uint128 binId;
uint8 kind;
int32 lowerTick;
bool isActive;
}
struct TwaState {
int96 twa;
int96 value;
uint64 lastTimestamp;
}
struct BinState {
uint128 reserveA;
uint128 reserveB;
uint128 mergeBinBalance;
uint128 mergeId;
uint128 totalSupply;
uint8 kind;
int32 lowerTick;
}
struct AddLiquidityParams {
uint8 kind;
int32 pos;
bool isDelta;
uint128 deltaA;
uint128 deltaB;
}
struct RemoveLiquidityParams {
uint128 binId;
uint128 amount;
}
struct State {
int32 activeTick;
uint8 status;
uint128 binCounter;
uint64 protocolFeeRatio;
}
function fee() external view returns (uint256);
function tickSpacing() external view returns (uint256);
function tokenA() external view returns (IERC20);
function tokenB() external view returns (IERC20);
function factory() external view returns (IFactory);
function binMap(int32 tick) external view returns (uint256);
function binPositions(int32 tick, uint256 kind) external view returns (uint128);
function binBalanceA() external view returns (uint128);
function binBalanceB() external view returns (uint128);
function getTwa() external view returns (TwaState memory);
function getState() external view returns (State memory);
function addLiquidity(
uint256 tokenId,
AddLiquidityParams[] calldata params,
bytes calldata data
)
external
returns (
uint256 tokenAAmount,
uint256 tokenBAmount,
BinDelta[] memory binDeltas
);
function transferLiquidity(
uint256 fromTokenId,
uint256 toTokenId,
RemoveLiquidityParams[] calldata params
) external;
function removeLiquidity(
address recipient,
uint256 tokenId,
RemoveLiquidityParams[] calldata params
)
external
returns (
uint256 tokenAOut,
uint256 tokenBOut,
BinDelta[] memory binDeltas
);
function migrateBinUpStack(uint128 binId, uint32 maxRecursion) external;
function swap(
address recipient,
uint256 amount,
bool tokenAIn,
bool exactOutput,
uint256 sqrtPriceLimit,
bytes calldata data
) external returns (uint256 amountIn, uint256 amountOut);
function getBin(uint128 binId) external view returns (BinState memory bin);
function balanceOf(uint256 tokenId, uint128 binId) external view returns (uint256 lpToken);
function tokenAScale() external view returns (uint256);
function tokenBScale() external view returns (uint256);
}
文件 11 的 23:IPosition.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "../interfaces/IPositionMetadata.sol";
interface IPosition is IERC721Enumerable {
event SetMetadata(IPositionMetadata metadata);
function mint(address to) external returns (uint256 tokenId);
function tokenOfOwnerByIndexExists(address owner, uint256 index) external view returns (bool);
}
文件 12 的 23:IPositionMetadata.sol
pragma solidity ^0.8.0;
interface IPositionMetadata {
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 13 的 23:IRouter.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@maverick/contracts/contracts/interfaces/IFactory.sol";
import "@maverick/contracts/contracts/interfaces/IPool.sol";
import "@maverick/contracts/contracts/interfaces/IPosition.sol";
import "@maverick/contracts/contracts/interfaces/ISwapCallback.sol";
import "./external/IWETH9.sol";
import "./ISlimRouter.sol";
interface IRouter is ISlimRouter {
function factory() external view returns (IFactory);
function position() external view returns (IPosition);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutput(
ExactOutputParams calldata params
) external payable returns (uint256 amountIn);
struct PoolParams {
uint256 fee;
uint256 tickSpacing;
int256 lookback;
int32 activeTick;
IERC20 tokenA;
IERC20 tokenB;
}
function getOrCreatePoolAndAddLiquidity(
PoolParams calldata poolParams,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata addParams,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
payable
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
);
function addLiquidityToPool(
IPool pool,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
payable
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
);
function addLiquidityWTickLimits(
IPool pool,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
int32 minActiveTick,
int32 maxActiveTick,
uint256 deadline
)
external
payable
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
);
function migrateBinsUpStack(
IPool pool,
uint128[] calldata binIds,
uint32 maxRecursion,
uint256 deadline
) external;
function removeLiquidity(
IPool pool,
address recipient,
uint256 tokenId,
IPool.RemoveLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
returns (uint256 tokenAAmount, uint256 tokenBAmount, IPool.BinDelta[] memory binDeltas);
}
文件 14 的 23:ISelfPermit.sol
pragma solidity >=0.7.5;
interface ISelfPermit {
function selfPermit(
address token,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function selfPermitIfNecessary(
address token,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function selfPermitAllowed(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
function selfPermitAllowedIfNecessary(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
}
文件 15 的 23:ISlimRouter.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@maverick/contracts/contracts/interfaces/IFactory.sol";
import "@maverick/contracts/contracts/interfaces/IPool.sol";
import "@maverick/contracts/contracts/interfaces/IPosition.sol";
import "@maverick/contracts/contracts/interfaces/ISwapCallback.sol";
import "./external/IWETH9.sol";
interface ISlimRouter is ISwapCallback {
function WETH9() external view returns (IWETH9);
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
IPool pool;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint256 sqrtPriceLimitD18;
}
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
IPool pool;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutputSingle(
ExactOutputSingleParams calldata params
) external payable returns (uint256 amountIn);
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;
function refundETH() external payable;
function sweepToken(IERC20 token, uint256 amountMinimum, address recipient) external payable;
}
文件 16 的 23:ISwapCallback.sol
pragma solidity ^0.8.0;
interface ISwapCallback {
function swapCallback(
uint256 amountIn,
uint256 amountOut,
bytes calldata data
) external;
}
文件 17 的 23:IWETH9.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 18 的 23:Multicall.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import "../interfaces/IMulticall.sol";
abstract contract Multicall is IMulticall {
function multicall(
bytes[] calldata data
) public payable override returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
if (!success) {
if (result.length < 68) revert();
assembly {
result := add(result, 0x04)
}
revert(abi.decode(result, (string)));
}
results[i] = result;
}
}
}
文件 19 的 23:Path.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@maverick/contracts/contracts/interfaces/IPool.sol";
import "./BytesLib.sol";
library Path {
using BytesLib for bytes;
uint256 private constant ADDR_SIZE = 20;
uint256 private constant NEXT_OFFSET = ADDR_SIZE + ADDR_SIZE;
uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE;
uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;
function hasMultiplePools(bytes memory path) internal pure returns (bool) {
return path.length >= MULTIPLE_POOLS_MIN_LENGTH;
}
function numPools(bytes memory path) internal pure returns (uint256) {
return ((path.length - ADDR_SIZE) / NEXT_OFFSET);
}
function decodeFirstPool(
bytes memory path
) internal pure returns (IERC20 tokenIn, IERC20 tokenOut, IPool pool) {
tokenIn = IERC20(path.toAddress(0));
pool = IPool(path.toAddress(ADDR_SIZE));
tokenOut = IERC20(path.toAddress(NEXT_OFFSET));
}
function getFirstPool(bytes memory path) internal pure returns (bytes memory) {
return path.slice(0, POP_OFFSET);
}
function skipToken(bytes memory path) internal pure returns (bytes memory) {
return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET);
}
}
文件 20 的 23:Router.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@maverick/contracts/contracts/interfaces/IPool.sol";
import "@maverick/contracts/contracts/interfaces/IFactory.sol";
import "@maverick/contracts/contracts/interfaces/IPosition.sol";
import "./interfaces/IRouter.sol";
import "./interfaces/external/IWETH9.sol";
import "./libraries/TransferHelper.sol";
import "./libraries/Path.sol";
import "./libraries/Deadline.sol";
import "./libraries/Multicall.sol";
import "./libraries/SelfPermit.sol";
contract Router is IRouter, Multicall, SelfPermit, Deadline {
using Path for bytes;
uint256 private constant DEFAULT_AMOUNT_IN_CACHED = type(uint256).max;
uint256 private amountInCached = DEFAULT_AMOUNT_IN_CACHED;
struct AddLiquidityCallbackData {
IERC20 tokenA;
IERC20 tokenB;
IPool pool;
address payer;
}
struct SwapCallbackData {
bytes path;
address payer;
bool exactOutput;
}
IFactory public immutable factory;
IPosition public immutable position;
IWETH9 public immutable WETH9;
constructor(IFactory _factory, IWETH9 _WETH9) {
factory = _factory;
position = _factory.position();
WETH9 = _WETH9;
}
receive() external payable {
require(IWETH9(msg.sender) == WETH9, "Not WETH9");
}
function unwrapWETH9(uint256 amountMinimum, address recipient) public payable override {
uint256 balanceWETH9 = WETH9.balanceOf(address(this));
require(balanceWETH9 >= amountMinimum, "Insufficient WETH9");
if (balanceWETH9 > 0) {
WETH9.withdraw(balanceWETH9);
TransferHelper.safeTransferETH(recipient, balanceWETH9);
}
}
function sweepToken(IERC20 token, uint256 amountMinimum, address recipient) public payable {
uint256 balanceToken = token.balanceOf(address(this));
require(balanceToken >= amountMinimum, "Insufficient token");
if (balanceToken > 0) {
TransferHelper.safeTransfer(address(token), recipient, balanceToken);
}
}
function refundETH() external payable override {
if (address(this).balance > 0)
TransferHelper.safeTransferETH(msg.sender, address(this).balance);
}
function pay(IERC20 token, address payer, address recipient, uint256 value) internal {
if (IWETH9(address(token)) == WETH9 && address(this).balance >= value) {
WETH9.deposit{value: value}();
WETH9.transfer(recipient, value);
} else if (payer == address(this)) {
TransferHelper.safeTransfer(address(token), recipient, value);
} else {
TransferHelper.safeTransferFrom(address(token), payer, recipient, value);
}
}
function swapCallback(uint256 amountToPay, uint256 amountOut, bytes calldata _data) external {
require(amountToPay > 0 && amountOut > 0, "In or Out Amount is Zero");
require(factory.isFactoryPool(IPool(msg.sender)), "Must call from a Factory Pool");
SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData));
(IERC20 tokenIn, IERC20 tokenOut, IPool pool) = data.path.decodeFirstPool();
require(msg.sender == address(pool));
if (data.exactOutput) {
if (data.path.hasMultiplePools()) {
data.path = data.path.skipToken();
exactOutputInternal(amountToPay, msg.sender, data);
} else {
amountInCached = amountToPay;
pay(tokenOut, data.payer, msg.sender, amountToPay);
}
} else {
pay(tokenIn, data.payer, msg.sender, amountToPay);
}
}
function exactInputInternal(
uint256 amountIn,
address recipient,
uint256 sqrtPriceLimitD18,
SwapCallbackData memory data
) private returns (uint256 amountOut) {
if (recipient == address(0)) recipient = address(this);
(IERC20 tokenIn, IERC20 tokenOut, IPool pool) = data.path.decodeFirstPool();
bool tokenAIn = tokenIn < tokenOut;
(, amountOut) = pool.swap(
recipient,
amountIn,
tokenAIn,
false,
sqrtPriceLimitD18,
abi.encode(data)
);
}
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable override checkDeadline(params.deadline) returns (uint256 amountOut) {
bool tokenAIn = params.tokenIn < params.tokenOut;
(, amountOut) = params.pool.swap(
(params.recipient == address(0)) ? address(this) : params.recipient,
params.amountIn,
tokenAIn,
false,
params.sqrtPriceLimitD18,
abi.encode(
SwapCallbackData({
path: abi.encodePacked(params.tokenIn, params.pool, params.tokenOut),
payer: msg.sender,
exactOutput: false
})
)
);
require(amountOut >= params.amountOutMinimum, "Too little received");
}
function exactInput(
ExactInputParams memory params
) external payable override checkDeadline(params.deadline) returns (uint256 amountOut) {
address payer = msg.sender;
while (true) {
bool stillMultiPoolSwap = params.path.hasMultiplePools();
params.amountIn = exactInputInternal(
params.amountIn,
stillMultiPoolSwap ? address(this) : params.recipient,
0,
SwapCallbackData({
path: params.path.getFirstPool(),
payer: payer,
exactOutput: false
})
);
if (stillMultiPoolSwap) {
payer = address(this);
params.path = params.path.skipToken();
} else {
amountOut = params.amountIn;
break;
}
}
require(amountOut >= params.amountOutMinimum, "Too little received");
}
function exactOutputInternal(
uint256 amountOut,
address recipient,
SwapCallbackData memory data
) private returns (uint256 amountIn) {
if (recipient == address(0)) recipient = address(this);
(IERC20 tokenOut, IERC20 tokenIn, IPool pool) = data.path.decodeFirstPool();
bool tokenAIn = tokenIn < tokenOut;
uint256 amountOutReceived;
(amountIn, amountOutReceived) = pool.swap(
recipient,
amountOut,
tokenAIn,
true,
0,
abi.encode(data)
);
require(amountOutReceived == amountOut, "Requested amount not available");
}
function exactOutputSingle(
ExactOutputSingleParams calldata params
) external payable override checkDeadline(params.deadline) returns (uint256 amountIn) {
bool tokenAIn = params.tokenIn < params.tokenOut;
uint256 amountOutReceived;
(amountIn, amountOutReceived) = params.pool.swap(
(params.recipient == address(0)) ? address(this) : params.recipient,
params.amountOut,
tokenAIn,
true,
0,
abi.encode(
SwapCallbackData({
path: abi.encodePacked(params.tokenOut, params.pool, params.tokenIn),
payer: msg.sender,
exactOutput: true
})
)
);
require(amountOutReceived == params.amountOut, "Requested amount not available");
require(amountIn <= params.amountInMaximum, "Too much requested");
amountInCached = DEFAULT_AMOUNT_IN_CACHED;
}
function exactOutput(
ExactOutputParams calldata params
) external payable override checkDeadline(params.deadline) returns (uint256 amountIn) {
exactOutputInternal(
params.amountOut,
params.recipient,
SwapCallbackData({path: params.path, payer: msg.sender, exactOutput: true})
);
amountIn = amountInCached;
require(amountIn <= params.amountInMaximum, "Too much requested");
amountInCached = DEFAULT_AMOUNT_IN_CACHED;
}
function addLiquidityCallback(uint256 amountA, uint256 amountB, bytes calldata _data) external {
AddLiquidityCallbackData memory data = abi.decode(_data, (AddLiquidityCallbackData));
require(factory.isFactoryPool(IPool(msg.sender)));
require(msg.sender == address(data.pool));
if (amountA != 0) {
pay(data.tokenA, data.payer, msg.sender, amountA);
}
if (amountB != 0) {
pay(data.tokenB, data.payer, msg.sender, amountB);
}
}
function addLiquidity(
IPool pool,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount
)
private
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
)
{
if (tokenId == 0) {
if (IPosition(position).tokenOfOwnerByIndexExists(msg.sender, 0)) {
tokenId = IPosition(position).tokenOfOwnerByIndex(msg.sender, 0);
} else {
tokenId = IPosition(position).mint(msg.sender);
}
}
receivingTokenId = tokenId;
AddLiquidityCallbackData memory data = AddLiquidityCallbackData({
tokenA: pool.tokenA(),
tokenB: pool.tokenB(),
pool: pool,
payer: msg.sender
});
(tokenAAmount, tokenBAmount, binDeltas) = pool.addLiquidity(
tokenId,
params,
abi.encode(data)
);
require(
tokenAAmount >= minTokenAAmount && tokenBAmount >= minTokenBAmount,
"Too little added"
);
}
function addLiquidityToPool(
IPool pool,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
payable
checkDeadline(deadline)
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
)
{
return addLiquidity(pool, tokenId, params, minTokenAAmount, minTokenBAmount);
}
function addLiquidityWTickLimits(
IPool pool,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
int32 minActiveTick,
int32 maxActiveTick,
uint256 deadline
)
external
payable
checkDeadline(deadline)
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
)
{
int32 activeTick = pool.getState().activeTick;
require(
activeTick >= minActiveTick && activeTick <= maxActiveTick,
"activeTick not in range"
);
return addLiquidity(pool, tokenId, params, minTokenAAmount, minTokenBAmount);
}
function getOrCreatePool(PoolParams calldata poolParams) private returns (IPool pool) {
{
pool = IFactory(factory).lookup(
poolParams.fee,
poolParams.tickSpacing,
poolParams.lookback,
poolParams.tokenA,
poolParams.tokenB
);
}
if (address(pool) == address(0)) {
pool = IFactory(factory).create(
poolParams.fee,
poolParams.tickSpacing,
poolParams.lookback,
poolParams.activeTick,
poolParams.tokenA,
poolParams.tokenB
);
}
}
function getOrCreatePoolAndAddLiquidity(
PoolParams calldata poolParams,
uint256 tokenId,
IPool.AddLiquidityParams[] calldata addParams,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
payable
checkDeadline(deadline)
returns (
uint256 receivingTokenId,
uint256 tokenAAmount,
uint256 tokenBAmount,
IPool.BinDelta[] memory binDeltas
)
{
IPool pool = getOrCreatePool(poolParams);
return addLiquidity(pool, tokenId, addParams, minTokenAAmount, minTokenBAmount);
}
function migrateBinsUpStack(
IPool pool,
uint128[] calldata binIds,
uint32 maxRecursion,
uint256 deadline
) external checkDeadline(deadline) {
for (uint256 i = 0; i < binIds.length; i++) {
pool.migrateBinUpStack(binIds[i], maxRecursion);
}
}
function removeLiquidity(
IPool pool,
address recipient,
uint256 tokenId,
IPool.RemoveLiquidityParams[] calldata params,
uint256 minTokenAAmount,
uint256 minTokenBAmount,
uint256 deadline
)
external
checkDeadline(deadline)
returns (uint256 tokenAAmount, uint256 tokenBAmount, IPool.BinDelta[] memory binDeltas)
{
require(msg.sender == position.ownerOf(tokenId), "P");
if (recipient == address(0)) recipient = address(this);
(tokenAAmount, tokenBAmount, binDeltas) = pool.removeLiquidity(recipient, tokenId, params);
require(
tokenAAmount >= minTokenAAmount && tokenBAmount >= minTokenBAmount,
"Too little removed"
);
}
}
文件 21 的 23:SelfPermit.sol
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../interfaces/ISelfPermit.sol";
import "../interfaces/external/IERC20PermitAllowed.sol";
abstract contract SelfPermit is ISelfPermit {
function selfPermit(
address token,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public payable override {
IERC20Permit(token).permit(msg.sender, address(this), value, deadline, v, r, s);
}
function selfPermitIfNecessary(
address token,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable override {
if (IERC20(token).allowance(msg.sender, address(this)) < value)
selfPermit(token, value, deadline, v, r, s);
}
function selfPermitAllowed(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public payable override {
IERC20PermitAllowed(token).permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
}
function selfPermitAllowedIfNecessary(
address token,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external payable override {
if (IERC20(token).allowance(msg.sender, address(this)) < type(uint256).max)
selfPermitAllowed(token, nonce, expiry, v, r, s);
}
}
文件 22 的 23:TransferHelper.sol
pragma solidity >=0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
library TransferHelper {
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "STF");
}
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.transfer.selector, to, value)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "ST");
}
function safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.approve.selector, to, value)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "SA");
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "STE");
}
}
文件 23 的 23:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/Router.sol": "Router"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IFactory","name":"_factory","type":"address"},{"internalType":"contract IWETH9","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"contract IWETH9","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"addLiquidityCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"pos","type":"int32"},{"internalType":"bool","name":"isDelta","type":"bool"},{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"}],"internalType":"struct IPool.AddLiquidityParams[]","name":"params","type":"tuple[]"},{"internalType":"uint256","name":"minTokenAAmount","type":"uint256"},{"internalType":"uint256","name":"minTokenBAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityToPool","outputs":[{"internalType":"uint256","name":"receivingTokenId","type":"uint256"},{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"},{"components":[{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"},{"internalType":"uint256","name":"deltaLpBalance","type":"uint256"},{"internalType":"uint128","name":"binId","type":"uint128"},{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"lowerTick","type":"int32"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct IPool.BinDelta[]","name":"binDeltas","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"pos","type":"int32"},{"internalType":"bool","name":"isDelta","type":"bool"},{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"}],"internalType":"struct IPool.AddLiquidityParams[]","name":"params","type":"tuple[]"},{"internalType":"uint256","name":"minTokenAAmount","type":"uint256"},{"internalType":"uint256","name":"minTokenBAmount","type":"uint256"},{"internalType":"int32","name":"minActiveTick","type":"int32"},{"internalType":"int32","name":"maxActiveTick","type":"int32"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityWTickLimits","outputs":[{"internalType":"uint256","name":"receivingTokenId","type":"uint256"},{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"},{"components":[{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"},{"internalType":"uint256","name":"deltaLpBalance","type":"uint256"},{"internalType":"uint128","name":"binId","type":"uint128"},{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"lowerTick","type":"int32"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct IPool.BinDelta[]","name":"binDeltas","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint256","name":"sqrtPriceLimitD18","type":"uint256"}],"internalType":"struct ISlimRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct ISlimRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"tickSpacing","type":"uint256"},{"internalType":"int256","name":"lookback","type":"int256"},{"internalType":"int32","name":"activeTick","type":"int32"},{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"}],"internalType":"struct IRouter.PoolParams","name":"poolParams","type":"tuple"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"pos","type":"int32"},{"internalType":"bool","name":"isDelta","type":"bool"},{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"}],"internalType":"struct IPool.AddLiquidityParams[]","name":"addParams","type":"tuple[]"},{"internalType":"uint256","name":"minTokenAAmount","type":"uint256"},{"internalType":"uint256","name":"minTokenBAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"getOrCreatePoolAndAddLiquidity","outputs":[{"internalType":"uint256","name":"receivingTokenId","type":"uint256"},{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"},{"components":[{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"},{"internalType":"uint256","name":"deltaLpBalance","type":"uint256"},{"internalType":"uint128","name":"binId","type":"uint128"},{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"lowerTick","type":"int32"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct IPool.BinDelta[]","name":"binDeltas","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"uint128[]","name":"binIds","type":"uint128[]"},{"internalType":"uint32","name":"maxRecursion","type":"uint32"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"migrateBinsUpStack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"position","outputs":[{"internalType":"contract IPosition","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPool","name":"pool","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint128","name":"binId","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IPool.RemoveLiquidityParams[]","name":"params","type":"tuple[]"},{"internalType":"uint256","name":"minTokenAAmount","type":"uint256"},{"internalType":"uint256","name":"minTokenBAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"tokenAAmount","type":"uint256"},{"internalType":"uint256","name":"tokenBAmount","type":"uint256"},{"components":[{"internalType":"uint128","name":"deltaA","type":"uint128"},{"internalType":"uint128","name":"deltaB","type":"uint128"},{"internalType":"uint256","name":"deltaLpBalance","type":"uint256"},{"internalType":"uint128","name":"binId","type":"uint128"},{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"int32","name":"lowerTick","type":"int32"},{"internalType":"bool","name":"isActive","type":"bool"}],"internalType":"struct IPool.BinDelta[]","name":"binDeltas","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"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":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"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":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToPay","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"swapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]