Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/validators/KSZapValidatorV2Part1.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {ZapTypeHash} from 'contracts/common/ZapTypeHash.sol';
import {IAlgebraV19NFT} from 'contracts/interfaces/algebrav19/IAlgebraV19NFT.sol';
import {
IBinPoolManager,
PoolId as PancakeV4PoolId
} from 'contracts/interfaces/pancakev4/IBinPoolManager.sol';
import {IBinPositionManager} from 'contracts/interfaces/pancakev4/IBinPositionManager.sol';
import {IBinPositionManager} from 'contracts/interfaces/pancakev4/IBinPositionManager.sol';
import {ICLPositionManager as IPancakeV4CLNFT} from
'contracts/interfaces/pancakev4/ICLPositionManager.sol';
import {ISolidlyV3Pool} from 'contracts/interfaces/solidlyv3/ISolidlyV3Pool.sol';
import {IUniswapv3NFT} from 'contracts/interfaces/uniswapv3/IUniswapv3NFT.sol';
import {
IPositionManager as IUniswapV4NFT,
PositionInfo
} from 'contracts/interfaces/uniswapv4/IPositionManager.sol';
import {IERC1155} from 'openzeppelin/contracts/token/ERC1155/IERC1155.sol';
import {IERC20} from 'openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IERC721} from 'openzeppelin/contracts/token/ERC721/IERC721.sol';
import {Strings} from 'openzeppelin/contracts/utils/Strings.sol';
import './KSZapValidatorV2Base.sol';
import {IKSZapValidatorV2Part1} from
'contracts/interfaces/zap/validators/IKSZapValidatorV2Part1.sol';
contract KSZapValidatorV2Part1 is KSZapValidatorV2Base, IKSZapValidatorV2Part1 {
function _prepareUniswapV3ValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
UniswapV3ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (UniswapV3ZapInfo));
if (data.zapInfo.posID == 0) {
// minting new position, temporary store the total supply here
data.zapInfo.posID = IUniswapv3NFT(data.zapInfo.posManager).totalSupply();
} else {
(,,,,,,, data.initialLiquidity,,,,) =
IUniswapv3NFT(data.zapInfo.posManager).positions(data.zapInfo.posID);
}
return abi.encode(data);
}
function _prepareAlgebraValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
UniswapV3ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (UniswapV3ZapInfo));
if (data.zapInfo.posID == 0) {
// minting new position, temporary store the total supply here
data.zapInfo.posID = IAlgebraV19NFT(data.zapInfo.posManager).totalSupply();
} else {
(,,,,,, data.initialLiquidity,,,,) =
IAlgebraV19NFT(data.zapInfo.posManager).positions(data.zapInfo.posID);
}
return abi.encode(data);
}
/// @notice Generate initial data for validation for zap out action
/// @param _zapInfo contains info of zap out
function _prepareERC20ValidationData(bytes memory _zapInfo) internal view returns (bytes memory) {
ERC20ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (ERC20ZapInfo));
data.initialBalance = data.zapInfo.token == ETH_ADDRESS
? data.zapInfo.recipient.balance
: IERC20(data.zapInfo.token).balanceOf(data.zapInfo.recipient);
return abi.encode(data);
}
/// @notice Generate initial data for validation zap out with multi ERC20 token
/// @param _zapInfo contains info of zap out with multi ERC20 token
function _prepareMultiERC20ValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
MultiERC20ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (ERC20ZapInfo[]));
data.initialBalances = new uint256[](data.zapInfo.length);
for (uint256 i; i < data.zapInfo.length; ++i) {
data.initialBalances[i] = data.zapInfo[i].token == ETH_ADDRESS
? data.zapInfo[i].recipient.balance
: IERC20(data.zapInfo[i].token).balanceOf(data.zapInfo[i].recipient);
}
return abi.encode(data);
}
/// @notice Generate initial data for validation for zap in Solidly V3
/// @param _zapInfo contains info of zap in Solidly V3
function _prepareSolidlyV3ValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
SolidlyV3ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (SolidlyV3ZapInfo));
bytes32 positionKey = keccak256(
abi.encodePacked(data.zapInfo.recipient, data.zapInfo.tickLower, data.zapInfo.tickUpper)
);
(data.initialLiquidity,,) = ISolidlyV3Pool(data.zapInfo.pool).positions(positionKey);
return abi.encode(data);
}
/// @notice Generate initial data for validation for zap in Uniswap V4
/// @param _zapInfo contains info of zap in Uniswap V4
function _prepareUniswapV4ValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
UniswapV4ValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (UniswapV4ZapInfo));
IUniswapV4NFT posManager = IUniswapV4NFT(data.zapInfo.posManager);
if (data.zapInfo.tokenId == 0) {
data.zapInfo.tokenId = posManager.nextTokenId();
} else {
data.initialLiquidity = posManager.getPositionLiquidity(data.zapInfo.tokenId);
}
return abi.encode(data);
}
function _preparePancakeV4BinValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
PancakeV4BinZapInfo memory zapInfo = abi.decode(_zapInfo, (PancakeV4BinZapInfo));
PancakeV4BinValidationData memory data;
data.zapInfo = zapInfo;
data.shares = new uint256[](zapInfo.deltaIds.length);
PancakeV4PoolId poolId = PancakeV4PoolId.wrap(zapInfo.poolId);
{
(uint256 activeId,,) = IBinPoolManager(zapInfo.poolManager).getSlot0(poolId);
data.activeId = int24(int256(activeId));
}
for (uint256 i = 0; i < zapInfo.deltaIds.length; i++) {
int24 binId = data.activeId + zapInfo.deltaIds[i];
uint256 tokenId = _getTokenId(poolId, binId);
data.shares[i] = IERC1155(zapInfo.posManager).balanceOf(zapInfo.recipient, tokenId);
}
return abi.encode(data);
}
function _prepareUniversalCLValidationData(bytes memory _zapInfo)
internal
view
returns (bytes memory)
{
UniversalCLValidationData memory data;
data.zapInfo = abi.decode(_zapInfo, (UniversalCLZapInfo));
if (data.zapInfo.posID == 0) {
// minting new position, temporary store the total supply here
data.zapInfo.posID = IUniswapv3NFT(data.zapInfo.posManager).totalSupply();
} else {
address posManager = data.zapInfo.posManager;
(bool success, bytes memory result) = address(posManager).staticcall(
abi.encodeWithSelector(IUniswapv3NFT.positions.selector, data.zapInfo.posID)
);
require(success, 'ZapValidator: failed to fetch position info');
uint256 offset = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields >> 64);
uint128 initialLiquidity;
assembly {
initialLiquidity := mload(add(result, offset))
}
data.initialLiquidity = initialLiquidity;
}
return abi.encode(data);
}
/// @notice Validate result for zapping into Uniswap V3
/// 2 cases:
/// - new position:
/// + posID is the totalSupply, need to fetch the corresponding posID
/// + _extraData contains (recipient, posTickLower, posTickLower, minLiquidity) where:
/// (+) recipient is the owner of the posID
/// (+) posTickLower, posTickUpper are matched with position's tickLower/tickUpper
/// (+) pool is matched with position's pool
/// (+) minLiquidity <= pos.liquidity
/// - increase liquidity:
/// + _extraData contains minLiquidity, where:
/// (+) minLiquidity <= (pos.liquidity - initialLiquidity)
function _validateUniswapV3Result(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV3ValidationData memory data = abi.decode(_validationData, (UniswapV3ValidationData));
IUniswapv3NFT posManager = IUniswapv3NFT(data.zapInfo.posManager);
UniswapV3ExtraData memory extraData = abi.decode(_extraData, (UniswapV3ExtraData));
uint128 newLiquidity;
if (extraData.tickLower < extraData.tickUpper) {
// minting a new position, need to validate many data
// Calculate the posID and replace, it should be the last index
uint256 posID = posManager.tokenByIndex(data.zapInfo.posID);
// require owner of the pos id is the recipient
if (posManager.ownerOf(posID) != extraData.recipient) return false;
// getting pos info from Position Manager
int24 tickLower;
int24 tickUpper;
(,,,,, tickLower, tickUpper, newLiquidity,,,,) = posManager.positions(posID);
// tick ranges should match
if (extraData.tickLower != tickLower || extraData.tickUpper != tickUpper) {
return false;
}
} else {
// not a new position, only need to verify liquidity increment
// getting new position liquidity, make sure it is increased
(,,,,,,, newLiquidity,,,,) = posManager.positions(data.zapInfo.posID);
}
return newLiquidity >= extraData.minLiquidity + data.initialLiquidity;
}
/// @notice Validate result for zapping into Algebra
/// 2 cases:
/// - new position:
/// + posID is the totalSupply, need to fetch the corresponding posID
/// + _extraData contains (recipient, posTickLower, posTickLower, minLiquidity) where:
/// (+) recipient is the owner of the posID
/// (+) posTickLower, posTickUpper are matched with position's tickLower/tickUpper
/// (+) pool is matched with position's pool
/// (+) minLiquidity <= pos.liquidity
/// - increase liquidity:
/// + _extraData contains minLiquidity, where:
/// (+) minLiquidity <= (pos.liquidity - initialLiquidity)
function _validateAlgebraResult(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV3ValidationData memory data = abi.decode(_validationData, (UniswapV3ValidationData));
IAlgebraV19NFT posManager = IAlgebraV19NFT(data.zapInfo.posManager);
UniswapV3ExtraData memory extraData = abi.decode(_extraData, (UniswapV3ExtraData));
uint128 newLiquidity;
if (extraData.tickLower < extraData.tickUpper) {
// minting a new position, need to validate many data
// Calculate the posID and replace, it should be the last index
uint256 posID = posManager.tokenByIndex(data.zapInfo.posID);
// require owner of the pos id is the recipient
if (posManager.ownerOf(posID) != extraData.recipient) return false;
// getting pos info from Position Manager
int24 tickLower;
int24 tickUpper;
(,,,, tickLower, tickUpper, newLiquidity,,,,) = posManager.positions(posID);
// tick ranges should match
if (extraData.tickLower != tickLower || extraData.tickUpper != tickUpper) {
return false;
}
} else {
// not a new position, only need to verify liquidty increment
// getting new position liquidity, make sure it is increased
(,,,,,, newLiquidity,,,,) = posManager.positions(data.zapInfo.posID);
}
return newLiquidity >= extraData.minLiquidity + data.initialLiquidity;
}
function _validateERC20Result(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
ERC20ValidationData memory data = abi.decode(_validationData, (ERC20ValidationData));
uint256 minAmountOut = abi.decode(_extraData, (uint256));
uint256 currentBalance = data.zapInfo.token == ETH_ADDRESS
? data.zapInfo.recipient.balance
: IERC20(data.zapInfo.token).balanceOf(data.zapInfo.recipient);
return currentBalance >= data.initialBalance + minAmountOut;
}
function _validateMultiERC20Result(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
MultiERC20ValidationData memory data = abi.decode(_validationData, (MultiERC20ValidationData));
uint256[] memory minAmountOuts = abi.decode(_extraData, (uint256[]));
uint256 currentBalance;
for (uint256 i; i < data.zapInfo.length; ++i) {
currentBalance = data.zapInfo[i].token == ETH_ADDRESS
? data.zapInfo[i].recipient.balance
: IERC20(data.zapInfo[i].token).balanceOf(data.zapInfo[i].recipient);
require(
currentBalance >= data.initialBalances[i] + minAmountOuts[i],
string(
abi.encodePacked(
'ZapValidator: insufficient output amount for token ',
Strings.toHexString(data.zapInfo[i].token),
'. Expected: ',
Strings.toString(minAmountOuts[i]),
', Got: ',
Strings.toString(currentBalance - data.initialBalances[i])
)
)
);
}
return true;
}
function _validateSolidlyV3Result(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
SolidlyV3ValidationData memory data = abi.decode(_validationData, (SolidlyV3ValidationData));
bytes32 positionKey = keccak256(
abi.encodePacked(data.zapInfo.recipient, data.zapInfo.tickLower, data.zapInfo.tickUpper)
);
(uint256 newLiquidity,,) = ISolidlyV3Pool(data.zapInfo.pool).positions(positionKey);
uint256 minLiquidity = abi.decode(_extraData, (uint256));
return newLiquidity >= minLiquidity + data.initialLiquidity;
}
function _validatePancakeV4CLResult(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV4ValidationData memory data = abi.decode(_validationData, (UniswapV4ValidationData));
(, int24 tickLower, int24 tickUpper, uint128 newLiquidity,,,) =
IPancakeV4CLNFT(data.zapInfo.posManager).positions(data.zapInfo.tokenId);
UniswapV4ExtraData memory extraData = abi.decode(_extraData, (UniswapV4ExtraData));
if (
IPancakeV4CLNFT(data.zapInfo.posManager).ownerOf(data.zapInfo.tokenId) != extraData.recipient
) {
return false;
}
if (extraData.tickLower < extraData.tickUpper) {
// tick ranges should match
if (extraData.tickLower != tickLower || extraData.tickUpper != tickUpper) {
return false;
}
}
return newLiquidity >= extraData.minLiquidity + data.initialLiquidity;
}
function _validateUniswapV4Result(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV4ValidationData memory data = abi.decode(_validationData, (UniswapV4ValidationData));
IUniswapV4NFT posManager = IUniswapV4NFT(data.zapInfo.posManager);
int24 tickLower;
int24 tickUpper;
{
(, PositionInfo posInfo) = posManager.getPoolAndPositionInfo(data.zapInfo.tokenId);
assembly {
tickLower := signextend(2, shr(8, posInfo))
tickUpper := signextend(2, shr(32, posInfo))
}
}
uint128 newLiquidity = posManager.getPositionLiquidity(data.zapInfo.tokenId);
UniswapV4ExtraData memory extraData = abi.decode(_extraData, (UniswapV4ExtraData));
if (posManager.ownerOf(data.zapInfo.tokenId) != extraData.recipient) {
return false;
}
if (extraData.tickLower < extraData.tickUpper) {
// tick ranges should match
if (extraData.tickLower != tickLower || extraData.tickUpper != tickUpper) {
return false;
}
}
return newLiquidity >= extraData.minLiquidity + data.initialLiquidity;
}
function _validatePancakeV4BinResult(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
PancakeV4BinValidationData memory data =
abi.decode(_validationData, (PancakeV4BinValidationData));
PancakeV4BinExtraData memory extraData = abi.decode(_extraData, (PancakeV4BinExtraData));
PancakeV4PoolId poolId = PancakeV4PoolId.wrap(data.zapInfo.poolId);
for (uint256 i; i < data.zapInfo.deltaIds.length; ++i) {
int24 binId = int24(data.activeId) + data.zapInfo.deltaIds[i];
uint256 tokenId = _getTokenId(poolId, binId);
uint256 mintedShares = IERC1155(data.zapInfo.posManager).balanceOf(
data.zapInfo.recipient, tokenId
) - data.shares[i];
(uint256 reserveX, uint256 reserveY,, uint256 totalShares) =
IBinPoolManager(data.zapInfo.poolManager).getBin(poolId, uint24(binId));
if (
mintedShares * reserveX / totalShares < extraData.minReserveXs[i]
|| mintedShares * reserveY / totalShares < extraData.minReserveYs[i]
) {
return false;
}
}
return true;
}
/// @notice Validate result for zapping into Universal CL
/// 2 cases:
/// - new position:
/// + posID is the totalSupply, need to fetch the corresponding posID
/// + _extraData contains (recipient, posTickLower, posTickLower, minLiquidity) where:
/// (+) recipient is the owner of the posID
/// (+) posTickLower, posTickUpper are matched with position's tickLower/tickUpper
/// (+) pool is matched with position's pool
/// (+) minLiquidity <= pos.liquidity
/// - increase liquidity:
/// + _extraData contains minLiquidity, where:
/// (+) minLiquidity <= (pos.liquidity - initialLiquidity)
function _validateUniversalCLResult(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniversalCLValidationData memory data = abi.decode(_validationData, (UniversalCLValidationData));
IUniswapv3NFT posManager = IUniswapv3NFT(data.zapInfo.posManager);
UniswapV3ExtraData memory extraData = abi.decode(_extraData, (UniswapV3ExtraData));
uint128 newLiquidity;
if (extraData.tickLower < extraData.tickUpper) {
// minting a new position, need to validate many data
// Calculate the posID and replace, it should be the last index
uint256 posID = posManager.tokenByIndex(data.zapInfo.posID);
(bool success, bytes memory result) = address(posManager).staticcall(
abi.encodeWithSelector(IUniswapv3NFT.positions.selector, posID)
);
require(success, 'ZapValidator: failed to fetch position info');
// require owner of the pos id is the recipient
if (posManager.ownerOf(posID) != extraData.recipient) return false;
// getting pos info from Position Manager
int24 tickLower;
int24 tickUpper;
uint256 offsetLower = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields);
uint256 offsetUpper = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields >> 32);
uint256 offsetLiquidity = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields >> 64);
assembly {
tickLower := mload(add(result, offsetLower))
tickUpper := mload(add(result, offsetUpper))
newLiquidity := mload(add(result, offsetLiquidity))
}
// tick ranges should match
if (extraData.tickLower != tickLower || extraData.tickUpper != tickUpper) {
return false;
}
} else {
// not a new position, only need to verify liquidity increment
// getting new position liquidity, make sure it is increased
(bool success, bytes memory result) = address(posManager).staticcall(
abi.encodeWithSelector(IUniswapv3NFT.positions.selector, data.zapInfo.posID)
);
require(success, 'ZapValidator: failed to fetch position info');
uint256 offsetLiquidity = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields >> 64);
assembly {
newLiquidity := mload(add(result, offsetLiquidity))
}
}
return newLiquidity >= extraData.minLiquidity + data.initialLiquidity;
}
/**
* @notice Validate the position after removing liquidity from Uniswap V3
* @param _extraData contains the expected liquidity to be removed
* @param _validationData contains the initial liquidity before removing
*/
function _validateUniswapV3Removing(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV3ValidationData memory data = abi.decode(_validationData, (UniswapV3ValidationData));
IUniswapv3NFT posManager = IUniswapv3NFT(data.zapInfo.posManager);
(,,,,,,, uint128 newLiquidity,,,,) = posManager.positions(data.zapInfo.posID);
(address owner, uint256 expectedRemoval) = abi.decode(_extraData, (address, uint256));
if (data.initialLiquidity - newLiquidity != expectedRemoval) {
return false;
}
return owner == posManager.ownerOf(data.zapInfo.posID);
}
/**
* @notice Validate the position after removing liquidity from Algebra
* @param _extraData contains the expected liquidity to be removed
* @param _validationData contains the initial liquidity before removing
*/
function _validateAlgebraRemoving(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV3ValidationData memory data = abi.decode(_validationData, (UniswapV3ValidationData));
IAlgebraV19NFT posManager = IAlgebraV19NFT(data.zapInfo.posManager);
(,,,,,, uint128 newLiquidity,,,,) = posManager.positions(data.zapInfo.posID);
(address owner, uint256 expectedRemoval) = abi.decode(_extraData, (address, uint256));
if (data.initialLiquidity - newLiquidity != expectedRemoval) {
return false;
}
return owner == posManager.ownerOf(data.zapInfo.posID);
}
/**
* @notice Validate the position after removing liquidity from Uniswap V4
* @param _extraData contains the expected liquidity to be removed
* @param _validationData contains the initial liquidity before removing
*/
function _validateUniswapV4Removing(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniswapV4ValidationData memory data = abi.decode(_validationData, (UniswapV4ValidationData));
IUniswapV4NFT posManager = IUniswapV4NFT(data.zapInfo.posManager);
uint128 newLiquidity = posManager.getPositionLiquidity(data.zapInfo.tokenId);
(address owner, uint256 expectedRemoval) = abi.decode(_extraData, (address, uint256));
if (data.initialLiquidity - newLiquidity != expectedRemoval) {
return false;
}
return owner == posManager.ownerOf(data.zapInfo.tokenId);
}
/**
* @notice Validate the position after removing liquidity from Uniswap V3
* @param _extraData contains the expected liquidity to be removed
* @param _validationData contains the initial liquidity before removing
*/
function _validateUniversalCLRemoving(bytes memory _extraData, bytes memory _validationData)
internal
view
returns (bool)
{
UniversalCLValidationData memory data = abi.decode(_validationData, (UniversalCLValidationData));
address posManager = data.zapInfo.posManager;
(bool success, bytes memory result) = address(posManager).staticcall(
abi.encodeWithSelector(IUniswapv3NFT.positions.selector, data.zapInfo.posID)
);
require(success, 'ZapValidator: failed to fetch position info');
uint256 offset = 0x20 + 0x20 * uint32(data.zapInfo.offsetPositionFields >> 64);
uint128 newLiquidity;
assembly {
newLiquidity := mload(add(result, offset))
}
(address owner, uint256 expectedRemoval) = abi.decode(_extraData, (address, uint256));
if (data.initialLiquidity - newLiquidity != expectedRemoval) {
return false;
}
return owner == IERC721(posManager).ownerOf(data.zapInfo.posID) || newLiquidity == 0;
}
function _getPrepareDataFunction(bytes32 _type)
internal
pure
override
returns (function(bytes memory) internal view returns (bytes memory))
{
if (_type == UNISWAP_V3_TYPE) {
return _prepareUniswapV3ValidationData;
} else if (_type == ALGEBRA_V19_TYPE || _type == ALGEBRA_V19_DIRFEE_TYPE) {
return _prepareAlgebraValidationData;
} else if (_type == ERC20_TYPE) {
return _prepareERC20ValidationData;
} else if (_type == SOLIDLY_V3_TYPE) {
return _prepareSolidlyV3ValidationData;
} else if (_type == PANCAKE_V4_CL_TYPE || _type == UNISWAP_V4_TYPE) {
return _prepareUniswapV4ValidationData;
} else if (_type == MULTI_ERC20_TYPE) {
return _prepareMultiERC20ValidationData;
} else if (_type == UNIVERSAL_CL_TYPE) {
return _prepareUniversalCLValidationData;
} else if (_type == PANCAKE_V4_BIN_TYPE) {
return _preparePancakeV4BinValidationData;
} else {
return _prepareNoneValidationData;
}
}
function _getValidateResultsFunction(bytes32 _type)
internal
pure
override
returns (function(bytes memory, bytes memory) internal view returns (bool))
{
if (_type == UNISWAP_V3_TYPE) {
return _validateUniswapV3Result;
} else if (_type == ALGEBRA_V19_TYPE || _type == ALGEBRA_V19_DIRFEE_TYPE) {
return _validateAlgebraResult;
} else if (_type == ERC20_TYPE) {
return _validateERC20Result;
} else if (_type == SOLIDLY_V3_TYPE) {
return _validateSolidlyV3Result;
} else if (_type == PANCAKE_V4_CL_TYPE) {
return _validatePancakeV4CLResult;
} else if (_type == UNISWAP_V4_TYPE) {
return _validateUniswapV4Result;
} else if (_type == MULTI_ERC20_TYPE) {
return _validateMultiERC20Result;
} else if (_type == UNIVERSAL_CL_TYPE) {
return _validateUniversalCLResult;
} else if (_type == PANCAKE_V4_BIN_TYPE) {
return _validatePancakeV4BinResult;
} else {
return _validateNoneResult;
}
}
function _getValidateRemovingFunction(bytes32 _type)
internal
pure
override
returns (function(bytes memory, bytes memory) internal view returns (bool))
{
if (_type == UNISWAP_V3_TYPE) {
return _validateUniswapV3Removing;
} else if (_type == ALGEBRA_V19_TYPE || _type == ALGEBRA_V19_DIRFEE_TYPE) {
return _validateAlgebraRemoving;
} else if (_type == PANCAKE_V4_CL_TYPE || _type == UNISWAP_V4_TYPE) {
return _validateUniswapV4Removing;
} else if (_type == UNIVERSAL_CL_TYPE) {
return _validateUniversalCLRemoving;
} else {
return _validateNoneRemoving;
}
}
function _getTokenId(PancakeV4PoolId poolId, int256 binId) internal pure returns (uint256) {
return uint256(keccak256(abi.encode(poolId, binId)));
}
}
"
},
"contracts/common/ZapTypeHash.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
abstract contract ZapTypeHash {
bytes32 public constant NONE_TYPE = keccak256('None');
bytes32 public constant UNISWAP_V3_TYPE = keccak256('UniswapV3');
bytes32 public constant ALGEBRA_V19_TYPE = keccak256('AlgebraV19');
bytes32 public constant ALGEBRA_V19_DIRFEE_TYPE = keccak256('AlgebraV19DirFee');
bytes32 public constant SOLIDLY_V3_TYPE = keccak256('SolidlyV3');
bytes32 public constant ERC20_TYPE = keccak256('ERC20');
bytes32 public constant PANCAKE_V4_CL_TYPE = keccak256('PancakeSwapV4CL');
bytes32 public constant UNISWAP_V4_TYPE = keccak256('UniswapV4');
bytes32 public constant FLUID_VAULT_TYPE = keccak256('FluidVault');
bytes32 public constant MULTI_ERC20_TYPE = keccak256('MultiERC20');
bytes32 public constant UNIVERSAL_CL_TYPE = keccak256('UniversalCL');
bytes32 public constant MAVERICK_TYPE = keccak256('Maverick');
bytes32 public constant PANCAKE_V4_BIN_TYPE = keccak256('PancakeV4Bin');
}
"
},
"contracts/interfaces/algebrav19/IAlgebraV19NFT.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
interface IAlgebraV19NFT {
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
struct MintParams {
address token0;
address token1;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function mint(MintParams calldata params)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function increaseLiquidity(IncreaseLiquidityParams calldata params)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function collect(CollectParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
function sweepToken(address token, uint256 amountMinimum, address recipient) external payable;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address spender, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function WETH9() external view returns (address);
function ownerOf(uint256 tokenId) external view returns (address);
function tokenByIndex(uint256 index) external view returns (uint256);
function totalSupply() external view returns (uint256);
}
"
},
"contracts/interfaces/pancakev4/IBinPoolManager.sol": {
"content": "//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {BalanceDelta, PoolId, PoolKey} from './Types.sol';
interface IBinPoolManager {
/// @notice PoolManagerMismatch is thrown when pool manager specified in the pool key does not match current contract
error PoolManagerMismatch();
/// @notice Pool binStep cannot be lesser than 1. Otherwise there will be no price jump between bin
error BinStepTooSmall(uint16 binStep);
/// @notice Pool binstep cannot be greater than the limit set at maxBinStep
error BinStepTooLarge(uint16 binStep);
/// @notice Error thrown when owner set max bin step too small
error MaxBinStepTooSmall(uint16 maxBinStep);
/// @notice Error thrown when bin has insufficient shares to accept donation
error InsufficientBinShareForDonate(uint256 shares);
/// @notice Error thrown when amount specified is 0 in swap
error AmountSpecifiedIsZero();
/// @notice Returns the constant representing the max bin step
/// @return maxBinStep a value of 100 would represent a 1% price jump between bin (limit can be raised by owner)
function maxBinStep() external view returns (uint16);
/// @notice Returns the constant representing the min bin step
/// @dev 1 would represent a 0.01% price jump between bin
function MIN_BIN_STEP() external view returns (uint16);
/// @notice min share in bin before donate is allowed in current bin
function minBinShareForDonate() external view returns (uint256);
/// @notice Emitted for swaps between currency0 and currency1
/// @param id The abi encoded hash of the pool key struct for the pool that was modified
/// @param sender The address that initiated the swap call, and that received the callback
/// @param amount0 The delta of the currency0 balance of the pool
/// @param amount1 The delta of the currency1 balance of the pool
/// @param activeId The activeId of the pool after the swap
/// @param fee The fee collected upon every swap in the pool (including protocol fee and LP fee), denominated in hundredths of a bip
/// @param protocolFee Single direction protocol fee from the swap, also denominated in hundredths of a bip
event Swap(
PoolId indexed id,
address indexed sender,
int128 amount0,
int128 amount1,
uint24 activeId,
uint24 fee,
uint16 protocolFee
);
/// @notice Emitted when liquidity is added
/// @param id The abi encoded hash of the pool key struct for the pool that was modified
/// @param sender The address that modified the pool
/// @param ids List of binId with liquidity added
/// @param salt The salt to distinguish different mint from the same owner
/// @param amounts List of amount added to each bin
/// @param compositionFeeAmount fee occurred
/// @param feeAmountToProtocol Protocol fee from the swap: token0 and token1 amount
event Mint(
PoolId indexed id,
address indexed sender,
uint256[] ids,
bytes32 salt,
bytes32[] amounts,
bytes32 compositionFeeAmount,
bytes32 feeAmountToProtocol
);
/// @notice Emitted when liquidity is removed
/// @param id The abi encoded hash of the pool key struct for the pool that was modified
/// @param sender The address that modified the pool
/// @param ids List of binId with liquidity removed
/// @param salt The salt to specify the position to burn if multiple positions are available
/// @param amounts List of amount removed from each bin
event Burn(
PoolId indexed id, address indexed sender, uint256[] ids, bytes32 salt, bytes32[] amounts
);
/// @notice Emitted when donate happen
/// @param id The abi encoded hash of the pool key struct for the pool that was modified
/// @param sender The address that modified the pool
/// @param amount0 The delta of the currency0 balance of the pool
/// @param amount1 The delta of the currency1 balance of the pool
/// @param binId The donated bin id
event Donate(
PoolId indexed id, address indexed sender, int128 amount0, int128 amount1, uint24 binId
);
/// @notice Emitted when min share for donate is updated
event SetMinBinSharesForDonate(uint256 minLiquidity);
/// @notice Emitted when bin step is updated
event SetMaxBinStep(uint16 maxBinStep);
struct MintParams {
bytes32[] liquidityConfigs;
/// @dev amountIn intended
bytes32 amountIn;
/// the salt to distinguish different mint from the same owner
bytes32 salt;
}
struct BurnParams {
/// @notice id of the bin from which to withdraw
uint256[] ids;
/// @notice amount of share to burn for each bin
uint256[] amountsToBurn;
/// the salt to specify the position to burn if multiple positions are available
bytes32 salt;
}
/// @notice Get the current value in slot0 of the given pool
function getSlot0(PoolId id)
external
view
returns (uint24 activeId, uint24 protocolFee, uint24 lpFee);
/// @notice Returns the reserves of a bin
/// @param id The id of the bin
/// @return binReserveX The reserve of token X in the bin
/// @return binReserveY The reserve of token Y in the bin
/// @return binLiquidity The total liquidity in the bin
/// @return totalShares The total shares minted in the bin
function getBin(PoolId id, uint24 binId)
external
view
returns (uint128 binReserveX, uint128 binReserveY, uint256 binLiquidity, uint256 totalShares);
/// @notice Peform a swap to a pool
/// @param key The pool key
/// @param swapForY If true, swap token X for Y, if false, swap token Y for X
/// @param amountSpecified If negative, imply exactInput, if positive, imply exactOutput.
function swap(PoolKey memory key, bool swapForY, int128 amountSpecified, bytes calldata hookData)
external
returns (BalanceDelta delta);
}
"
},
"contracts/interfaces/pancakev4/IBinPositionManager.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IBinPoolManager} from './IBinPoolManager.sol';
import {IVault} from './IVault.sol';
import {BalanceDelta, CLPositionInfo, PoolKey} from './Types.sol';
import {IAllowanceTransfer} from 'contracts/interfaces/permit2/IAllowanceTransfer.sol';
interface IBinPositionManager {
/// @notice Thrown when the block.timestamp exceeds the user-provided deadline
error DeadlinePassed(uint256 deadline);
/// @notice Thrown when calling transfer, subscribe, or unsubscribe on CLPositionManager
/// or batchTransferFrom on BinPositionManager when the vault is locked.
/// @dev This is to prevent hooks from being able to trigger actions or notifications at the same time the position is being modified.
error VaultMustBeUnlocked();
/// @notice Thrown when the token ID is bind to an unexisting pool
error InvalidTokenID();
/// @notice Unlocks Vault and batches actions for modifying liquidity
/// @dev This is the standard entrypoint for the PositionManager
/// @param payload is an encoding of actions, and parameters for those actions
/// @param deadline is the deadline for the batched actions to be executed
function modifyLiquidities(bytes calldata payload, uint256 deadline) external payable;
/// @notice Batches actions for modifying liquidity without getting a lock from vault
/// @dev This must be called by a contract that has already locked the vault
/// @param actions the actions to perform
/// @param params the parameters to provide for the actions
function modifyLiquiditiesWithoutLock(bytes calldata actions, bytes[] calldata params)
external
payable;
error IdOverflows(int256);
error IdSlippageCaught(uint256 activeIdDesired, uint256 idSlippage, uint24 activeId);
error AddLiquidityInputActiveIdMismatch();
/// @notice BinAddLiquidityParams
/// - amount0: Amount to send for token0
/// - amount1: Amount to send for token1
/// - amount0Max: Max amount to send for token0
/// - amount1Max: Max amount to send for token1
/// - activeIdDesired: Active id that user wants to add liquidity from
/// - idSlippage: Number of id that are allowed to slip
/// - deltaIds: List of delta ids to add liquidity (`deltaId = activeId - desiredId`)
/// - distributionX: Distribution of tokenX with sum(distributionX) = 1e18 (100%) or 0 (0%)
/// - distributionY: Distribution of tokenY with sum(distributionY) = 1e18 (100%) or 0 (0%)
/// - to: Address of recipient
/// - hookData: Data to pass to the hook
struct BinAddLiquidityParams {
PoolKey poolKey;
uint128 amount0;
uint128 amount1;
uint128 amount0Max;
uint128 amount1Max;
uint256 activeIdDesired;
uint256 idSlippage;
int256[] deltaIds;
uint256[] distributionX;
uint256[] distributionY;
address to;
bytes hookData;
}
/// @notice BinRemoveLiquidityParams
/// - amount0Min: Min amount to receive for token0
/// - amount1Min: Min amount to receive for token1
/// - ids: List of bin ids to remove liquidity
/// - amounts: List of share amount to remove for each bin
/// - from: Address of NFT holder to burn the NFT
/// - hookData: Data to pass to the hook
struct BinRemoveLiquidityParams {
PoolKey poolKey;
uint128 amount0Min;
uint128 amount1Min;
uint256[] ids;
uint256[] amounts;
address from;
bytes hookData;
}
/// @notice BinAddLiquidityFromDeltasParams
/// - amount0Max: Max amount to send for token0
/// - amount1Max: Max amount to send for token1
/// - activeIdDesired: Active id that user wants to add liquidity from
/// - idSlippage: Number of id that are allowed to slip
/// - deltaIds: List of delta ids to add liquidity (`deltaId = activeId - desiredId`)
/// - distributionX: Distribution of tokenX with sum(distributionX) = 1e18 (100%) or 0 (0%)
/// - distributionY: Distribution of tokenY with sum(distributionY) = 1e18 (100%) or 0 (0%)
/// - to: Address of recipient
/// - hookData: Data to pass to the hook
struct BinAddLiquidityFromDeltasParams {
PoolKey poolKey;
uint128 amount0Max;
uint128 amount1Max;
uint256 activeIdDesired;
uint256 idSlippage;
int256[] deltaIds;
uint256[] distributionX;
uint256[] distributionY;
address to;
bytes hookData;
}
function binPoolManager() external view returns (IBinPoolManager);
/// @notice Initialize a infinity PCS bin pool
/// @dev If the pool is already initialized, this function will not revert
/// @param key the PoolKey of the pool to initialize
/// @param activeId the active bin id of the pool
function initializePool(PoolKey memory key, uint24 activeId) external payable;
/// @notice Return the position information associated with a given tokenId
/// @dev Revert if non-existent tokenId
/// @param tokenId Id of the token that represent position
/// @return poolKey the pool key of the position
/// @return binId the binId of the position
function positions(uint256 tokenId) external view returns (PoolKey memory poolKey, uint24 binId);
function permit2() external view returns (IAllowanceTransfer);
function vault() external view returns (IVault);
function approveForAll(address operator, bool approved) external;
}
"
},
"contracts/interfaces/pancakev4/ICLPositionManager.sol": {
"content": "//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ICLPoolManager} from './ICLPoolManager.sol';
import {IVault} from './IVault.sol';
import {BalanceDelta, CLPositionInfo, PoolKey} from './Types.sol';
import {IAllowanceTransfer} from 'contracts/interfaces/permit2/IAllowanceTransfer.sol';
interface ICLPositionManager {
/// @notice Thrown when the block.timestamp exceeds the user-provided deadline
error DeadlinePassed(uint256 deadline);
/// @notice Thrown when calling transfer, subscribe, or unsubscribe on CLPositionManager
/// or batchTransferFrom on BinPositionManager when the vault is locked.
/// @dev This is to prevent hooks from being able to trigger actions or notifications at the same time the position is being modified.
error VaultMustBeUnlocked();
/// @notice Thrown when the token ID is bind to an unexisting pool
error InvalidTokenID();
/// @notice Unlocks Vault and batches actions for modifying liquidity
/// @dev This is the standard entrypoint for the PositionManager
/// @param payload is an encoding of actions, and parameters for those actions
/// @param deadline is the deadline for the batched actions to be executed
function modifyLiquidities(bytes calldata payload, uint256 deadline) external payable;
/// @notice Batches actions for modifying liquidity without getting a lock from vault
/// @dev This must be called by a contract that has already locked the vault
/// @param actions the actions to perform
/// @param params the parameters to provide for the actions
function modifyLiquiditiesWithoutLock(bytes calldata actions, bytes[] calldata params)
external
payable;
/// @notice Thrown when the caller is not approved to modify a position
error NotApproved(address caller);
/// @notice Emitted when a new liquidity position is minted
event MintPosition(uint256 indexed tokenId);
/// @notice Emitted when liquidity is modified
/// @param tokenId the tokenId of the position that was modified
/// @param liquidityChange the change in liquidity of the position
/// @param feesAccrued the fees collected from the liquidity change
event ModifyLiquidity(uint256 indexed tokenId, int256 liquidityChange, BalanceDelta feesAccrued);
/// @notice Get the clPoolManager
function clPoolManager() external view returns (ICLPoolManager);
/// @notice Initialize a v4 PCS cl pool
/// @param key the PoolKey of the pool to initialize
/// @param sqrtPriceX96 the initial sqrtPriceX96 of the pool
function initializePool(PoolKey calldata key, uint160 sqrtPriceX96)
external
payable
returns (int24);
/// @notice Used to get the ID that will be used for the next minted liquidity position
/// @return uint256 The next token ID
function nextTokenId() external view returns (uint256);
/// @param tokenId the ERC721 tokenId
/// @return liquidity the position's liquidity, as a liquidityAmount
/// @dev this value can be processed as an amount0 and amount1 by using the LiquidityAmounts library
function getPositionLiquidity(uint256 tokenId) external view returns (uint128 liquidity);
/// @notice Get the detailed information for a specified position
/// @param tokenId the ERC721 tokenId
/// @return poolKey the pool key of the position
/// @return tickLower the lower tick of the position
/// @return tickUpper the upper tick of the position
/// @return liquidity the liquidity of the position
/// @return feeGrowthInside0LastX128 the fee growth count of token0 since last time updated
/// @return feeGrowthInside1LastX128 the fee growth count of token1 since last time updated
/// @return _subscriber the address of the subscriber, if not set, it returns address(0)
function positions(uint256 tokenId)
external
view
returns (
PoolKey memory poolKey,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
address _subscriber
);
/// @param tokenId the ERC721 tokenId
/// @return poolKey the pool key of the position
/// @return CLPositionInfo a uint256 packed value holding information about the position including the range (tickLower, tickUpper)
function getPoolAndPositionInfo(uint256 tokenId)
external
view
returns (PoolKey memory, CLPositionInfo);
function permit2() external view returns (IAllowanceTransfer);
function approve(address to, uint256 tokenId) external;
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function vault() external view returns (IVault);
function poolKeys(bytes25 poolId) external view returns (PoolKey memory);
}
"
},
"contracts/interfaces/solidlyv3/ISolidlyV3Pool.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface ISolidlyV3Pool {
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
/// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
/// tick The current tick of the pool, i.e. according to the last tick transition that was run.
/// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// fee The pool's current fee in hundredths of a bip, i.e. 1e-6
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (uint160 sqrtPriceX96, int24 tick, uint24 fee, bool unlocked);
/// @notice The currently in range liquidity available to the pool
/// @dev This value has no relationship to the total liquidity across all ticks
function liquidity() external view returns (uint128);
/// @notice Look up information about a specific tick in the pool
/// @param tick The tick to look up
/// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
/// tick upper,
/// liquidityNet how much liquidity changes when the pool price crosses the tick,
/// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.
/// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
/// In addition, these values are only relative and must be used only in comparison to previous snapshots for
/// a specific position.
function ticks(int24 tick)
external
view
returns (uint128 liquidityGross, int128 liquidityNet, bool initialized);
/// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information
function tickBitmap(int16 wordPosition) external view returns (uint256);
/// @notice Returns the information about a position by the position's key
/// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper
/// @return _liquidity The amount of liquidity in the position,
/// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
/// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke
function positions(bytes32 key)
external
view
returns (uint128 _liquidity, uint128 tokensOwed0, uint128 tokensOwed1);
/// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
/// Uses callback for payments and includes additional slippage/deadline protection
/// @dev The caller of this method receives a callback in the form of ISolidlyV3MintCallback#solidlyV3MintCallback
/// in which they must pay any token0 or token1 owed for the liquidity
/// @param recipient The address for which the liquidity will be created
/// @param tickLower The lower tick of the position in which to add liquidity
/// @param tickUpper The upper tick of the position in which to add liquidity
/// @param amount The amount of liquidity to mint
/// @param amount0Min The minimum amount of token0 to spend, which serves as a slippage check
/// @param amount1Min The minimum amount of token1 to spend, which serves as a slippage check
/// @param deadline A constraint on the time by which the mint transaction must mined
/// @param data Any data to be passed through to the callback
/// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
/// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
uint256 amount0Min,
uint256 amount1Min,
uint256 deadline,
bytes calldata data
) external returns (uint256 amount0, uint256 amount1);
/// @notice Convenience method to burn liquidity and then collect owed tokens in one go
/// @param recipient The address which should receive the tokens collected
/// @param tickLower The lower tick of the position for which to collect tokens
/// @param tickUpper The upper tick of the position for which to collect tokens
/// @param amountToBurn How much liquidity to burn
/// @param amount0ToCollect How much token0 should be withdrawn from the tokens owed
/// @param amount1ToCollect How much token1 should be withdrawn from the tokens owed
/// @return amount0FromBurn The amount of token0 accrued to the position from the burn
/// @return amount1FromBurn The amount of token1 accrued to the position from the burn
/// @return amount0Collected The amount of token0 collected from the positions
/// @return amount1Collected The amount of token1 collected from the positions
function burnAndCollect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amountToBurn,
uint128 amount0ToCollect,
uint128 amount1ToCollect
)
external
returns (
uint256 amount0FromBurn,
uint256 amount1FromBurn,
uint128 amount0Collected,
uint128 amount1Collected
);
/// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
/// @dev Tokens must be collected separately via a call to #collect
/// @param tickLower The lower tick of the position for which to burn liquidity
/// @param tickUpper The upper tick of the position for which to burn liquidity
/// @param amount How much liquidity to burn
/// @return amount0 The amount of token0 sent to the recipient
/// @return amount1 The amount of token1 sent to the recipient
function burn(int24 tickLower, int24 tickUpper, uint128 amount)
external
returns (uint256 amount0, uint256 amount1);
/// @notice Swap token0 for token1, or token1 for token0
/// Uses a callback for payments; no additional slippage/deadline protection or referrer tracking
/// @dev The caller of this method receives a callback in the form of ISolidlyV3MintCallback#solidlyV3SwapCallback
/// in which they must pay any token0 or token1 owed for the swap
/// @param recipient The address to receive the output of the swap
/// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
/// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
/// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
/// value after the swap. If one for zero, the price cannot be greater than this value after the swap
/// @param data Any data to be passed through to the callback
/// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
/// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}
"
},
"contracts/interfaces/uniswapv3/IUniswapv3NFT.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
interface IUniswapv3NFT {
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function mint(MintParams calldata params)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function increaseLiquidity(IncreaseLiquidityParams calldata params)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function collect(CollectParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
function sweepToken(address token, uint256 amountMinimum, address recipient) external payable;
function transferFrom(address from, address to, uint256 tokenId) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function approve(address spender, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function WETH9() external view returns (address);
function ownerOf(uint256 tokenId) external view returns (address);
function tokenByIndex(uint256 index) external view returns (uint256);
function totalSupply() external view returns (uint256);
}
"
},
"contracts/interfaces/uniswapv4/IPositionManager.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import './IPoolManager.sol';
import {PositionInfo} from './Types.sol';
import {IAllowanceTransfer} from 'contracts/interfaces/permit2/IAllowanceTransfer.sol';
/// @title IPositionManager
/// @notice Interface for the PositionManager contract
interface IPositionManager {
/// @notice The Uniswap v4 PoolManager contract
function poolManager() external view returns (IPoolManager);
/// @notice Thrown when the caller is not approved to modify a position
error NotApproved(address caller);
/// @notice Thrown when the block.timestamp exceeds the user-provided deadline
error DeadlinePassed(uint256 deadline);
/// @notice Thrown when calling transfer, subscribe, or unsubscribe when the PoolManager is unlocked.
/// @dev This is to prevent hooks from being able to trigger notifications at the same time the position is being modified.
error PoolManagerMustBeLocked();
/// @notice Unlocks Uniswap v4 PoolManager and batches actions for modifying liquidity
/// @dev This is the standard entrypoint for the PositionManager
/// @param unlockData is an encoding of actions, and parameters for those actions
/// @param deadline is the deadline for the batched actions to be executed
function modifyLiquidities(bytes calldata unlockData, uint256 deadline) external payable;
/// @notice Batches actions for modifying liquidity without unlocking v4 PoolManager
/// @dev This must be called by a contract that has already unlocked the v4 PoolManager
/// @param actions the actions to perform
/// @param params the parameters to provide for the actions
function modifyLiquiditiesWithoutUnlock(bytes calldata actions, bytes[] calldata params)
external
payable;
/// @notice Used to get the ID that will be used for the next minted liquidity position
/// @return uint256 The next token ID
function nextTokenId() external view returns (uint256);
/// @param tokenId the ERC721 tokenId
/// @return liquidity the position's liquidity, as a liquidityAmount
/// @dev this value can be processed as an amount0 and amount1 by using the LiquidityAmounts library
function getPositionLiquidity(uint256 tokenId) external view returns (uint128 liquidity);
/// @param tokenId the ERC721 tokenId
/// @return PositionInfo a uint256 packed value holding information about the position including the range (tickLower, tickUpper)
/// @return poolKey the pool key of the position
function getPoolAndPositionInfo(uint256 tokenId)
external
view
returns (PoolKey memory, PositionInfo);
function permit2() external view returns (IAllowanceTransfer);
function approve(address to, uint256 tokenId) external;
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function poolKeys(bytes25 poolId) external view returns (PoolKey memory);
}
"
},
"lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) exte
Submitted on: 2025-10-06 16:14:06
Comments
Log in to comment.
No comments yet.