Source Code
Overview
S Balance
S Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 1689789 | 394 days ago | Contract Creation | 0 S |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Oracle
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 933 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.26;
import {PoolStorage, Observation, TickInfo, Slot0} from './PoolStorage.sol';
/// @title Oracle
/// @notice Provides price and liquidity data useful for a wide variety of system designs
/// @dev Instances of stored oracle data, "observations", are collected in the oracle array
/// Every pool is initialized with an oracle array length of 1. Anyone can pay the SSTOREs to increase the
/// maximum length of the oracle array. New slots will be added when the array is fully populated.
/// Observations are overwritten when the full length of the oracle array is populated.
/// The most recent observation is available, independent of the length of the oracle array, by passing 0 to observe()
library Oracle {
error I();
error OLD();
/// @notice Transforms a previous observation into a new observation, given the passage of time and the current tick and liquidity values
/// @dev blockTimestamp _must_ be chronologically equal to or greater than last.blockTimestamp, safe for 0 or 1 overflows
/// @param last The specified observation to be transformed
/// @param blockTimestamp The timestamp of the new observation
/// @param tick The active tick at the time of the new observation
/// @param liquidity The total in-range liquidity at the time of the new observation
/// @return Observation The newly populated observation
function transform(
Observation memory last,
uint32 blockTimestamp,
int24 tick,
uint128 liquidity
) private pure returns (Observation memory) {
unchecked {
uint32 delta = blockTimestamp - last.blockTimestamp;
return
Observation({
blockTimestamp: blockTimestamp,
tickCumulative: last.tickCumulative + int56(tick) * int56(uint56(delta)),
secondsPerLiquidityCumulativeX128: last.secondsPerLiquidityCumulativeX128 +
((uint160(delta) << 128) / (liquidity > 0 ? liquidity : 1)),
initialized: true
});
}
}
/// @notice Initialize the oracle array by writing the first slot. Called once for the lifecycle of the observations array
/// @param self The stored oracle array
/// @param time The time of the oracle initialization, via block.timestamp truncated to uint32
/// @return cardinality The number of populated elements in the oracle array
/// @return cardinalityNext The new length of the oracle array, independent of population
function initialize(
Observation[65535] storage self,
uint32 time
) internal returns (uint16 cardinality, uint16 cardinalityNext) {
self[0] = Observation({
blockTimestamp: time,
tickCumulative: 0,
secondsPerLiquidityCumulativeX128: 0,
initialized: true
});
return (1, 1);
}
/// @notice Writes an oracle observation to the array
/// @dev Writable at most once per block. Index represents the most recently written element. cardinality and index must be tracked externally.
/// If the index is at the end of the allowable array length (according to cardinality), and the next cardinality
/// is greater than the current one, cardinality may be increased. This restriction is created to preserve ordering.
/// @param self The stored oracle array
/// @param index The index of the observation that was most recently written to the observations array
/// @param blockTimestamp The timestamp of the new observation
/// @param tick The active tick at the time of the new observation
/// @param liquidity The total in-range liquidity at the time of the new observation
/// @param cardinality The number of populated elements in the oracle array
/// @param cardinalityNext The new length of the oracle array, independent of population
/// @return indexUpdated The new index of the most recently written element in the oracle array
/// @return cardinalityUpdated The new cardinality of the oracle array
function write(
Observation[65535] storage self,
uint16 index,
uint32 blockTimestamp,
int24 tick,
uint128 liquidity,
uint16 cardinality,
uint16 cardinalityNext
) internal returns (uint16 indexUpdated, uint16 cardinalityUpdated) {
unchecked {
Observation memory last = self[index];
/// @dev early return if we've already written an observation this block
if (last.blockTimestamp == blockTimestamp) return (index, cardinality);
/// @dev if the conditions are right, we can bump the cardinality
if (cardinalityNext > cardinality && index == (cardinality - 1)) {
cardinalityUpdated = cardinalityNext;
} else {
cardinalityUpdated = cardinality;
}
indexUpdated = (index + 1) % cardinalityUpdated;
self[indexUpdated] = transform(last, blockTimestamp, tick, liquidity);
}
}
/// @notice Prepares the oracle array to store up to `next` observations
/// @param self The stored oracle array
/// @param current The current next cardinality of the oracle array
/// @param next The proposed next cardinality which will be populated in the oracle array
/// @return next The next cardinality which will be populated in the oracle array
function grow(Observation[65535] storage self, uint16 current, uint16 next) internal returns (uint16) {
unchecked {
if (current <= 0) revert I();
/// @dev no-op if the passed next value isn't greater than the current next value
if (next <= current) return current;
/// @dev store in each slot to prevent fresh SSTOREs in swaps
/// @dev this data will not be used because the initialized boolean is still false
for (uint16 i = current; i < next; i++) self[i].blockTimestamp = 1;
return next;
}
}
/// @notice comparator for 32-bit timestamps
/// @dev safe for 0 or 1 overflows, a and b _must_ be chronologically before or equal to time
/// @param time A timestamp truncated to 32 bits
/// @param a A comparison timestamp from which to determine the relative position of `time`
/// @param b From which to determine the relative position of `time`
/// @return Whether `a` is chronologically <= `b`
function lte(uint32 time, uint32 a, uint32 b) private pure returns (bool) {
unchecked {
/// @dev if there hasn't been overflow, no need to adjust
if (a <= time && b <= time) return a <= b;
uint256 aAdjusted = a > time ? a : a + 2 ** 32;
uint256 bAdjusted = b > time ? b : b + 2 ** 32;
return aAdjusted <= bAdjusted;
}
}
/// @notice Fetches the observations beforeOrAt and atOrAfter a target, i.e. where [beforeOrAt, atOrAfter] is satisfied.
/// The result may be the same observation, or adjacent observations.
/// @dev The answer must be contained in the array, used when the target is located within the stored observation
/// boundaries: older than the most recent observation and younger, or the same age as, the oldest observation
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param target The timestamp at which the reserved observation should be for
/// @param index The index of the observation that was most recently written to the observations array
/// @param cardinality The number of populated elements in the oracle array
/// @return beforeOrAt The observation recorded before, or at, the target
/// @return atOrAfter The observation recorded at, or after, the target
function binarySearch(
Observation[65535] storage self,
uint32 time,
uint32 target,
uint16 index,
uint16 cardinality
) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) {
unchecked {
/// @dev oldest observation
uint256 l = (index + 1) % cardinality;
/// @dev newest observation
uint256 r = l + cardinality - 1;
uint256 i;
while (true) {
i = (l + r) / 2;
beforeOrAt = self[i % cardinality];
/// @dev we've landed on an uninitialized tick, keep searching higher (more recently)
if (!beforeOrAt.initialized) {
l = i + 1;
continue;
}
atOrAfter = self[(i + 1) % cardinality];
bool targetAtOrAfter = lte(time, beforeOrAt.blockTimestamp, target);
/// @dev check if we've found the answer!
if (targetAtOrAfter && lte(time, target, atOrAfter.blockTimestamp)) break;
if (!targetAtOrAfter) r = i - 1;
else l = i + 1;
}
}
}
/// @notice Fetches the observations beforeOrAt and atOrAfter a given target, i.e. where [beforeOrAt, atOrAfter] is satisfied
/// @dev Assumes there is at least 1 initialized observation.
/// Used by observeSingle() to compute the counterfactual accumulator values as of a given block timestamp.
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param target The timestamp at which the reserved observation should be for
/// @param tick The active tick at the time of the returned or simulated observation
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The total pool liquidity at the time of the call
/// @param cardinality The number of populated elements in the oracle array
/// @return beforeOrAt The observation which occurred at, or before, the given timestamp
/// @return atOrAfter The observation which occurred at, or after, the given timestamp
function getSurroundingObservations(
Observation[65535] storage self,
uint32 time,
uint32 target,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) {
unchecked {
/// @dev optimistically set before to the newest observation
beforeOrAt = self[index];
/// @dev if the target is chronologically at or after the newest observation, we can early return
if (lte(time, beforeOrAt.blockTimestamp, target)) {
if (beforeOrAt.blockTimestamp == target) {
/// @dev if newest observation equals target, we're in the same block, so we can ignore atOrAfter
return (beforeOrAt, atOrAfter);
} else {
/// @dev otherwise, we need to transform
return (beforeOrAt, transform(beforeOrAt, target, tick, liquidity));
}
}
/// @dev now, set before to the oldest observation
beforeOrAt = self[(index + 1) % cardinality];
if (!beforeOrAt.initialized) beforeOrAt = self[0];
/// @dev ensure that the target is chronologically at or after the oldest observation
if (!lte(time, beforeOrAt.blockTimestamp, target)) revert OLD();
/// @dev if we've reached this point, we have to binary search
return binarySearch(self, time, target, index, cardinality);
}
}
/// @dev Reverts if an observation at or before the desired observation timestamp does not exist.
/// 0 may be passed as `secondsAgo' to return the current cumulative values.
/// If called with a timestamp falling between two observations, returns the counterfactual accumulator values
/// at exactly the timestamp between the two observations.
/// @param self The stored oracle array
/// @param time The current block timestamp
/// @param secondsAgo The amount of time to look back, in seconds, at which point to return an observation
/// @param tick The current tick
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The current in-range pool liquidity
/// @param cardinality The number of populated elements in the oracle array
/// @return tickCumulative The tick * time elapsed since the pool was first initialized, as of `secondsAgo`
/// @return secondsPerLiquidityCumulativeX128 The time elapsed / max(1, liquidity) since the pool was first initialized, as of `secondsAgo`
function observeSingle(
Observation[65535] storage self,
uint32 time,
uint32 secondsAgo,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) internal view returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) {
unchecked {
if (secondsAgo == 0) {
Observation memory last = self[index];
if (last.blockTimestamp != time) last = transform(last, time, tick, liquidity);
return (last.tickCumulative, last.secondsPerLiquidityCumulativeX128);
}
uint32 target = time - secondsAgo;
(Observation memory beforeOrAt, Observation memory atOrAfter) = getSurroundingObservations(
self,
time,
target,
tick,
index,
liquidity,
cardinality
);
if (target == beforeOrAt.blockTimestamp) {
/// @dev we're at the left boundary
return (beforeOrAt.tickCumulative, beforeOrAt.secondsPerLiquidityCumulativeX128);
} else if (target == atOrAfter.blockTimestamp) {
/// @dev we're at the right boundary
return (atOrAfter.tickCumulative, atOrAfter.secondsPerLiquidityCumulativeX128);
} else {
/// @dev we're in the middle
uint32 observationTimeDelta = atOrAfter.blockTimestamp - beforeOrAt.blockTimestamp;
uint32 targetDelta = target - beforeOrAt.blockTimestamp;
return (
beforeOrAt.tickCumulative +
((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / int56(uint56(observationTimeDelta))) *
int56(uint56(targetDelta)),
beforeOrAt.secondsPerLiquidityCumulativeX128 +
uint160(
(uint256(
atOrAfter.secondsPerLiquidityCumulativeX128 -
beforeOrAt.secondsPerLiquidityCumulativeX128
) * targetDelta) / observationTimeDelta
)
);
}
}
}
/// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
/// @dev Reverts if `secondsAgos` > oldest observation
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an observation
/// @param tick The current tick
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The current in-range pool liquidity
/// @param cardinality The number of populated elements in the oracle array
/// @return tickCumulatives The tick * time elapsed since the pool was first initialized, as of each `secondsAgo`
/// @return secondsPerLiquidityCumulativeX128s The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo`
function observe(
Observation[65535] storage self,
uint32 time,
uint32[] memory secondsAgos,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) internal view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) {
unchecked {
if (cardinality <= 0) revert I();
tickCumulatives = new int56[](secondsAgos.length);
secondsPerLiquidityCumulativeX128s = new uint160[](secondsAgos.length);
for (uint256 i = 0; i < secondsAgos.length; i++) {
(tickCumulatives[i], secondsPerLiquidityCumulativeX128s[i]) = observeSingle(
self,
time,
secondsAgos[i],
tick,
index,
liquidity,
cardinality
);
}
}
}
function newPeriod(
Observation[65535] storage self,
uint16 index,
uint256 period
) external returns (uint160 secondsPerLiquidityCumulativeX128) {
Observation memory last = self[index];
PoolStorage.PoolState storage $ = PoolStorage.getStorage();
unchecked {
uint32 delta = uint32(period) * 1 weeks - 1 - last.blockTimestamp;
secondsPerLiquidityCumulativeX128 =
last.secondsPerLiquidityCumulativeX128 +
((uint160(delta) << 128) / ($.liquidity > 0 ? $.liquidity : 1));
self[index] = Observation({
blockTimestamp: uint32(period) * 1 weeks - 1,
tickCumulative: last.tickCumulative + int56($.slot0.tick) * int56(uint56(delta)),
secondsPerLiquidityCumulativeX128: secondsPerLiquidityCumulativeX128,
initialized: last.initialized
});
}
}
struct SnapShot {
int56 tickCumulativeLower;
int56 tickCumulativeUpper;
uint160 secondsPerLiquidityOutsideLowerX128;
uint160 secondsPerLiquidityOutsideUpperX128;
uint32 secondsOutsideLower;
uint32 secondsOutsideUpper;
}
struct SnapshotCumulativesInsideCache {
uint32 time;
int56 tickCumulative;
uint160 secondsPerLiquidityCumulativeX128;
}
/// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
/// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
/// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
/// snapshot is taken and the second snapshot is taken. Boosted data is only valid if it's within the same period
/// @param tickLower The lower tick of the range
/// @param tickUpper The upper tick of the range
/// @return tickCumulativeInside The snapshot of the tick accumulator for the range
/// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range
/// @return secondsInside The snapshot of seconds per liquidity for the range
function snapshotCumulativesInside(
int24 tickLower,
int24 tickUpper,
uint32 _blockTimestamp
) external view returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside) {
PoolStorage.PoolState storage $ = PoolStorage.getStorage();
TickInfo storage lower = $._ticks[tickLower];
TickInfo storage upper = $._ticks[tickUpper];
SnapShot memory snapshot;
bool initializedLower;
(
snapshot.tickCumulativeLower,
snapshot.secondsPerLiquidityOutsideLowerX128,
snapshot.secondsOutsideLower,
initializedLower
) = (
lower.tickCumulativeOutside,
lower.secondsPerLiquidityOutsideX128,
lower.secondsOutside,
lower.initialized
);
require(initializedLower);
bool initializedUpper;
(
snapshot.tickCumulativeUpper,
snapshot.secondsPerLiquidityOutsideUpperX128,
snapshot.secondsOutsideUpper,
initializedUpper
) = (
upper.tickCumulativeOutside,
upper.secondsPerLiquidityOutsideX128,
upper.secondsOutside,
upper.initialized
);
require(initializedUpper);
Slot0 memory _slot0 = $.slot0;
unchecked {
if (_slot0.tick < tickLower) {
return (
snapshot.tickCumulativeLower - snapshot.tickCumulativeUpper,
snapshot.secondsPerLiquidityOutsideLowerX128 - snapshot.secondsPerLiquidityOutsideUpperX128,
snapshot.secondsOutsideLower - snapshot.secondsOutsideUpper
);
} else if (_slot0.tick < tickUpper) {
SnapshotCumulativesInsideCache memory cache;
cache.time = _blockTimestamp;
(cache.tickCumulative, cache.secondsPerLiquidityCumulativeX128) = observeSingle(
$.observations,
cache.time,
0,
_slot0.tick,
_slot0.observationIndex,
$.liquidity,
_slot0.observationCardinality
);
return (
cache.tickCumulative - snapshot.tickCumulativeLower - snapshot.tickCumulativeUpper,
cache.secondsPerLiquidityCumulativeX128 -
snapshot.secondsPerLiquidityOutsideLowerX128 -
snapshot.secondsPerLiquidityOutsideUpperX128,
cache.time - snapshot.secondsOutsideLower - snapshot.secondsOutsideUpper
);
} else {
return (
snapshot.tickCumulativeUpper - snapshot.tickCumulativeLower,
snapshot.secondsPerLiquidityOutsideUpperX128 - snapshot.secondsPerLiquidityOutsideLowerX128,
snapshot.secondsOutsideUpper - snapshot.secondsOutsideLower
);
}
}
}
/// @notice Returns the seconds per liquidity and seconds inside a tick range for a period
/// @dev This does not ensure the range is a valid range
/// @param period The timestamp of the period
/// @param tickLower The lower tick of the range
/// @param tickUpper The upper tick of the range
/// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range
function periodCumulativesInside(
uint32 period,
int24 tickLower,
int24 tickUpper,
uint32 _blockTimestamp
) external view returns (uint160 secondsPerLiquidityInsideX128) {
PoolStorage.PoolState storage $ = PoolStorage.getStorage();
TickInfo storage lower = $._ticks[tickLower];
TickInfo storage upper = $._ticks[tickUpper];
SnapShot memory snapshot;
{
int24 startTick = $.periods[period].startTick;
uint256 previousPeriod = $.periods[period].previousPeriod;
snapshot.secondsPerLiquidityOutsideLowerX128 = uint160(lower.periodSecondsPerLiquidityOutsideX128[period]);
if (tickLower <= startTick && snapshot.secondsPerLiquidityOutsideLowerX128 == 0) {
snapshot.secondsPerLiquidityOutsideLowerX128 = $
.periods[previousPeriod]
.endSecondsPerLiquidityPeriodX128;
}
snapshot.secondsPerLiquidityOutsideUpperX128 = uint160(upper.periodSecondsPerLiquidityOutsideX128[period]);
if (tickUpper <= startTick && snapshot.secondsPerLiquidityOutsideUpperX128 == 0) {
snapshot.secondsPerLiquidityOutsideUpperX128 = $
.periods[previousPeriod]
.endSecondsPerLiquidityPeriodX128;
}
}
int24 lastTick;
uint256 currentPeriod = $.lastPeriod;
{
/// @dev if period is already finalized, use period's last tick, if not, use current tick
if (currentPeriod > period) {
lastTick = $.periods[period].lastTick;
} else {
lastTick = $.slot0.tick;
}
}
unchecked {
if (lastTick < tickLower) {
return snapshot.secondsPerLiquidityOutsideLowerX128 - snapshot.secondsPerLiquidityOutsideUpperX128;
} else if (lastTick < tickUpper) {
SnapshotCumulativesInsideCache memory cache;
/// @dev if period's on-going, observeSingle, if finalized, use endSecondsPerLiquidityPeriodX128
if (currentPeriod <= period) {
cache.time = _blockTimestamp;
/// @dev limit to the end of period
if (cache.time >= currentPeriod * 1 weeks + 1 weeks) {
cache.time = uint32(currentPeriod * 1 weeks + 1 weeks - 1);
}
Slot0 memory _slot0 = $.slot0;
(, cache.secondsPerLiquidityCumulativeX128) = observeSingle(
$.observations,
cache.time,
0,
_slot0.tick,
_slot0.observationIndex,
$.liquidity,
_slot0.observationCardinality
);
} else {
cache.secondsPerLiquidityCumulativeX128 = $.periods[period].endSecondsPerLiquidityPeriodX128;
}
return
cache.secondsPerLiquidityCumulativeX128 -
snapshot.secondsPerLiquidityOutsideLowerX128 -
snapshot.secondsPerLiquidityOutsideUpperX128;
} else {
return snapshot.secondsPerLiquidityOutsideUpperX128 - snapshot.secondsPerLiquidityOutsideLowerX128;
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.26;
struct Slot0 {
/// @dev the current price
uint160 sqrtPriceX96;
/// @dev the current tick
int24 tick;
/// @dev the most-recently updated index of the observations array
uint16 observationIndex;
/// @dev the current maximum number of observations that are being stored
uint16 observationCardinality;
/// @dev the next maximum number of observations to store, triggered in observations.write
uint16 observationCardinalityNext;
/// @dev the current protocol fee as a percentage of the swap fee taken on withdrawal
/// @dev represented as an integer denominator (1/x)%
uint8 feeProtocol;
/// @dev whether the pool is locked
bool unlocked;
}
struct Observation {
/// @dev the block timestamp of the observation
uint32 blockTimestamp;
/// @dev the tick accumulator, i.e. tick * time elapsed since the pool was first initialized
int56 tickCumulative;
/// @dev the seconds per liquidity, i.e. seconds elapsed / max(1, liquidity) since the pool was first initialized
uint160 secondsPerLiquidityCumulativeX128;
/// @dev whether or not the observation is initialized
bool initialized;
}
struct RewardInfo {
/// @dev used to account for changes in the deposit amount
int256 secondsDebtX96;
/// @dev used to check if starting seconds have already been written
bool initialized;
/// @dev used to account for changes in secondsPerLiquidity
int160 secondsPerLiquidityPeriodStartX128;
}
/// @dev info stored for each user's position
struct PositionInfo {
/// @dev the amount of liquidity owned by this position
uint128 liquidity;
/// @dev fee growth per unit of liquidity as of the last update to liquidity or fees owed
uint256 feeGrowthInside0LastX128;
uint256 feeGrowthInside1LastX128;
/// @dev the fees owed to the position owner in token0/token1
uint128 tokensOwed0;
uint128 tokensOwed1;
mapping(uint256 => RewardInfo) periodRewardInfo;
}
/// @dev info stored for each initialized individual tick
struct TickInfo {
/// @dev the total position liquidity that references this tick
uint128 liquidityGross;
/// @dev amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left),
int128 liquidityNet;
/// @dev fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick)
/// @dev only has relative meaning, not absolute — the value depends on when the tick is initialized
uint256 feeGrowthOutside0X128;
uint256 feeGrowthOutside1X128;
/// @dev the cumulative tick value on the other side of the tick
int56 tickCumulativeOutside;
/// @dev the seconds per unit of liquidity on the _other_ side of this tick (relative to the current tick)
/// @dev only has relative meaning, not absolute — the value depends on when the tick is initialized
uint160 secondsPerLiquidityOutsideX128;
/// @dev the seconds spent on the other side of the tick (relative to the current tick)
/// @dev only has relative meaning, not absolute — the value depends on when the tick is initialized
uint32 secondsOutside;
/// @dev true iff the tick is initialized, i.e. the value is exactly equivalent to the expression liquidityGross != 0
/// @dev these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks
bool initialized;
/// @dev secondsPerLiquidityOutsideX128 separated into periods, placed here to preserve struct slots
mapping(uint256 => uint256) periodSecondsPerLiquidityOutsideX128;
}
/// @dev info stored for each period
struct PeriodInfo {
uint32 previousPeriod;
int24 startTick;
int24 lastTick;
uint160 endSecondsPerLiquidityPeriodX128;
}
/// @dev accumulated protocol fees in token0/token1 units
struct ProtocolFees {
uint128 token0;
uint128 token1;
}
/// @dev Position period and liquidity
struct PositionCheckpoint {
uint256 period;
uint256 liquidity;
}
library PoolStorage {
/// @dev keccak256(abi.encode(uint256(keccak256("pool.storage")) - 1)) & ~bytes32(uint256(0xff));
bytes32 public constant POOL_STORAGE_LOCATION = 0xf047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb2800;
/// @custom꞉storage‑location erc7201꞉pool.storage
struct PoolState {
Slot0 slot0;
uint24 fee;
uint256 feeGrowthGlobal0X128;
uint256 feeGrowthGlobal1X128;
ProtocolFees protocolFees;
uint128 liquidity;
mapping(int24 => TickInfo) _ticks;
mapping(int16 => uint256) tickBitmap;
mapping(bytes32 => PositionInfo) positions;
Observation[65535] observations;
mapping(uint256 => PeriodInfo) periods;
uint256 lastPeriod;
mapping(bytes32 => PositionCheckpoint[]) positionCheckpoints;
bool initialized;
address nfpManager;
}
/// @dev Return state storage struct for reading and writing
function getStorage() internal pure returns (PoolState storage $) {
assembly {
$.slot := POOL_STORAGE_LOCATION
}
}
}{
"remappings": [
"@openzeppelin-contracts-5.1.0/=dependencies/@openzeppelin-contracts-5.1.0/",
"@openzeppelin-contracts-upgradeable-5.1.0/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",
"@forge-std-1.9.4/=dependencies/forge-std-1.9.4/",
"@openzeppelin-contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",
"@openzeppelin-contracts/contracts/=dependencies/@openzeppelin-contracts-5.1.0/",
"@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.1.0/",
"forge-std/=dependencies/forge-std-1.9.4/src/",
"permit2/=lib/permit2/",
"@openzeppelin-3.4.2/=node_modules/@openzeppelin-3.4.2/",
"@openzeppelin-contracts-5.1.0/=dependencies/@openzeppelin-contracts-5.1.0/",
"@openzeppelin-contracts-upgradeable-5.1.0/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",
"@uniswap/=node_modules/@uniswap/",
"base64-sol/=node_modules/base64-sol/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std-1.9.4/=dependencies/forge-std-1.9.4/src/",
"hardhat/=node_modules/hardhat/",
"solmate/=node_modules/solmate/"
],
"optimizer": {
"enabled": true,
"runs": 933
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true,
"libraries": {
"contracts/CL/core/libraries/Oracle.sol": {
"Oracle": "0x50f6A754f94a6a5eE3D887e6b1f12B55aee0C69c"
},
"contracts/CL/core/libraries/Position.sol": {
"Position": "0x4bd87e0077d12B9B18b158DbE5Ea7944135318E6"
},
"contracts/CL/core/libraries/ProtocolActions.sol": {
"ProtocolActions": "0x0c2E1dd2960879f9461C1d2f6472b72bA12BD617"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"I","type":"error"},{"inputs":[],"name":"OLD","type":"error"},{"inputs":[{"internalType":"uint32","name":"period","type":"uint32"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint32","name":"_blockTimestamp","type":"uint32"}],"name":"periodCumulativesInside","outputs":[{"internalType":"uint160","name":"secondsPerLiquidityInsideX128","type":"uint160"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint32","name":"_blockTimestamp","type":"uint32"}],"name":"snapshotCumulativesInside","outputs":[{"internalType":"int56","name":"tickCumulativeInside","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityInsideX128","type":"uint160"},{"internalType":"uint32","name":"secondsInside","type":"uint32"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60808060405234601b57610c8390816100208239308160a10152f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80639b7beb60146102ad578063c51185d81461009e5763feb0d7171461003a575f80fd5b608036600319011261009a5760043563ffffffff8116810361009a5761005e610313565b906044358060020b810361009a576064359063ffffffff8216820361009a5760209361008993610777565b6001600160a01b0360405191168152f35b5f80fd5b307f00000000000000000000000000000000000000000000000000000000000000001461009a57606036600319011261009a5760043560243561ffff8116810361009a576100f56100ef82846106e3565b50610707565b63ffffffff5f198162093a808160443516021601169263ffffffff8251168403916101fb6001600160a01b03806040840151166001600160801b037ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280554168015155f1461029a576001600160801b03610189915b1673ffffffff000000000000000000000000000000008860801b16610745565b011694602083015160060b60607ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb28005460a01c60020b9401511515936101cc610323565b98895263ffffffff60208a01971660060b0260060b0160060b85526040870193868552606088019384526106e3565b939093610287579451945191519051602092831b6affffffffffffff000000001663ffffffff969096169590951760589190911b7effffffffffffffffffffffffffffffffffffffff0000000000000000000000161793151560f81b7fff0000000000000000000000000000000000000000000000000000000000000016939093179055604051908152f35b634e487b7160e01b5f525f60045260245ffd5b506101896001600160801b036001610169565b606036600319011261009a576004358060020b810361009a576102ce610313565b6044359063ffffffff8216820361009a576102f96001600160a01b039263ffffffff92606095610461565b9193906040519460060b8552166020840152166040820152f35b602435908160020b820361009a57565b604051906080820182811067ffffffffffffffff82111761034357604052565b634e487b7160e01b5f52604160045260245ffd5b6040519060c0820182811067ffffffffffffffff821117610343576040525f60a0838281528260208201528260408201528260608201528260808201520152565b6040519060e0820182811067ffffffffffffffff821117610343576040528160c060ff7ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb2800546001600160a01b03811684528060a01c60020b602085015261ffff8160b81c16604085015261ffff8160c81c16606085015261ffff8160d81c166080850152818160e81c1660a085015260f01c161515910152565b604051906060820182811067ffffffffffffffff821117610343576040525f6040838281528260208201520152565b9290916104988460020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b936104cd8460020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b9360036104d8610357565b960154956040810195608082019763ffffffff8160d81c1689526001600160a01b038160381c1688528060060b835260f81c1561009a5760030154936020820192606083019460a084019663ffffffff8160d81c1688526001600160a01b038160381c1687528060060b865260f81c1561009a57610554610398565b906020820192835160020b9160020b82125f146105ab5750505050506001600160a01b0363ffffffff94938180879586955160060b905160060b900360060b99511691511690031696511691511690031691929190565b939a96959360020b13156106a3576105c1610432565b9963ffffffff1691828b525160020b90604081015161ffff167ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb2805546001600160801b0316916060015161ffff169261061894610b01565b6001600160a01b039093919316928360408b015260060b908160208b01525160060b900360060b905160060b900360060b95516001600160a01b031690036001600160a01b031690516001600160a01b031690036001600160a01b0316945163ffffffff16905163ffffffff16900363ffffffff16905163ffffffff16900363ffffffff1691929190565b505063ffffffff9497508492966001600160a01b0380859481945160060b905160060b900360060b99511691511690031696511691511690031691929190565b61ffff8210156106f35701905f90565b634e487b7160e01b5f52603260045260245ffd5b90610710610323565b915463ffffffff811683528060201c60060b60208401526001600160a01b038160581c16604084015260f81c15156060830152565b906001600160a01b0316908115610763576001600160a01b03160490565b634e487b7160e01b5f52601260045260245ffd5b926001600160a01b03936107b58360020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b916107ea8560020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b9263ffffffff6107f8610357565b931690815f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205260405f205460201c60020b93825f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc2808602052600463ffffffff60405f20541692845f520160205260048960405f205416966040830198888a5260020b97878913159081610af8575b50610ac0575b845f520160205260608960405f20541691019781895260020b948513159081610ab7575b50610a7f575b507ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc2809549281841194855f14610a5257825f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205260405f205460381c60020b5b60020b9081121561093c57505050505050828091511691511690031690565b1215610a3f57604087959394869586948594610956610432565b93610a04575063ffffffff1680835262093a8091820291820111156109f1575b50826109d7610983610398565b63ffffffff84511690602081015160020b61ffff87830151169061ffff60606001600160801b037ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280554169401511693610b01565b905016828201525b01511691511690031691511690031690565b62093a7f0163ffffffff1681525f610976565b9150505f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205282825f205460501c16828201526109df565b5050505090828091511691511690031690565b7ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb28005460a01c60020b61091d565b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc28086020528660405f205460501c1686525f6108bb565b9050155f6108b5565b835f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc28086020528a60405f205460501c168952610891565b9050155f61088b565b92919094935061ffff8110156106f357610b3c907ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280901610707565b9363ffffffff85511663ffffffff841603610b6e575b5050506001600160a01b036040602084015160060b9301511690565b5f949192939450610b7d610c2d565b5063ffffffff6001600160a01b0381845116860394816040602087015160060b96015116906001600160801b03811615155f14610c1a576001600160801b03610be0911673ffffffff000000000000000000000000000000008860801b16610745565b01169381610bec610323565b961686521660060b9060020b0260060b0160060b6020830152604082015260016060820152905f8080610b52565b50610be06001600160801b036001610169565b610c35610323565b905f82525f60208301525f60408301525f606083015256fea2646970667358221220ca2969138c2b58d089a63e751bd2f520d8fa3225669c7d654bc97cc9840fed4664736f6c634300081c0033
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c80639b7beb60146102ad578063c51185d81461009e5763feb0d7171461003a575f80fd5b608036600319011261009a5760043563ffffffff8116810361009a5761005e610313565b906044358060020b810361009a576064359063ffffffff8216820361009a5760209361008993610777565b6001600160a01b0360405191168152f35b5f80fd5b307f00000000000000000000000050f6a754f94a6a5ee3d887e6b1f12b55aee0c69c1461009a57606036600319011261009a5760043560243561ffff8116810361009a576100f56100ef82846106e3565b50610707565b63ffffffff5f198162093a808160443516021601169263ffffffff8251168403916101fb6001600160a01b03806040840151166001600160801b037ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280554168015155f1461029a576001600160801b03610189915b1673ffffffff000000000000000000000000000000008860801b16610745565b011694602083015160060b60607ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb28005460a01c60020b9401511515936101cc610323565b98895263ffffffff60208a01971660060b0260060b0160060b85526040870193868552606088019384526106e3565b939093610287579451945191519051602092831b6affffffffffffff000000001663ffffffff969096169590951760589190911b7effffffffffffffffffffffffffffffffffffffff0000000000000000000000161793151560f81b7fff0000000000000000000000000000000000000000000000000000000000000016939093179055604051908152f35b634e487b7160e01b5f525f60045260245ffd5b506101896001600160801b036001610169565b606036600319011261009a576004358060020b810361009a576102ce610313565b6044359063ffffffff8216820361009a576102f96001600160a01b039263ffffffff92606095610461565b9193906040519460060b8552166020840152166040820152f35b602435908160020b820361009a57565b604051906080820182811067ffffffffffffffff82111761034357604052565b634e487b7160e01b5f52604160045260245ffd5b6040519060c0820182811067ffffffffffffffff821117610343576040525f60a0838281528260208201528260408201528260608201528260808201520152565b6040519060e0820182811067ffffffffffffffff821117610343576040528160c060ff7ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb2800546001600160a01b03811684528060a01c60020b602085015261ffff8160b81c16604085015261ffff8160c81c16606085015261ffff8160d81c166080850152818160e81c1660a085015260f01c161515910152565b604051906060820182811067ffffffffffffffff821117610343576040525f6040838281528260208201520152565b9290916104988460020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b936104cd8460020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b9360036104d8610357565b960154956040810195608082019763ffffffff8160d81c1689526001600160a01b038160381c1688528060060b835260f81c1561009a5760030154936020820192606083019460a084019663ffffffff8160d81c1688526001600160a01b038160381c1687528060060b865260f81c1561009a57610554610398565b906020820192835160020b9160020b82125f146105ab5750505050506001600160a01b0363ffffffff94938180879586955160060b905160060b900360060b99511691511690031696511691511690031691929190565b939a96959360020b13156106a3576105c1610432565b9963ffffffff1691828b525160020b90604081015161ffff167ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb2805546001600160801b0316916060015161ffff169261061894610b01565b6001600160a01b039093919316928360408b015260060b908160208b01525160060b900360060b905160060b900360060b95516001600160a01b031690036001600160a01b031690516001600160a01b031690036001600160a01b0316945163ffffffff16905163ffffffff16900363ffffffff16905163ffffffff16900363ffffffff1691929190565b505063ffffffff9497508492966001600160a01b0380859481945160060b905160060b900360060b99511691511690031696511691511690031691929190565b61ffff8210156106f35701905f90565b634e487b7160e01b5f52603260045260245ffd5b90610710610323565b915463ffffffff811683528060201c60060b60208401526001600160a01b038160581c16604084015260f81c15156060830152565b906001600160a01b0316908115610763576001600160a01b03160490565b634e487b7160e01b5f52601260045260245ffd5b926001600160a01b03936107b58360020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b916107ea8560020b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280660205260405f2090565b9263ffffffff6107f8610357565b931690815f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205260405f205460201c60020b93825f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc2808602052600463ffffffff60405f20541692845f520160205260048960405f205416966040830198888a5260020b97878913159081610af8575b50610ac0575b845f520160205260608960405f20541691019781895260020b948513159081610ab7575b50610a7f575b507ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc2809549281841194855f14610a5257825f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205260405f205460381c60020b5b60020b9081121561093c57505050505050828091511691511690031690565b1215610a3f57604087959394869586948594610956610432565b93610a04575063ffffffff1680835262093a8091820291820111156109f1575b50826109d7610983610398565b63ffffffff84511690602081015160020b61ffff87830151169061ffff60606001600160801b037ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280554169401511693610b01565b905016828201525b01511691511690031691511690031690565b62093a7f0163ffffffff1681525f610976565b9150505f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc280860205282825f205460501c16828201526109df565b5050505090828091511691511690031690565b7ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb28005460a01c60020b61091d565b5f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc28086020528660405f205460501c1686525f6108bb565b9050155f6108b5565b835f527ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccc28086020528a60405f205460501c168952610891565b9050155f61088b565b92919094935061ffff8110156106f357610b3c907ff047b0c59244a0faf8e48cb6b6fde518e6717176152b6dd953628cd9dccb280901610707565b9363ffffffff85511663ffffffff841603610b6e575b5050506001600160a01b036040602084015160060b9301511690565b5f949192939450610b7d610c2d565b5063ffffffff6001600160a01b0381845116860394816040602087015160060b96015116906001600160801b03811615155f14610c1a576001600160801b03610be0911673ffffffff000000000000000000000000000000008860801b16610745565b01169381610bec610323565b961686521660060b9060020b0260060b0160060b6020830152604082015260016060820152905f8080610b52565b50610be06001600160801b036001610169565b610c35610323565b905f82525f60208301525f60408301525f606083015256fea2646970667358221220ca2969138c2b58d089a63e751bd2f520d8fa3225669c7d654bc97cc9840fed4664736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.