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/XStakingFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./interfaces/IToken.sol";
import "./interfaces/IXStakingPool.sol";
import "./interfaces/IXStakingFactory.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
/**
* @title XStakingFactory
* @dev This contract is used to deploy and manage XStakingPool contracts.
* It uses an upgradeable beacon pattern for creating pools, allowing for future upgrades.
* @custom:oz-upgrades-from XStakingFactoryV1
*/
contract XStakingFactory is
Initializable,
Ownable2StepUpgradeable,
IXStakingFactory,
ReentrancyGuardUpgradeable
{
using SafeERC20 for IToken;
/// @dev 10000 = 100%
uint256 public constant FEE_DENOMINATOR = 100_00;
/// @dev 10000 = 100%
uint256 public constant SLIPPAGE_DENOMINATOR = 1000;
/// @notice the beacon of BeaconProxy pattern
UpgradeableBeacon public beacon;
/// @notice address of smart contract with logic of pool
IXStakingPool public xstakingPoolImplementation;
/// @notice address of treasury wallet
address public treasuryWallet;
/// @notice records of all deployed staking pools
address[] public xstakingPools;
/// @notice the address of USDT
address[] public depositTokens;
/// @notice the address of 1inch exchange aggregator
address public oneInchRouter;
/// @notice amount of USDT for creation pool
uint256 public poolCreationFee;
/// @notice the numerator of staking fee
uint256 public stakingFeeNumerator;
/// @notice the numerator of unstaking fee
uint256 public unstakingFeeNumerator;
/// @notice the index of deposit token in `depositTokens` array
mapping(address depositToken => uint256) public depositTokenIndex;
/// @notice is token is able for depositing
mapping(address token => bool) public isDepositToken;
/// @notice is XStakingPool listed
mapping(address pool => bool) public isXStakingPool;
struct FeeConfig {
uint256 from;
uint256 to;
uint256 percentage;
uint256 fixedFee;
}
FeeConfig[] public depositFeeConfig;
FeeConfig[] public withdrawFeeConfig;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @notice Initializes the XStakingFactory with a specified XStakingPool implementation.
/// @dev Sets the initial XStakingPool implementation and creates an upgradeable beacon.
/// @param _xstakingPoolImplementation Address of the initial XStakingPool implementation.
/// @param _depositTokens address of base ERC20 token (USDT)
/// @param _oneInchRouter address of 1inch router aggregator V5
/// @param _poolCreationFee amount of USDT for pool creation
function initialize(
address _xstakingPoolImplementation,
address _treasuryWallet,
address[] memory _depositTokens,
address _oneInchRouter,
uint256 _poolCreationFee
) public initializer {
require(
_xstakingPoolImplementation != address(0) &&
_treasuryWallet != address(0) &&
_oneInchRouter != address(0),
"XStakingFactory: Given address is zero-value"
);
__Ownable_init(msg.sender);
__ReentrancyGuard_init();
beacon = new UpgradeableBeacon(
_xstakingPoolImplementation,
address(this)
);
xstakingPoolImplementation = IXStakingPool(_xstakingPoolImplementation);
treasuryWallet = _treasuryWallet;
for (uint256 i = 0; i < _depositTokens.length; ) {
isDepositToken[_depositTokens[i]] = true;
depositTokenIndex[_depositTokens[i]] = i;
unchecked {
i++;
}
}
depositTokens = _depositTokens;
oneInchRouter = _oneInchRouter;
poolCreationFee = _poolCreationFee;
}
// ------------------------------------------------------------------------
// OWNER FUNCTIONS
/// @notice set oneInchRouter address
/// @dev can be called only by owner
/// @param _oneInchRouter the address of 1inch router aggregator
function setOneInchRouter(address _oneInchRouter) public onlyOwner {
require(
_oneInchRouter != address(0),
"XStakingFacroty: oneInchRouter is 0"
);
oneInchRouter = _oneInchRouter;
}
/// @notice set treasury wallet
/// @dev can be called only by owner
function setTreasuryWallet(address _treasuryWallet) public onlyOwner {
require(
_treasuryWallet != address(0),
"XStakingFacroty: treasury wallet is 0"
);
treasuryWallet = _treasuryWallet;
}
/// @notice sets pool creation fee
/// @param _poolCreationFee the amount of baseAsset
function setPoolCreationFee(uint256 _poolCreationFee) public onlyOwner {
poolCreationFee = _poolCreationFee;
}
function setFeesInfo(
FeeConfig[] calldata fees,
bool isDeposit
) external onlyOwner {
require(fees.length != 0, "XStakingPool: fees length is 0");
for (uint256 i = 0; i < fees.length; ) {
require(
fees[i].from <= fees[i].to,
"XStakingPool: fee from should be less than to"
);
require(
fees[i].percentage <= FEE_DENOMINATOR,
"XStakingPool: percentage should be less than FEE_DENOMINATOR"
);
if (fees[i].percentage == 0)
require(
fees[i].fixedFee > 0,
"XStakingPool: fixed fee should be greater than 0"
);
if (fees[i].percentage != 0)
require(
fees[i].fixedFee == 0,
"XStakingPool: fixed fee must be 0"
);
if (i > 0) {
require(
fees[i].from > fees[i - 1].to,
"XStakingPool: range from should be greater than previous to"
);
if (fees[i].percentage == 0) {
require(
fees[i].fixedFee > 0,
"XStakingPool: fixed fee should be greater than 0"
);
}
}
unchecked {
++i;
}
}
isDeposit ? depositFeeConfig = fees : withdrawFeeConfig = fees;
}
/// @notice sweep any token to owner
/// @param token address of token
function sweep(address token) public onlyOwner {
uint256 balanceOfToken = IToken(token).balanceOf(address(this));
IToken(token).safeTransfer(owner(), balanceOfToken);
}
/// @notice Upgrades the XStakingPool implementation to a new contract.
/// @dev Can only be called by the owner. Updates the beacon with the new implementation address.
/// @param _xstakingPoolImplementation Address of the new XStakingPool implementation.
function upgradeTo(address _xstakingPoolImplementation) public onlyOwner {
xstakingPoolImplementation = IXStakingPool(_xstakingPoolImplementation);
beacon.upgradeTo(_xstakingPoolImplementation);
}
// ------------------------------------------------------------------------
// USER FUNCTIONS
/// @notice Deploys a new XStakingPool contract.
/// @dev Creates a new BeaconProxy pointing to the beacon and initializes the pool.
/// @param tokens the array of addresses of tokens
/// @param allocations the allocation for tokens
/// @return Address of the newly deployed XStakingPool.
function deployPool(
address depositToken,
uint256 capitalizationCap,
address[] memory tokens,
uint256[] memory allocations,
uint256 profitSharingFeeNumerator,
uint256 initialDepositTokenAmount,
bytes[] calldata oneInchSwapData,
string memory description
) public nonReentrant returns (address) {
require(
isDepositToken[depositToken],
"XStakingFactory: token is not deposit token"
);
uint256 tokensLength = tokens.length;
require(
tokensLength == oneInchSwapData.length,
"XStakingFactory: tokens.length != oneInchSwapData.length"
);
uint256 poolId = xstakingPools.length + 1;
// Staking fee
uint256 depositTokenAmount = getTotalDepositTokenAmountForDeployPool(
initialDepositTokenAmount
);
{
IToken(depositToken).safeTransferFrom(
msg.sender,
address(this),
depositTokenAmount
);
uint256 stakingFee = calculateFeeAmount(
initialDepositTokenAmount,
true
);
uint256 totalFee = poolCreationFee + stakingFee;
IToken(depositToken).safeTransfer(treasuryWallet, totalFee);
}
BeaconProxy newPool = new BeaconProxy(address(beacon), bytes(""));
xstakingPools.push(address(newPool));
isXStakingPool[address(newPool)] = true;
IToken(depositToken).forceApprove(
oneInchRouter,
initialDepositTokenAmount
);
uint256 totalSwappedDepositTokenAmount = 0;
uint256[] memory tokensAmounts = new uint256[](tokensLength);
address token;
for (uint256 i = 0; i < tokensLength; ) {
token = tokens[i];
uint256 balanceBefore = IToken(token).balanceOf(address(this));
uint256 depositTokenBalanceBefore = IToken(depositToken).balanceOf(
address(this)
);
(bool success, ) = oneInchRouter.call(oneInchSwapData[i]);
uint256 depositTokenBalanceAfter = IToken(depositToken).balanceOf(
address(this)
);
uint256 balanceAfter = IToken(token).balanceOf(address(this));
uint256 amountOut = balanceAfter - balanceBefore;
require(
amountOut > 0,
"XStakingFactory: 1inch swap out amount is 0"
);
require(
oneInchSwapData[i].length >= 4,
"XStakingFactory: Incorrect data length"
);
(
,
address receiver,
address srcToken,
uint256 srcTokenAmount,
uint256 minReturnAmount
) = decodeSwapData(oneInchSwapData[i]);
require(
srcTokenAmount ==
depositTokenBalanceBefore - depositTokenBalanceAfter,
"XStakingFactory: srcTokenAmount is not correct"
);
require(
receiver == address(this),
"XStakingFactory: receiver is not factory"
);
require(
depositToken == address(srcToken),
"XStakingFactory: deposit token does not match with src token in swap data"
);
require(success, "XStakingFactory: 1inch swap failed");
totalSwappedDepositTokenAmount += srcTokenAmount;
IToken(token).forceApprove(address(newPool), amountOut);
tokensAmounts[i] = amountOut;
require(
tokensAmounts[i] >= minReturnAmount,
"XStakingFactory: output amount does not match with encoded amount from swap data"
);
unchecked {
i++;
}
}
require(
totalSwappedDepositTokenAmount == initialDepositTokenAmount,
"XStakingFactory: swapped tokens amount does not match with sum of amount in every swap"
);
IXStakingPool(address(newPool)).initialize(
poolId,
msg.sender,
capitalizationCap,
tokens,
allocations,
profitSharingFeeNumerator,
tokensAmounts,
depositToken,
initialDepositTokenAmount
);
emit DeployPool(
msg.sender,
address(newPool),
poolId,
tokens,
allocations,
description,
capitalizationCap,
profitSharingFeeNumerator
);
return address(newPool);
}
/// @notice return the allocation tokens for deposit using 1inch, when creating pool
/// @dev this helper view function uses for forming swap request to 1inch API
/// @param tokens the array of tokens
/// @param allocations the array of allocations of tokens
/// @param initialDepositTokenAmount the amount of base token to deposit
/// @return the array of allocation of depositTokenAmount for swap using 1inch and sum of array elements
function calcDepositTokenAmountAllocationForDeployPool(
address[] memory tokens,
uint256[] memory allocations,
uint256 initialDepositTokenAmount
) public pure returns (uint256[] memory, uint256) {
require(
tokens.length == allocations.length,
"XStakingFactory: not equal length of tokens and allocations"
);
uint256[] memory allocatedDepositTokens = new uint256[](tokens.length);
uint256 totalSumOfAllocatedBaseToken;
uint256 totalAllocation = 0;
for (uint256 i = 0; i < allocations.length; ) {
unchecked {
totalAllocation += allocations[i];
i++;
}
}
for (uint256 i = 0; i < tokens.length; ) {
allocatedDepositTokens[i] =
(initialDepositTokenAmount * allocations[i]) /
totalAllocation;
totalSumOfAllocatedBaseToken += allocatedDepositTokens[i];
unchecked {
i++;
}
}
return (allocatedDepositTokens, totalSumOfAllocatedBaseToken);
}
function calculateFeeAmount(
uint256 amount,
bool isDeposit
) public view returns (uint256) {
FeeConfig memory feeInfo;
if (isDeposit) {
uint256 length = depositFeeConfig.length;
for (uint256 i = 0; i < length; ) {
if (
depositFeeConfig[i].from <= amount &&
depositFeeConfig[i].to >= amount
) {
feeInfo = depositFeeConfig[i];
}
unchecked {
i++;
}
}
} else {
uint256 length = withdrawFeeConfig.length;
for (uint256 i = 0; i < length; ) {
if (
withdrawFeeConfig[i].from <= amount &&
withdrawFeeConfig[i].to >= amount
) {
feeInfo = withdrawFeeConfig[i];
}
unchecked {
i++;
}
}
}
if (feeInfo.percentage == 0) return feeInfo.fixedFee;
return (amount * feeInfo.percentage) / FEE_DENOMINATOR;
}
/// @notice returns the total amount of base token for deployment of pool
function getTotalDepositTokenAmountForDeployPool(
uint256 initialDepositTokenAmount
) public view returns (uint256 depositTokenAmount) {
uint256 stakingFee = calculateFeeAmount(
initialDepositTokenAmount,
true
);
depositTokenAmount =
poolCreationFee +
initialDepositTokenAmount +
stakingFee;
}
/// @notice Returns an array of all deployed XStakingPool addresses.
/// @return An array of addresses of all XStakingPools.
function getXStakingPools() public view returns (address[] memory) {
return xstakingPools;
}
/// @notice Returns a slice of deployed XStakingPool addresses within a specified range.
/// @dev Fetches pools from the `fromId` up to (but not including) `toId`.
/// @param fromId The starting index in the list of pools.
/// @param toId The ending index in the list of pools.
/// @return xstakingPoolsSlice as array of addresses of XStakingPools in the specified range.
function getXStakingPoolsByIds(
uint256 fromId,
uint256 toId
) public view returns (address[] memory xstakingPoolsSlice) {
require(fromId <= toId, "XStakingFactory: exceeded length of pools");
require(
toId <= xstakingPools.length,
"XStakingFactory: toId exceeds length of pools"
);
if (fromId == toId) {
xstakingPoolsSlice = new address[](1);
xstakingPoolsSlice[0] = xstakingPools[fromId];
} else {
xstakingPoolsSlice = new address[](toId - fromId);
for (uint256 i = 0; i < toId - fromId; i++) {
xstakingPoolsSlice[i] = xstakingPools[i + fromId];
}
}
return xstakingPoolsSlice;
}
/// @notice Returns the total number of deployed XStakingPools.
/// @return The number of XStakingPools deployed by this factory.
function getXStakingPoolsLength() public view returns (uint256) {
return xstakingPools.length;
}
function getDepositToken(uint8 index) external view returns (address) {
return depositTokens[index];
}
function getCurrentFees()
external
view
returns (
FeeConfig[] memory depositFees_,
FeeConfig[] memory withdrawFees_
)
{
return (depositFeeConfig, withdrawFeeConfig);
}
/// @notice decode swap data for 1inch and return the parameters used in swap
/// @param data the calldata of swap
function decodeSwapData(
bytes calldata data
)
public
view
returns (
address sender,
address receiver,
address srcToken,
uint256 srcTokenAmount,
uint256 minReturnAmount
)
{
bytes4 selector;
assembly {
selector := calldataload(data.offset)
}
/// @dev `0x0502b1c5` - unoswap selector
if (selector == bytes4(0x0502b1c5)) {
(srcToken, srcTokenAmount, minReturnAmount, ) = abi.decode(
data[4:],
(address, uint256, uint256, uint256[])
);
sender = address(this);
receiver = address(this);
}
/// @dev `0x12aa3caf` - swap selector
else if (selector == bytes4(0x12aa3caf)) {
(address executor, SwapDescription memory desc, , ) = abi.decode(
data[4:], // Skip selector (4 bytes)
(address, SwapDescription, bytes, bytes)
);
sender = executor;
receiver = desc.dstReceiver;
srcToken = address(desc.srcToken);
srcTokenAmount = desc.amount;
minReturnAmount = desc.minReturnAmount;
} else if (selector == bytes4(0xe449022e)) {
uint256[] memory pools;
(srcTokenAmount, minReturnAmount, pools) = abi.decode(
data[4:], // Skip selector (4 bytes)
(uint256, uint256, uint256[])
);
address token0 = IUniswapV3Pool(address(uint160(pools[0])))
.token0();
address token1 = IUniswapV3Pool(address(uint160(pools[0])))
.token1();
if (isDepositToken[token0] && isDepositToken[token1]) {
revert("XStakingFactory: both tokens are deposit tokens");
}
if (!isDepositToken[token0]) {
srcToken = token1;
} else {
srcToken = token0;
}
sender = address(this);
receiver = address(this);
} else if (selector == bytes4(0x62e238bb)) {
(
Order memory order,
,
,
uint256 makingAmount,
uint256 takingAmount,
) = abi.decode(
data[4:], // Skip selector (4 bytes)
(Order, bytes, bytes, uint256, uint256, uint256)
);
sender = msg.sender;
receiver = order.maker;
srcToken = order.takerAsset;
srcTokenAmount = takingAmount;
minReturnAmount = makingAmount;
} else {
revert("XStakingFactory: unknown selector");
}
}
}
"
},
"contracts/interfaces/IToken.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
interface IToken is IERC20Metadata {
}"
},
"contracts/interfaces/IXStakingPool.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IXStakingPool {
struct SwapDescription {
IERC20 srcToken;
IERC20 dstToken;
address payable srcReceiver;
address payable dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
}
struct Order {
uint256 salt;
address makerAsset;
address takerAsset;
address maker;
address receiver;
address allowedSender; // equals to Zero address on public orders
uint256 makingAmount;
uint256 takingAmount;
uint256 offsets;
bytes interactions; // concat(makerAssetData, takerAssetData, getMakingAmount, getTakingAmount, predicate, permit, preIntercation, postInteraction)
}
event TokenSwap(
address token,
uint256 tokenAmount,
uint256 baseTokenAmount
);
event TokensAmounts(address[] tokens, uint256[] tokenAmounts);
event Volume(uint256 amount);
event PoolCapitalization(address pool, uint256 capitalization);
event UserCapitalization(
address pool,
address user,
uint256 capitalization
);
event Deposit(
address pool,
address depositor,
uint256 amount,
uint256[] userTokenAmounts
);
event Withdraw(
address pool,
address depositor,
uint256 amount,
uint256[] userTokenAmounts
);
event DepositStatusUpdated(bool isPaused);
function initialize(
uint256 _poolId,
address _poolOwner,
uint256 _capitalizationCap,
address[] memory _tokens,
uint256[] memory _allocations,
uint256 _profitSharingFeeNumerator,
uint256[] memory _tokensAmounts,
address initialDepositToken,
uint256 initialBaseTokenAmount
) external;
function deposit(
address depositToken,
uint256 baseTokenAmount,
bytes[] calldata oneInchSwapData
) external returns (uint256);
function depositTo(
address depositToken,
address to,
uint256 baseTokenAmount,
bytes[] calldata oneInchSwapData
) external returns (uint256);
function withdraw(
address depositToken,
uint256 amountLP,
bytes[] calldata oneInchSwapData
) external returns (uint256);
}"
},
"contracts/interfaces/IXStakingFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IXStakingFactory {
/// @notice argument for oneInch swap function.
struct SwapDescription {
IERC20 srcToken;
IERC20 dstToken;
address payable srcReceiver;
address payable dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
}
struct Order {
uint256 salt;
address makerAsset;
address takerAsset;
address maker;
address receiver;
address allowedSender; // equals to Zero address on public orders
uint256 makingAmount;
uint256 takingAmount;
uint256 offsets;
bytes interactions; // concat(makerAssetData, takerAssetData, getMakingAmount, getTakingAmount, predicate, permit, preIntercation, postInteraction)
}
function FEE_DENOMINATOR() external view returns (uint256);
function treasuryWallet() external view returns (address);
function oneInchRouter() external view returns (address);
function getDepositToken(uint8 index) external view returns (address);
function getXStakingPools() external view returns (address[] memory);
function isDepositToken(address token) external view returns (bool);
function isXStakingPool(address pool) external view returns (bool);
function decodeSwapData(bytes calldata data)
external
returns (address sender, address receiver, address srcToken, uint256 srcTokenAmount, uint256 minReturnAmount);
function calculateFeeAmount(
uint256 amount,
bool isDeposit
) external view returns (uint256);
event DeployPool(
address deployer,
address pool,
uint256 poolId,
address[] tokens,
uint256[] allocations,
string description,
uint256 capitalizationCap,
uint256 profitSharingFeeNumerator
);
}
"
},
"node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './pool/IUniswapV3PoolImmutables.sol';
import './pool/IUniswapV3PoolState.sol';
import './pool/IUniswapV3PoolDerivedState.sol';
import './pool/IUniswapV3PoolActions.sol';
import './pool/IUniswapV3PoolOwnerActions.sol';
import './pool/IUniswapV3PoolEvents.sol';
/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
IUniswapV3PoolImmutables,
IUniswapV3PoolState,
IUniswapV3PoolDerivedState,
IUniswapV3PoolActions,
IUniswapV3PoolOwnerActions,
IUniswapV3PoolEvents
{
}
"
},
"node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}
"
},
"node_modules/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "./IBeacon.sol";
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
* immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally.
*
* CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
* the beacon to not upgrade the implementation maliciously.
*
* IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
* an inconsistent state where the beacon storage slot does not match the beacon address.
*/
contract BeaconProxy is Proxy {
// An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
address private immutable _beacon;
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
* - If `data` is empty, `msg.value` must be zero.
*/
constructor(address beacon, bytes memory data) payable {
ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
_beacon = beacon;
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Returns the beacon.
*/
function _getBeacon() internal view virtual returns (address) {
return _beacon;
}
}
"
},
"node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
"
},
"node_modules/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "./IBeacon.sol";
import {Ownable} from "../../access/Ownable.sol";
/**
* @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
* implementation contract, which is where they will delegate all function calls.
*
* An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
*/
contract UpgradeableBeacon is IBeacon, Ownable {
address private _implementation;
/**
* @dev The `implementation` of the beacon is invalid.
*/
error BeaconInvalidImplementation(address implementation);
/**
* @dev Emitted when the implementation returned by the beacon is changed.
*/
event Upgraded(address indexed implementation);
/**
* @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
*/
constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
_setImplementation(implementation_);
}
/**
* @dev Returns the current implementation address.
*/
function implementation() public view virtual returns (address) {
return _implementation;
}
/**
* @dev Upgrades the beacon to a new implementation.
*
* Emits an {Upgraded} event.
*
* Requirements:
*
* - msg.sender must be the owner of the contract.
* - `newImplementation` must be a contract.
*/
function upgradeTo(address newImplementation) public virtual onlyOwner {
_setImplementation(newImplementation);
}
/**
* @dev Sets the implementation contract address for this beacon
*
* Requirements:
*
* - `newImplementation` must be a contract.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert BeaconInvalidImplementation(newImplementation);
}
_implementation = newImplementation;
emit Upgraded(newImplementation);
}
}
"
},
"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"node_modules/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
struct Ownable2StepStorage {
address _pendingOwner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;
function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
assembly {
$.slot := Ownable2StepStorageLocation
}
}
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
return $._pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
$._pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
Ownable2StepStorage storage $ = _getOwnable2StepStorage();
delete $._pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
"
},
"node_modules/@openzeppelin/contracts/interfaces/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
"
},
"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
},
"node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
/// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
/// @return The contract address
function factory() external view returns (address);
/// @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's fee in hundredths of a bip, i.e. 1e-6
/// @return The fee
function fee() external view returns (uint24);
/// @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 maximum amount of position liquidity that can use any tick in the range
/// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
/// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
/// @return The max amount of liquidity per tick
function maxLiquidityPerTick() external view returns (uint128);
}
"
},
"node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
/// @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.
/// observationIndex The index of the last oracle observation that was written,
/// observationCardinality The current maximum number of observations stored in the pool,
/// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
/// feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
/// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal0X128() external view returns (uint256);
/// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal1X128() external view returns (uint256);
/// @notice The amounts of token0 and token1 that are owed to the protocol
/// @dev Protocol fees will never exceed uint128 max in either token
function protocolFees() external view returns (uint128 token0, uint128 token1);
/// @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,
/// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
/// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
/// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
/// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
/// secondsOutside the seconds spent on the other side of the tick from the current 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,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
/// @notice Returns 256 packed tick initialized boolean values. See TickBitmap fo
Submitted on: 2025-10-21 20:55:11
Comments
Log in to comment.
No comments yet.