Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 251 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit | 12532604 | 384 days ago | IN | 0 ETH | 0.00006182 | ||||
| Deposit | 12507437 | 385 days ago | IN | 0 ETH | 0.0000633 | ||||
| Deposit | 12482770 | 386 days ago | IN | 0 ETH | 0.00006274 | ||||
| Deposit | 12458863 | 387 days ago | IN | 0 ETH | 0.00002037 | ||||
| Rebalance | 12458861 | 387 days ago | IN | 0 ETH | 0.00002928 | ||||
| Deposit | 12435420 | 388 days ago | IN | 0 ETH | 0.00006242 | ||||
| Deposit | 12411216 | 389 days ago | IN | 0 ETH | 0.00006306 | ||||
| Deposit | 12387953 | 390 days ago | IN | 0 ETH | 0.00007255 | ||||
| Deposit | 12340220 | 392 days ago | IN | 0 ETH | 0.00006117 | ||||
| Deposit | 12314117 | 393 days ago | IN | 0 ETH | 0.00006107 | ||||
| Deposit | 12289062 | 394 days ago | IN | 0 ETH | 0.00006074 | ||||
| Deposit | 12263466 | 395 days ago | IN | 0 ETH | 0.00006122 | ||||
| Deposit | 12183988 | 398 days ago | IN | 0 ETH | 0.00006048 | ||||
| Deposit | 12157732 | 399 days ago | IN | 0 ETH | 0.0000629 | ||||
| Rebalance | 12104793 | 401 days ago | IN | 0 ETH | 0.00002811 | ||||
| Deposit | 12104786 | 401 days ago | IN | 0 ETH | 0.00005968 | ||||
| Deposit | 12078892 | 402 days ago | IN | 0 ETH | 0.0000596 | ||||
| Deposit | 12052322 | 403 days ago | IN | 0 ETH | 0.00006084 | ||||
| Deposit | 12025191 | 404 days ago | IN | 0 ETH | 0.00006413 | ||||
| Deposit | 11998458 | 405 days ago | IN | 0 ETH | 0.00006351 | ||||
| Deposit | 11973035 | 406 days ago | IN | 0 ETH | 0.00006363 | ||||
| Deposit | 11945356 | 407 days ago | IN | 0 ETH | 0.00006554 | ||||
| Deposit | 11918845 | 408 days ago | IN | 0 ETH | 0.0000205 | ||||
| Rebalance | 11918843 | 408 days ago | IN | 0 ETH | 0.0000299 | ||||
| Deposit | 11893071 | 409 days ago | IN | 0 ETH | 0.0000638 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 12532604 | 384 days ago | 0.00000096 ETH | ||||
| 12532604 | 384 days ago | 0.00000943 ETH | ||||
| 12532604 | 384 days ago | 0.00000024 ETH | ||||
| 12507437 | 385 days ago | 0.00000143 ETH | ||||
| 12507437 | 385 days ago | 0.00001417 ETH | ||||
| 12507437 | 385 days ago | 0.0000002 ETH | ||||
| 12482770 | 386 days ago | 0.00000156 ETH | ||||
| 12482770 | 386 days ago | 0.00001554 ETH | ||||
| 12482770 | 386 days ago | 0.00000007 ETH | ||||
| 12458861 | 387 days ago | 0 ETH | ||||
| 12458861 | 387 days ago | 0 ETH | ||||
| 12458861 | 387 days ago | 0 ETH | ||||
| 12458861 | 387 days ago | 0.00023418 ETH | ||||
| 12458861 | 387 days ago | 0.00007284 ETH | ||||
| 12458861 | 387 days ago | 0 ETH | ||||
| 12458861 | 387 days ago | 0.00000005 ETH | ||||
| 12435420 | 388 days ago | 0.00000071 ETH | ||||
| 12435420 | 388 days ago | 0.00000705 ETH | ||||
| 12435420 | 388 days ago | 0.00000007 ETH | ||||
| 12411216 | 389 days ago | 0.00000208 ETH | ||||
| 12411216 | 389 days ago | 0.00002075 ETH | ||||
| 12411216 | 389 days ago | 0.00000009 ETH | ||||
| 12387953 | 390 days ago | 0.00000151 ETH | ||||
| 12387953 | 390 days ago | 0.00001507 ETH | ||||
| 12387953 | 390 days ago | 0.00000011 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SymetricAmbientStrategy
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23;
import { CrocsSwapDex } from "./interfaces/CrocsSwapDex.sol";
import { TickMath } from "src/libraries/TickMath.sol";
import { CrocsQuery, CurveState } from "./interfaces/CrocsQuery.sol";
import { PoolSpecs } from "./libraries/PoolSpecs.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeCast } from "./libraries/SafeCast.sol";
import { LiquidityAmounts } from "./libraries/LiquidityAmounts.sol";
import { LiquidityAmountsNative } from "./libraries/LiquidityAmountsNative.sol";
import { IOracle } from "src/interfaces/IOracle.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { FixedPoint } from "./libraries/FixedPoint.sol";
import { VaultLibrary, TickParameters } from "src/libraries/VaultLibrary.sol";
import "src/utils/Constants.sol";
import "src/utils/Variables.sol";
import "src/utils/Errors.sol";
contract SymetricAmbientStrategy is ReentrancyGuard, ERC20, AccessControl {
using SafeERC20 for IERC20Metadata;
using TickMath for int24;
using SafeCast for uint256;
using Math for *;
bool isDepositing;
uint8 private immutable assetIdx;
uint8 private immutable _decimals;
uint8 public padding = 4;
uint16 public fee;
uint16 public investedPercentage;
uint16 public swapSlippage;
int24 public baseWidth;
int24 public limitWidth;
address public oracle;
LpParam[] private lpParams;
bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE");
bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN");
address public feeRecipient;
CrocsSwapDex public immutable crocsSwapDex;
CrocsQuery public immutable crocsQuery;
address[2] public tokenAddresses;
event Withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares);
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event FeesSet(uint16 fee);
event FeeRecipientSet(address feeRecipient);
event InvestedPercentageSet(uint16 investedPercentage);
event SwapSlippageSet(uint16 swapSlippage);
event OracleSet(address oracle);
event PaddingSet(uint8 padding);
event BaseAndLimitUpdated(int24 baseWidth, int24 limitWidth);
modifier depositing() {
isDepositing = true;
_;
isDepositing = false;
}
struct SwapParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
}
constructor(
int24 _baseWidth,
int24 _limitWidth,
SymetricStrategyParameters memory sParams
) ERC20(sParams.name, sParams.symbol) {
if (
sParams.governor == address(0) ||
sParams.feeRecipient == address(0) ||
sParams.oracle == address(0) ||
sParams.token0 > sParams.token1 ||
sParams.fee > BASE ||
sParams.investedPercentage > BASE ||
sParams.swapSlippage > BASE
) {
revert BadSetup();
}
crocsQuery = CrocsQuery(sParams.cQuery);
crocsSwapDex = CrocsSwapDex(sParams.cSwapDex);
CrocsQuery.Pool memory poolParams = crocsQuery.queryPoolParams(sParams.token0, sParams.token1, 420);
int24 tickSize = int24(int16(poolParams.tickSize_));
uint8 token0Decimals = sParams.token0 == address(0) ? 18 : IERC20Metadata(sParams.token0).decimals();
uint8 token1Decimals = IERC20Metadata(sParams.token1).decimals();
uint8 oracleDecimals = IOracle(sParams.oracle).decimals();
uint256 oraclePrice = (uint256(IOracle(sParams.oracle).latestAnswer()) * 10 ** token0Decimals) /
10 ** oracleDecimals;
tokenAddresses[0] = sParams.token0;
tokenAddresses[1] = sParams.token1;
TickParameters memory params = TickParameters({
oraclePrice: oraclePrice,
baseWidth: _baseWidth,
limitWidth: _limitWidth,
tickSize: tickSize,
token1Decimals: token1Decimals,
currentTick: currentTick(),
isLimitRight: true
});
(int24[] memory _upperTicks, int24[] memory _lowerTicks) = VaultLibrary.setTicks(params);
VaultLibrary.checkLiqParams(_upperTicks, _lowerTicks, tickSize);
assetIdx = sParams.assetIdx;
_decimals = tokenAddresses[sParams.assetIdx] == address(0)
? 18
: IERC20Metadata(tokenAddresses[sParams.assetIdx]).decimals();
_initLpParams(_upperTicks, _lowerTicks);
if (sParams.token0 != address(0)) {
IERC20Metadata(sParams.token0).safeIncreaseAllowance(address(crocsSwapDex), type(uint256).max);
}
IERC20Metadata(sParams.token1).safeIncreaseAllowance(address(crocsSwapDex), type(uint256).max);
feeRecipient = sParams.feeRecipient;
fee = sParams.fee;
investedPercentage = sParams.investedPercentage;
swapSlippage = sParams.swapSlippage;
baseWidth = _baseWidth;
limitWidth = _limitWidth;
oracle = sParams.oracle;
_setRoleAdmin(GOVERNANCE_ROLE, GOVERNANCE_ROLE);
_setRoleAdmin(GUARDIAN_ROLE, GOVERNANCE_ROLE);
_grantRole(GOVERNANCE_ROLE, sParams.governor);
}
/// @notice Allows a user to deposit a specified amount of tokens into the contract
/// @param amount The amount of tokens to deposit
/// @param receiver The address that will receive the shares of the deposit
/// @return shares The amount of shares minted for the deposited amount
/// @dev This function collects fees, performs token swaps, checks the received amount,
/// calculates liquidity, and provides liquidity before minting shares to the receiver
/// @dev This function is non-reentrant and ensures proper depositing state
function deposit(uint256 amount, address receiver) external payable depositing nonReentrant returns (uint256 shares) {
// Local cache for gas saving
// Gas optimization
(LpParam[] memory _lpParams, uint8 _assetIdx, address[2] memory _tokenAddresses) = (
lpParams,
assetIdx,
tokenAddresses
);
// Collect fees from the specified tick range
_collectAllFees(_lpParams, _tokenAddresses, feeRecipient, fee);
// Preview the number of shares to be minted for the deposit amount
shares = previewDeposit(amount);
// Transfer tokens from the user to the contract
_transferTokenFromUser(_tokenAddresses[_assetIdx], amount);
// Calculate the buffer amount to be invested
uint256 investedAmount = amount.mulDiv(investedPercentage, BASE);
// Swap tokens and get the amounts received and spent
(uint256 received, uint256 spent) = _swapTokensForLP(
_lpParams[0].upperTick,
_lpParams[0].lowerTick,
_assetIdx,
oracle,
investedAmount
);
// When tokens are collected by the dex contract, the debit amount is padded by 3 wei compared to the credit amount.
// (E.g. mint versus burn operation). This is to make sure any rounding effects don't undercollateralize the pool.
uint256 amountToken1 = _assetIdx == 0 ? received : investedAmount - spent;
amountToken1 = amountToken1 > padding ? amountToken1 - padding : 0;
uint256 amountToken0 = _assetIdx == 0 ? investedAmount - spent : received;
amountToken0 = amountToken0 > padding ? amountToken0 - padding : 0;
uint128 liq = LiquidityAmountsNative.getLiquidityForAmounts(
crocsQuery.queryCurve(_tokenAddresses[0], _tokenAddresses[1], 420).priceRoot_,
TickMath.getSqrtRatioAtTick(_lpParams[0].lowerTick),
TickMath.getSqrtRatioAtTick(_lpParams[0].upperTick),
amountToken1,
amountToken0
);
if (liq != 0) {
// Provide liquidity based on the calculated liquidity and current ticks
_provideLiquidity(
_lpParams[0].upperTick,
_lpParams[0].lowerTick,
liq,
_tokenAddresses[0] == address(0) ? (_assetIdx == 0 ? investedAmount - spent : received) : 0
);
}
// Mint shares to the receiver
_mint(receiver, shares);
// Emit a deposit event
emit Deposit(msg.sender, receiver, amount, shares);
}
/// @notice Allows a user to withdraw a specified amount of assets from the contract
/// @param assets The amount of assets to withdraw
/// @param receiver The address that will receive the withdrawn assets
/// @param owner The address that owns the shares being withdrawn
/// @param minimumReceive The minimum amount of assets to be received by the receiver
/// @return shares The amount of shares burned for the withdrawal
/// @dev This function collects fees, previews the withdrawal, calculates assets, and performs the withdrawal
/// @dev This function is non-reentrant and ensures proper withdrawal state
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 minimumReceive
) external nonReentrant returns (uint256 shares) {
// Local cache for gas saving
(LpParam[] memory _lpParams, address[2] memory _tokenAddresses) = (lpParams, tokenAddresses);
// Collect fees from the specified tick range
_collectAllFees(_lpParams, _tokenAddresses, feeRecipient, fee);
// Preview the number of shares to be burned for the withdrawal amount
shares = previewWithdraw(assets);
// Calculate the assets and withdraw liquidity based on the shares
assets = _withdrawLiquidity(_lpParams, shares, _tokenAddresses);
// Revert if the assets received are less than the minimum specified
if (assets < minimumReceive) revert NotEnoughToken();
// Perform the withdrawal
_withdraw(msg.sender, receiver, owner, assets, shares, _tokenAddresses[assetIdx]);
}
/// @notice Allows a user to redeem shares for a specified amount of assets
/// @param shares The amount of shares to redeem
/// @param receiver The address that will receive the redeemed assets
/// @param owner The address that owns the shares being redeemed
/// @param minimumReceive The minimum amount of assets to be received by the receiver
/// @return assets The amount of assets received for the redeemed shares
/// @dev This function collects fees, calculates assets, and performs the redemption
/// @dev This function is non-reentrant and ensures proper redemption state
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 minimumReceive
) external nonReentrant returns (uint256 assets) {
// Local cache for gas saving
(LpParam[] memory _lpParams, address[2] memory _tokenAddresses) = (lpParams, tokenAddresses);
// Collect fees from the specified tick range
_collectAllFees(_lpParams, _tokenAddresses, feeRecipient, fee);
// Calculate the assets and withdraw liquidity based on the shares
assets = _withdrawLiquidity(_lpParams, shares, _tokenAddresses);
// Revert if the assets received are less than the minimum specified
if (assets < minimumReceive) revert NotEnoughToken();
// Perform the withdrawal
_withdraw(msg.sender, receiver, owner, assets, shares, _tokenAddresses[assetIdx]);
}
function rebalance() external nonReentrant onlyRole(GUARDIAN_ROLE) {
_rebalance(baseWidth, limitWidth);
}
function updateBaseAndLimit(int24 _baseWidth, int24 _limitWidth) external nonReentrant onlyRole(GUARDIAN_ROLE) {
// Validate the input arrays have the same length
if (_baseWidth == 0) revert BadSetup();
if (_limitWidth == 0) revert BadSetup();
baseWidth = _baseWidth;
limitWidth = _limitWidth;
emit BaseAndLimitUpdated(_baseWidth, _limitWidth);
_rebalance(_baseWidth, _limitWidth);
}
function _rebalance(int24 _baseWidth, int24 _limitWidth) internal {
// Query pool parameters for tick size
CrocsQuery.Pool memory poolParams = crocsQuery.queryPoolParams(tokenAddresses[0], tokenAddresses[1], 420);
int24 tickSize = int24(int16(poolParams.tickSize_));
// Create local copies of the LP parameters and token addresses
(LpParam[] memory _lpParams, address[2] memory _tokenAddresses) = (lpParams, tokenAddresses);
// Collect fees from the specified tick ranges
_collectAllFees(_lpParams, _tokenAddresses, feeRecipient, fee);
// Burn all existing liquidities
_burnAllLiquidities(0, _lpParams, _tokenAddresses, true);
(int24[] memory newUpperTicks, int24[] memory newLowerTicks) = processTokenData(
tokenAddresses,
oracle,
_baseWidth,
_limitWidth,
tickSize
);
// Validate the new tick range
VaultLibrary.checkLiqParams(newUpperTicks, newLowerTicks, tickSize);
// Update the tick ranges to the new values
_initLpParams(newUpperTicks, newLowerTicks);
// Provide new liquidities based on the updated tick ranges
_provideAllLiquidities();
}
/// @notice Invests the remaining dust amounts by providing liquidity
/// @dev This function calls _provideAllLiquidities to invest any remaining small amounts of tokens.
function investDust() external nonReentrant onlyRole(GUARDIAN_ROLE) {
_provideAllLiquidities();
}
function execute(
address to,
uint256 value,
bytes calldata data
) external payable nonReentrant onlyRole(GOVERNANCE_ROLE) returns (bool, bytes memory) {
(bool success, bytes memory result) = to.call{ value: value }(data);
return (success, result);
}
/// @notice Gets the current position in the pool for the specified tick ranges
/// @param _upperTick The upper tick range
/// @param _lowerTick The lower tick range
/// @return The current liquidity, amount of token0, and amount of token1
/// @dev This function queries the current position for the specified tick ranges and token addresses.
function getPosition(int24 _upperTick, int24 _lowerTick) external view returns (uint128, uint128, uint128) {
return _getPosition(_upperTick, _lowerTick, tokenAddresses);
}
/// @notice Initializes the LP parameters with the specified tick ranges
/// @param _upperTicks The upper tick ranges
/// @param _lowerTicks The lower tick ranges
/// @dev This function deletes the existing LP parameters and initializes them with the new tick ranges.
function _initLpParams(int24[] memory _upperTicks, int24[] memory _lowerTicks) internal {
// Delete the existing LP parameters
delete lpParams;
// Get the length of the new tick ranges
uint256 lenTicks = _upperTicks.length;
// Initialize the LP parameters with the new tick ranges
for (uint i; i < lenTicks; ) {
lpParams.push(LpParam(_upperTicks[i], _lowerTicks[i]));
unchecked {
++i;
}
}
}
function processTokenData(
address[2] memory _tokenAddresses,
address _oracle,
int24 _baseWidth,
int24 _limitWidth,
int24 tickSize
) internal view returns (int24[] memory _newUpperTicks, int24[] memory _newLowerTicks) {
uint8 token0Decimals = _tokenAddresses[0] == address(0) ? 18 : IERC20Metadata(_tokenAddresses[0]).decimals();
uint8 token1Decimals = IERC20Metadata(_tokenAddresses[1]).decimals();
uint256 oraclePrice = (uint256(IOracle(_oracle).latestAnswer()) * 10 ** token0Decimals) /
10 ** IOracle(_oracle).decimals(); // In decimal of token0
uint256[2] memory balances = _getBalances();
uint256 balToken1In0 = (balances[1] * oraclePrice) / 10 ** token1Decimals;
TickParameters memory params = TickParameters({
oraclePrice: oraclePrice,
baseWidth: _baseWidth,
limitWidth: _limitWidth,
tickSize: tickSize,
token1Decimals: token1Decimals,
currentTick: currentTick(),
isLimitRight: balances[0] < balToken1In0
});
(_newUpperTicks, _newLowerTicks) = VaultLibrary.setTicks(params);
}
/// @notice Collects all fees from the specified LP parameters and transfers them to the fee recipient
/// @param _lpParams The LP parameters
/// @param _tokenAddresses The addresses of the tokens
/// @param _feeRecipient The address of the fee recipient
/// @param _fee The fee percentage
/// @return owed0 The total amount of token0 owed
/// @return owed1 The total amount of token1 owed
/// @return feeAmount0 The fee amount in token0
/// @return feeAmount1 The fee amount in token1
/// @dev This function iterates over all LP parameters, collects fees, calculates the fee amounts, and transfers them to the fee recipient
function _collectAllFees(
LpParam[] memory _lpParams,
address[2] memory _tokenAddresses,
address _feeRecipient,
uint16 _fee
) internal returns (int128 owed0, int128 owed1, uint256 feeAmount0, uint256 feeAmount1) {
// Get the length of the LP parameters array
uint256 lpLength = lpParams.length;
// Iterate over all LP parameters
for (uint i; i < lpLength; ) {
(, int128 curOwed0, int128 curOwed1) = _collectFees(
_lpParams[i].upperTick,
_lpParams[i].lowerTick,
_tokenAddresses
);
// Sum up the owed amounts for token0 and token1
owed0 += curOwed0;
owed1 += curOwed1;
unchecked {
++i;
}
}
// Calculate and transfer the fee for token0 if owed
if (owed0 < 0) {
feeAmount0 = uint256(uint128(-owed0)).mulDiv(_fee, BASE);
if (_tokenAddresses[0] == address(0)) {
// Transfer the fee amount in ETH
payable(_feeRecipient).transfer(feeAmount0);
} else {
// Transfer the fee amount in token0
IERC20Metadata(_tokenAddresses[0]).safeTransfer(_feeRecipient, feeAmount0);
}
}
// Calculate and transfer the fee for token1 if owed
if (owed1 < 0) {
feeAmount1 = uint256(uint128(-owed1)).mulDiv(_fee, BASE);
// Transfer the fee amount in token1
IERC20Metadata(_tokenAddresses[1]).safeTransfer(_feeRecipient, feeAmount1);
}
}
/// @notice Collects fees from the specified tick ranges
/// @param _upperTick The upper tick range
/// @param _lowerTick The lower tick range
/// @param _tokenAddresses The addresses of the tokens
/// @return liq The current liquidity
/// @return owed0 The amount of token0 owed
/// @return owed1 The amount of token1 owed
/// @dev This function constructs commands for collecting fees and sends them to the crocsSwapDex contract
function _collectFees(
int24 _upperTick,
int24 _lowerTick,
address[2] memory _tokenAddresses
) internal returns (uint128 liq, int128 owed0, int128 owed1) {
// Get the current position for the specified tick ranges and token addresses
(liq, , ) = _getPosition(_upperTick, _lowerTick, _tokenAddresses);
if (liq <= 0) return (0, 0, 0);
// Encode the command for collecting fees
bytes memory cmd = abi.encode(
2, // Command type for collecting fees
_tokenAddresses[0],
_tokenAddresses[1],
420,
_lowerTick,
_upperTick,
0,
0,
type(uint128).max,
0,
address(0)
);
// Send the command to the crocsSwapDex contract
crocsSwapDex.userCmd(128, cmd);
// Encode the command for querying fees
cmd = abi.encode(
5, // Command type for querying fees
_tokenAddresses[0],
_tokenAddresses[1],
uint256(420),
_lowerTick,
_upperTick,
0,
0,
type(uint128).max,
0,
address(0)
);
// Send the command to the crocsSwapDex contract and decode the response
bytes memory outUserCmd = crocsSwapDex.userCmd(128, cmd);
(owed0, owed1) = abi.decode(outUserCmd, (int128, int128));
}
/// @notice Calculates the amount of tokens to swap based on the current tick and provided parameters
/// @param _assetIdx The index of the asset to swap (0 for token0, 1 for token1)
/// @param _curTick The current tick of the pool
/// @param _upperTick The upper tick range
/// @param _lowerTick The lower tick range
/// @param _amount The amount of the asset to swap
/// @param _tokenAddress The addresses of the tokens involved in the swap
/// @return The amount of tokens to swap
/// @dev This function calculates the swap amount considering the current tick position relative to the tick ranges
function _calcAmountToSwap(
uint8 _assetIdx,
int24 _curTick,
int24 _upperTick,
int24 _lowerTick,
uint256 _amount,
address[2] memory _tokenAddress
) internal view returns (uint256) {
// If the current tick is above the upper tick, return the entire amount for token1 if assetIdx is 1
if (_curTick > _upperTick) {
return _assetIdx * _amount;
}
// If the current tick is below the lower tick, return the entire amount for token0 if assetIdx is 0
if (_curTick < _lowerTick) {
return (1 - _assetIdx) * _amount;
}
// Get the decimals for token0 and token1
uint8 token0Decimals = _tokenAddress[0] == address(0) ? 18 : IERC20Metadata(_tokenAddress[0]).decimals();
uint8 token1Decimals = IERC20Metadata(_tokenAddress[1]).decimals();
uint128 sqrtPrice = crocsQuery.queryCurve(tokenAddresses[0], tokenAddresses[1], 420).priceRoot_;
// Calculate the amount of token1 in terms of token0
uint256 token1InToken0 = ((uint256(sqrtPrice) * uint256(sqrtPrice)) * 10 ** token1Decimals) >> 128;
// Calculate liquidity for token0 and token1 at the given tick ranges
uint128 liq0 = LiquidityAmountsNative.getLiquidityForAmount1(
TickMath.getSqrtRatioAtTick(_lowerTick),
sqrtPrice,
10 ** token0Decimals
);
uint128 liq1 = LiquidityAmountsNative.getLiquidityForAmount0(
sqrtPrice,
TickMath.getSqrtRatioAtTick(_upperTick),
10 ** token1Decimals
);
uint256 amountTokenToSwap;
// Calculate the amount to swap based on asset index
if (_assetIdx == 0) {
// Calculate the ratio of liquidity
uint256 ratioBase18 = liq0.mulDiv(1e18, liq1);
// Calculate the amount of token1 to swap
uint256 amountToken1 = (ratioBase18).mulDiv(
_amount * 1e18,
10 ** (token0Decimals + 18) + ratioBase18 * token1InToken0
);
// Calculate the final amount to swap
amountTokenToSwap = (_amount * 1e18 - amountToken1 * token1InToken0) / 1e18;
} else {
// Convert amount to new units
uint256 newAmount = _amount.mulDiv(token1InToken0, 10 ** token0Decimals);
// Calculate the ratio of liquidity
uint256 ratioBase18 = liq1.mulDiv(1e18, liq0);
// Calculate the amount of token0 to swap
uint256 amountToken0 = ratioBase18.mulDiv(
newAmount * 10 ** (18 + token0Decimals),
token1InToken0 * 10 ** (token1Decimals + 18) + ratioBase18 * 10 ** (token1Decimals + token0Decimals)
);
// Calculate the final amount to swap
amountTokenToSwap = (newAmount * 1e18 - amountToken0 * 10 ** token1Decimals).mulDiv(
10 ** token0Decimals,
token1InToken0 * 1e18
);
}
// Return the calculated amount to swap
return amountTokenToSwap;
}
/// @notice Swaps tokens for liquidity provision and calculates the received and spent amounts
/// @param _lowerTick The lower tick range
/// @param _upperTick The upper tick range
/// @param _assetIdx The index of the asset to swap (0 for token0, 1 for token1)
/// @param _oracle oracle
/// @return received The amount of tokens received from the swap
/// @return spent The amount of tokens spent for the swap
function _swapTokensForLP(
int24 _upperTick,
int24 _lowerTick,
uint8 _assetIdx,
address _oracle,
uint256 investedAmount
) internal returns (uint256 received, uint256 spent) {
// Swap tokens and get the amounts received and spent
(received, spent) = _swapTokens(
SwapParams(
tokenAddresses[_assetIdx],
tokenAddresses[1 - _assetIdx],
_calcAmountToSwap(_assetIdx, currentTick(), _upperTick, _lowerTick, investedAmount, tokenAddresses)
)
);
// Check the received amount after swapping
_checkReceivedAmount(investedAmount, investedAmount - spent, received, _assetIdx == 0, _oracle);
}
/// @notice Provides liquidity for the specified tick ranges
/// @param _upperTick The upper tick range
/// @param _lowerTick The lower tick range
/// @param liq The liquidity to provide
/// @param ethVal The value of ETH to send with the transaction
/// @dev This function constructs a command for adding liquidity and sends it to the crocsSwapDex contract
function _provideLiquidity(int24 _upperTick, int24 _lowerTick, uint128 liq, uint256 ethVal) internal {
// Encode the command for adding liquidity with relevant parameters
bytes memory cmd = abi.encode(
1, // 1 = AddLiquidity
tokenAddresses[0],
tokenAddresses[1],
uint256(420),
_lowerTick,
_upperTick,
(((liq * investedPercentage) / BASE) >> 11) << 11,
uint128(0),
type(uint128).max,
uint8(0),
address(0)
);
uint256 valueMsgSender;
// Adjust ethVal if the first token is ETH
if (tokenAddresses[0] == address(0)) {
valueMsgSender = ethVal;
}
// Send the command to the crocsSwapDex contract
crocsSwapDex.userCmd{ value: valueMsgSender }(128, cmd);
}
/// @notice Swaps tokens based on the provided parameters
/// @param params The parameters for the token swap
/// @return received The amount of tokens received from the swap
/// @return spent The amount of tokens spent for the swap
/// @dev This function performs a token swap and calculates the received and spent amounts
function _swapTokens(SwapParams memory params) internal returns (uint256 received, uint256 spent) {
// Return if the input amount is zero
if (params.amountIn == 0) return (0, 0);
// Determine the base and quote tokens and whether to sell the base token
(address _baseToken, address _quoteToken, bool sellBase) = params.tokenIn < params.tokenOut
? (params.tokenIn, params.tokenOut, true)
: (params.tokenOut, params.tokenIn, false);
// Get the current token balances
uint256[2] memory beforeBalList = _getBalances();
uint256 beforeBal;
uint256 beforeBalIn;
// Determine the balances before the swap
if (params.tokenIn == tokenAddresses[0]) {
(beforeBalIn, beforeBal) = (beforeBalList[0], beforeBalList[1]);
} else {
(beforeBal, beforeBalIn) = (beforeBalList[0], beforeBalList[1]);
}
// Perform the token swap
_swap(sellBase, _baseToken, _quoteToken, params.amountIn);
// Calculate the amount of tokens received from the swap
received = params.tokenOut == address(0)
? address(this).balance - beforeBal
: IERC20Metadata(params.tokenOut).balanceOf(address(this)) - beforeBal;
// Calculate the amount of tokens spent for the swap
spent = params.tokenIn == address(0)
? address(this).balance
: IERC20Metadata(params.tokenIn).balanceOf(address(this));
spent = beforeBalIn - spent;
}
/// @notice Performs a token swap
/// @param sellBase Indicates whether to sell the base token
/// @param _baseToken The address of the base token
/// @param _quoteToken The address of the quote token
/// @param amountIn The amount of the base token to swap
/// @dev This function constructs a command for the swap and sends it to the crocsSwapDex contract
function _swap(bool sellBase, address _baseToken, address _quoteToken, uint256 amountIn) internal {
// Encode the command for the swap
bytes memory cmd = abi.encode(
_baseToken,
_quoteToken,
420,
sellBase,
sellBase,
amountIn.toUint128(),
0,
sellBase ? uint128(21_267_430_153_580_247_136_652_501_917_186_561_137) : uint128(65_538),
0,
0
);
uint256 valueMsgSender;
// Set the value to send with the transaction if selling the base token and it's ETH
if (sellBase && _baseToken == address(0)) {
valueMsgSender = amountIn;
}
// Send the command to the crocsSwapDex contract
crocsSwapDex.userCmd{ value: valueMsgSender }(1, cmd);
}
/// @notice Gets the current position in the pool
/// @param _lowerTick The lower tick range
/// @param _upperTick The upper tick range
/// @return liquidity The current liquidity
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
/// @dev This function queries the current range tokens from the crocsQuery contract
function _getPosition(
int24 _upperTick,
int24 _lowerTick,
address[2] memory _tokenAddresses
) internal view returns (uint128 liquidity, uint128 amount0, uint128 amount1) {
(liquidity, amount0, amount1) = crocsQuery.queryRangeTokens(
address(this),
_tokenAddresses[0],
_tokenAddresses[1],
420,
_lowerTick,
_upperTick
);
}
/**
* @dev Provides all calculated liquidities based on the current balances and tick ranges.
*
* This function performs the following steps:
* 1. Retrieves the current token balances.
* 2. Calculates the new liquidity amount based on the current tick and given tick ranges.
* 3. Provides new liquidity using the updated tick ranges and calculated liquidity.
* 4. Repeats the process for a different set of tick ranges.
*/
function _provideAllLiquidities() internal {
// Get the current token balances
CurveState memory curveState = crocsQuery.queryCurve(tokenAddresses[0], tokenAddresses[1], 420);
LpParam[] memory _lpParams = lpParams;
uint256 lpParamsLength = lpParams.length;
for (uint256 i; i < lpParamsLength; ) {
(uint128 liq, uint256 _ethVal) = _computeLiquidityFromTicks(
curveState.priceRoot_,
_lpParams[i].upperTick,
_lpParams[i].lowerTick,
_getBalances(),
tokenAddresses
);
if (liq != 0) {
_provideLiquidity(_lpParams[i].upperTick, _lpParams[i].lowerTick, liq, _ethVal);
}
unchecked {
++i;
}
}
}
/// @notice Computes the liquidity from the given tick ranges and balances
/// @param sqrtPrice The square root of the current price
/// @param newUpperTick The new upper tick range
/// @param newLowerTick The new lower tick range
/// @param balances The current token balances
/// @param _tokenAddresses The addresses of the tokens
/// @return liq The computed liquidity
/// @return ethVal The value of ETH if the first token address is the zero address
/// @dev This function calculates the new liquidity amount based on the given tick ranges and balances,
/// and determines the ETH value if the first token is ETH.
function _computeLiquidityFromTicks(
uint128 sqrtPrice,
int24 newUpperTick,
int24 newLowerTick,
uint256[2] memory balances,
address[2] memory _tokenAddresses
) internal view returns (uint128 liq, uint256 ethVal) {
// Calculate the new liquidity amount using the given tick ranges and balances.
// If the balance is greater than 4, subtract 4 to avoid rounding issues.
liq = LiquidityAmountsNative.getLiquidityForAmounts(
sqrtPrice,
TickMath.getSqrtRatioAtTick(newLowerTick),
TickMath.getSqrtRatioAtTick(newUpperTick),
balances[1] > padding ? balances[1] - padding : 0,
balances[0] > padding ? balances[0] - padding : 0
);
// Determine the value of ETH if the first token address is the zero address (indicating ETH).
if (_tokenAddresses[0] == address(0)) {
ethVal = balances[0];
}
}
/// @notice Calculates the liquidity for a given number of shares in a specified tick range
/// @param _lowerTick The lower tick range
/// @param _upperTick The upper tick range
/// @param shares The number of shares
/// @return The calculated liquidity
/// @dev This function calculates the liquidity based on the provided shares and tick ranges
function _liquidityForShares(
int24 _upperTick,
int24 _lowerTick,
uint256 shares,
address[2] memory _tokenAddresses
) internal view returns (uint128) {
(uint128 position, , ) = _getPosition(_upperTick, _lowerTick, _tokenAddresses);
return _uint128Safe(uint256(position).mulDiv(shares, totalSupply()));
}
/// @notice Safely converts a uint256 to a uint128
/// @param x The uint256 value to convert
/// @return The converted uint128 value
/// @dev This function asserts that the input value can be safely converted to uint128
function _uint128Safe(uint256 x) internal pure returns (uint128) {
assert(x <= type(uint128).max);
return uint128(x);
}
/// @notice Burns all liquidities for the given shares and LP parameters
/// @param _shares The number of shares to burn
/// @param _lpParams The LP parameters
/// @param _tokenAddresses The addresses of the tokens
/// @param isRebalance Indicates if the burn is part of a rebalance operation
/// @dev This function iterates over all LP parameters and burns the corresponding liquidity
function _burnAllLiquidities(
uint256 _shares,
LpParam[] memory _lpParams,
address[2] memory _tokenAddresses,
bool isRebalance
) internal {
// Get the length of the LP parameters array
uint256 lpParamsLength = _lpParams.length;
// Iterate over all LP parameters
for (uint i; i < lpParamsLength; ) {
uint128 liqShares;
// Determine the liquidity to burn based on whether this is a rebalance operation
if (isRebalance) {
// Get the current position for the specified tick ranges
(liqShares, , ) = _getPosition(_lpParams[i].upperTick, _lpParams[i].lowerTick, _tokenAddresses);
} else {
// Calculate the liquidity for the given shares and tick ranges
liqShares = _liquidityForShares(_lpParams[i].upperTick, _lpParams[i].lowerTick, _shares, _tokenAddresses);
}
// Burn the liquidity for the specified tick ranges
_burnLiquidity(_lpParams[i].upperTick, _lpParams[i].lowerTick, liqShares, _tokenAddresses);
unchecked {
++i;
}
}
}
/// @notice Burns liquidity for the given tick ranges and liquidity amount
/// @param _upperTick The upper tick range
/// @param _lowerTick The lower tick range
/// @param liquidity The liquidity amount to burn
/// @param _tokenAddresses The addresses of the tokens
/// @dev This function constructs a command for burning liquidity and sends it to the crocsSwapDex contract
function _burnLiquidity(
int24 _upperTick,
int24 _lowerTick,
uint128 liquidity,
address[2] memory _tokenAddresses
) internal {
if (liquidity <= 0) return;
// Encode the command for burning liquidity
bytes memory cmd = abi.encode(
2,
_tokenAddresses[0],
_tokenAddresses[1],
420,
_lowerTick,
_upperTick,
(liquidity >> 11) << 11,
0,
type(uint128).max,
0,
address(0)
);
// Send the command to the crocsSwapDex contract
crocsSwapDex.userCmd(128, cmd);
}
/// @notice Withdraws liquidity for the given shares and LP parameters
/// @param _lpParams The LP parameters
/// @param _shares The number of shares to withdraw
/// @param _tokenAddresses The addresses of the tokens
/// @return totalAmountToSend The total amount of tokens to send
/// @dev This function burns the corresponding liquidity, swaps tokens if necessary, and returns the total amount to send
function _withdrawLiquidity(
LpParam[] memory _lpParams,
uint256 _shares,
address[2] memory _tokenAddresses
) internal returns (uint256 totalAmountToSend) {
// Get the current token balances
uint256[2] memory balBefore = _getBalances();
(uint256 bal0Before, uint256 bal1Before) = (balBefore[0], balBefore[1]);
// Calculate the token balances for the given shares
uint256 token0FromBal = bal0Before.mulDiv(_shares, totalSupply());
uint256 token1FromBal = bal1Before.mulDiv(_shares, totalSupply());
// Burn all liquidities for the given shares
_burnAllLiquidities(_shares, _lpParams, _tokenAddresses, false);
// Get the new token balances
uint256[2] memory balAfter = _getBalances();
(uint256 bal0After, uint256 bal1After) = (balAfter[0], balAfter[1]);
// Calculate the balances to swap
uint256 balance0ToSwap = bal0After - bal0Before + token0FromBal;
uint256 balance1ToSwap = bal1After - bal1Before + token1FromBal;
// Perform token swaps and calculate the total amount to send
if (assetIdx == 0) {
(uint256 receivedAmount, ) = _swapTokens(SwapParams(tokenAddresses[1], tokenAddresses[0], balance1ToSwap));
totalAmountToSend = receivedAmount + balance0ToSwap;
} else {
(uint256 receivedAmount, ) = _swapTokens(SwapParams(tokenAddresses[0], tokenAddresses[1], balance0ToSwap));
totalAmountToSend = receivedAmount + balance1ToSwap;
}
}
/// @notice Withdraws assets and burns shares
/// @param caller The address of the caller
/// @param receiver The address of the receiver
/// @param owner The address of the owner
/// @param assets The amount of assets to withdraw
/// @param shares The number of shares to burn
/// @param _asset The address of the asset
/// @dev This function burns the specified shares and transfers the corresponding assets to the receiver
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares,
address _asset
) internal {
if (caller != owner) {
_spendAllowance(owner, caller, shares);
}
_burn(owner, shares);
_transferTokenToUser(receiver, _asset, assets);
emit Withdraw(caller, receiver, owner, assets, shares);
}
/// @notice Transfers tokens from the user to the contract
/// @param token The address of the token
/// @param amount The amount of the token to transfer
/// @dev This function transfers the specified amount of tokens from the user to the contract
function _transferTokenFromUser(address token, uint256 amount) internal {
if (token == address(0)) {
if (msg.value != amount) revert WrongMessageValue();
} else {
IERC20Metadata(token).safeTransferFrom(msg.sender, address(this), amount);
}
}
/// @notice Transfers tokens from the contract to the user
/// @param token The address of the token
/// @param amount The amount of the token to transfer
/// @dev This function transfers the specified amount of tokens from the contract to the user
function _transferTokenToUser(address receiver, address token, uint256 amount) internal {
if (token == address(0)) {
payable(receiver).transfer(amount);
} else {
IERC20Metadata(token).safeTransfer(receiver, amount);
}
}
/// @notice Gets all positions in the pool for the specified LP parameters
/// @param _lpParams The LP parameters
/// @param _tokenAddresses The addresses of the tokens
/// @return liquidity The total liquidity
/// @return amount0 The total amount of token0
/// @return amount1 The total amount of token1
/// @dev This function iterates over all LP parameters and sums up the liquidity, token0 amount, and token1 amount
function getAllPositions(
LpParam[] memory _lpParams,
address[2] memory _tokenAddresses
) private view returns (uint128 liquidity, uint128 amount0, uint128 amount1) {
// Get the length of the LP parameters array
uint256 lpParamsLength = _lpParams.length;
// Iterate over all LP parameters
for (uint i; i < lpParamsLength; ) {
uint128 curAmount0;
uint128 curAmount1;
uint128 curLiquidity;
// Get the position for the current tick ranges and token addresses
(curLiquidity, curAmount0, curAmount1) = _getPosition(
_lpParams[i].upperTick,
_lpParams[i].lowerTick,
_tokenAddresses
);
// Sum up the liquidity, token0 amount, and token1 amount
liquidity += curLiquidity;
amount0 += curAmount0;
amount1 += curAmount1;
unchecked {
++i;
}
}
}
function getLpParams() external view returns (LpParam[] memory) {
return lpParams;
}
function getPositions()
external
view
returns (uint256 amount0Invested, uint256 amount1Invested, uint256 amount0Idle, uint256 amount1Idle)
{
(, amount0Invested, amount1Invested) = getAllPositions(lpParams, tokenAddresses);
uint256[2] memory idleAsset = _getBalances();
amount0Idle = idleAsset[0];
amount1Idle = idleAsset[1];
}
function getTokenAddresses() external view returns (address[2] memory) {
return tokenAddresses;
}
/// @notice Previews the number of shares for a given amount of assets
/// @param assets The amount of assets
/// @return The number of shares
/// @dev This function calculates the number of shares for the specified amount of assets
function previewDeposit(uint256 assets) public view returns (uint256) {
return _convertToShares(assets);
}
/// @notice Previews the number of shares for a given amount of assets to withdraw
/// @param assets The amount of assets
/// @return The number of shares
/// @dev This function calculates the number of shares for the specified amount of assets to withdraw
function previewWithdraw(uint256 assets) public view returns (uint256) {
return _convertToShares(assets);
}
/// @notice Converts a given amount to shares
/// @param amount The amount to convert
/// @return The number of shares corresponding to the amount
function convertToShares(uint256 amount) external view returns (uint256) {
return _convertToShares(amount);
}
/// @notice Converts a given number of shares to assets
/// @param shares The number of shares
/// @return The amount of assets corresponding to the shares
function convertToAssets(uint256 shares) external view returns (uint256) {
return _convertToAssets(shares);
}
/// @notice Returns the decimals used for the token
/// @return The number of decimals
function decimals() public view override returns (uint8) {
return _decimals;
}
/// @notice Returns the total assets held by the contract
/// @return The total assets
function totalAssets() public view returns (uint256) {
return _underlyingBalance(assetIdx == 0);
}
/// @notice Returns the current tick of the pool
/// @return The current tick
function currentTick() public view returns (int24) {
address _token0 = tokenAddresses[0];
address _token1 = tokenAddresses[1];
if (_token0 > _token1) {
(_token0, _token1) = (_token1, _token0);
}
bytes32 key = PoolSpecs.encodeKey(_token0, _token1, 420);
bytes32 slot = keccak256(abi.encode(key, CURVE_MAP_SLOT));
uint256 valOne = crocsSwapDex.readSlot(uint256(slot));
uint128 curvePrice = uint128((valOne << 128) >> 128);
return TickMath.getTickAtSqrtRatio(curvePrice);
}
receive() external payable {}
/// @notice Returns the current balances of token0 and token1
/// @return The balances of token0 and token1
function _getBalances() internal view returns (uint256[2] memory) {
return [
tokenAddresses[0] == address(0)
? address(this).balance
: IERC20Metadata(tokenAddresses[0]).balanceOf(address(this)),
IERC20Metadata(tokenAddresses[1]).balanceOf(address(this))
];
}
/// @notice Converts an amount to shares
/// @param amount The amount to convert
/// @return The number of shares
function _convertToShares(uint256 amount) internal view returns (uint256) {
uint256 supply = totalSupply();
if (supply == 0) return amount;
uint256 _totalAsset = totalAssets();
if (tokenAddresses[assetIdx] == address(0) && isDepositing) return amount.mulDiv(supply, _totalAsset - amount);
return amount.mulDiv(supply, _totalAsset);
}
/// @notice Converts shares to an amount
/// @param shares The number of shares to convert
/// @return The amount corresponding to the shares
function _convertToAssets(uint256 shares) internal view returns (uint256) {
uint256 supply = totalSupply();
if (supply == 0) return shares;
return shares.mulDiv(totalAssets(), supply);
}
/// @notice Returns the underlying balance of token0 or token1
/// @param _isToken0 Whether to return the balance of token0
/// @return The underlying balance
function _underlyingBalance(bool _isToken0) internal view returns (uint256) {
uint8 token1Decimals = IERC20Metadata(tokenAddresses[1]).decimals();
uint8 token0Decimals = tokenAddresses[0] == address(0) ? 18 : IERC20Metadata(tokenAddresses[0]).decimals();
uint256[2] memory tokenBal = _getBalances();
(uint256 token0Bal, uint256 token1Bal) = (tokenBal[0], tokenBal[1]);
uint256 token1InToken0 = (uint256(IOracle(oracle).latestAnswer()) * 10 ** token0Decimals) /
(10 ** IOracle(oracle).decimals());
(, uint128 amount0, uint128 amount1) = getAllPositions(lpParams, tokenAddresses);
uint256 curValBal = _isToken0 ? token1Bal : token0Bal;
uint256 amount = _isToken0
? token1InToken0.mulDiv((uint256(amount1) + curValBal), 10 ** token1Decimals)
: (uint256(amount0) + curValBal).mulDiv(10 ** token1Decimals, token1InToken0);
uint256 curUnderlyingBal = _isToken0 ? token0Bal : token1Bal;
return _isToken0 ? uint256(amount0) + amount + curUnderlyingBal : uint256(amount1) + amount + curUnderlyingBal;
}
/// @notice Checks if the received amount is acceptable
/// @param initialAmount The initial amount
/// @param currentUnderlyingAmount The current underlying amount
/// @param receivedAmount The received amount
/// @param _isToken0 Whether the token is token0
/// @param _oracle oracle
/// @dev This function reverts if the received amount is less than the acceptable amount
function _checkReceivedAmount(
uint256 initialAmount,
uint256 currentUnderlyingAmount,
uint256 receivedAmount,
bool _isToken0,
address _oracle
) internal view {
uint8 decimalToken1 = IERC20Metadata(tokenAddresses[1]).decimals();
uint8 token0Decimals = tokenAddresses[0] == address(0) ? 18 : IERC20Metadata(tokenAddresses[0]).decimals();
uint256 amountInOtherToken;
uint256 oraclePrice = (uint256(IOracle(_oracle).latestAnswer()) * 10 ** token0Decimals) /
(10 ** IERC20Metadata(_oracle).decimals());
if (_isToken0) {
// received is token1
amountInOtherToken = (receivedAmount * oraclePrice) / 10 ** decimalToken1;
} else {
amountInOtherToken = receivedAmount.mulDiv(10 ** decimalToken1, oraclePrice);
}
uint256 acceptableAmount = initialAmount.mulDiv(swapSlippage, BASE);
if (currentUnderlyingAmount + amountInOtherToken < acceptableAmount) revert NotEnoughReceived();
}
///////////////
/// Setters ///
///////////////
/// @notice Sets the fee
/// @param _fee The new fee
/// @dev This function sets the fee and emits a FeesSet event
function setFees(uint16 _fee) external onlyRole(GOVERNANCE_ROLE) {
if (_fee > BASE) {
revert BadSetup();
}
fee = _fee;
emit FeesSet(_fee);
}
/// @notice Sets the fee recipient
/// @param _feeRecipient The new fee recipient
/// @dev This function sets the fee recipient and emits a FeeRecipientSet event
function setFeeRecipient(address _feeRecipient) external onlyRole(GOVERNANCE_ROLE) {
if (_feeRecipient == address(0)) {
revert BadSetup();
}
feeRecipient = _feeRecipient;
emit FeeRecipientSet(_feeRecipient);
}
/// @notice Sets the invested percentage
/// @param _investedPercentage The new invested percentage
/// @dev This function sets the invested percentage and emits an InvestedPercentageSet event
function setInvestedPercentage(uint16 _investedPercentage) external onlyRole(GOVERNANCE_ROLE) {
if (_investedPercentage > BASE) {
revert BadSetup();
}
investedPercentage = _investedPercentage;
emit InvestedPercentageSet(_investedPercentage);
}
/// @notice Sets the swap slippage
/// @param _swapSlippage The new swap slippage
/// @dev This function sets the swap slippage and emits a SwapSlippageSet event
function setSwapSlippage(uint16 _swapSlippage) external onlyRole(GOVERNANCE_ROLE) {
if (_swapSlippage > BASE) {
revert BadSetup();
}
swapSlippage = _swapSlippage;
emit SwapSlippageSet(_swapSlippage);
}
function setOracle(address _oracle) external onlyRole(GOVERNANCE_ROLE) {
if (_oracle == address(0)) {
revert BadSetup();
}
oracle = _oracle;
emit OracleSet(_oracle);
}
/**
* @notice Sets the padding value.
* @param _padding The new padding value to be set.
* @dev This function can only be called by an account with the GOVERNANCE_ROLE.
* @dev Emits a PaddingSet event with the new padding value.
*/
function setPadding(uint8 _padding) external onlyRole(GOVERNANCE_ROLE) {
padding = _padding;
emit PaddingSet(_padding);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23;
interface CrocsSwapDex {
function userCmd(uint16 callpath, bytes calldata cmd) external payable returns (bytes memory);
function readSlot(uint256 slot) external view returns (uint256 data);
function swap(
address base,
address quote,
uint256 poolIdx,
bool isBuy,
bool inBaseQty,
uint128 qty,
uint16 tip,
uint128 limitPrice,
uint128 minOut,
uint8 settleFlags
) external payable returns (int128 baseFlow, int128 quoteFlow);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.23;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.64 numbers. Supports
/// prices between 2**-96 and 2**120
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-96
int24 internal constant MIN_TICK = -665_454;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**120
int24 internal constant MAX_TICK = 831_818;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to
/// getSqrtRatioAtTick(MIN_TICK). The reason we don't set this as min(uint128) is so that single precicion moves
/// represent a small fraction.
uint128 internal constant MIN_SQRT_RATIO = 65_538;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint128 internal constant MAX_SQRT_RATIO = 21_267_430_153_580_247_136_652_501_917_186_561_138;
/// @notice Calculates sqrt(1.0001^tick) * 2^64
/// @dev Throws if tick < MIN_TICK or tick > MAX_TICK
/// @param tick The input tick for the above formula
/// @return sqrtPriceX64 A Fixed point Q64.64 number representing the sqrt of the ratio of the two assets
/// (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint128 sqrtPriceX64) {
// Set to unchecked, but the original UniV3 library was written in a pre-checked version of Solidity
unchecked {
require(tick >= MIN_TICK && tick <= MAX_TICK);
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<64 rounding up to go from a Q128.128 to a Q64.64
// we then downcast because we know the result always fits within 128 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX64 = uint128((ratio >> 64) + (ratio % (1 << 64) == 0 ? 0 : 1));
}
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX64 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX64 The sqrt ratio for which to compute the tick as a Q64.64
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint128 sqrtPriceX64) internal pure returns (int24 tick) {
// Set to unchecked, but the original UniV3 library was written in a pre-checked version of Solidity
unchecked {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX64 >= MIN_SQRT_RATIO && sqrtPriceX64 < MAX_SQRT_RATIO);
uint256 ratio = uint256(sqrtPriceX64) << 64;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255_738_958_999_603_826_347_141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3_402_992_956_809_132_418_596_140_100_660_247_210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291_339_464_771_989_622_907_027_621_153_398_088_495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX64 ? tickHi : tickLow;
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23;
struct CurveState {
uint128 priceRoot_;
uint128 ambientSeeds_;
uint128 concLiq_;
uint64 seedDeflator_;
uint64 concGrowth_;
}
interface CrocsQuery {
struct Pool {
uint8 schema_;
uint16 feeRate_;
uint8 protocolTake_;
uint16 tickSize_;
uint8 jitThresh_;
uint8 knockoutBits_;
uint8 oracleFlags_;
}
function queryCurveTick(address base, address quote, uint256 poolIdx) external view returns (int24);
function queryKnockoutTokens(
address owner,
address base,
address quote,
uint256 poolIdx,
uint32 pivot,
bool isBid,
int24 lowerTick,
int24 upperTick
) external view returns (uint128 liq, uint128 baseQty, uint128 quoteQty, bool knockedOut);
function queryKnockoutPivot(
address base,
address quote,
uint256 poolIdx,
bool isBid,
int24 tick
) external view returns (uint96 lots, uint32 pivot, uint16 range);
function queryRangeTokens(
address owner,
address base,
address quote,
uint256 poolIdx,
int24 lowerTick,
int24 upperTick
) external view returns (uint128, uint128, uint128);
function queryPoolParams(address base, address quote, uint256 poolIdx) external view returns (Pool memory pool);
function queryCurve(address base, address quote, uint256 poolIdx) external view returns (CurveState memory curve);
}// SPDX-License-Identifier: GPL-3
pragma solidity >=0.8.23;
pragma experimental ABIEncoderV2;
/* @title Pool specification library.
* @notice Library for defining, querying, and encoding the specifications of the
* parameters of a pool type. */
library PoolSpecs {
/* @notice Specifcations of the parameters of a single pool type. Any given pair
* may have many different pool types, each of which may operate as segmented
* markets with different underlying behavior to the AMM.
*
* @param schema_ Placeholder that defines the structure of the poolSpecs object in
* in storage. Because slots initialize zero, 0 is used for an
* unitialized or disabled pool. 1 is the only currently used schema
* (for the below struct), but allows for upgradeability in the future
*
* @param feeRate_ The overall fee (liquidity fees + protocol fees inclusive) that
* swappers pay to the pool as a fraction of notional. Represented as an
* integer representing hundredths of a basis point. I.e. a 0.25% fee
* would be 2500
*
* @param protocolTake_ The fraction of the fee rate that goes to the protocol fee
* (the rest accumulates as a liquidity fee to LPs). Represented in units
* of 1/256. Since uint8 can represent up to 255, protocol could take
* as much as 99.6% of liquidity fees. However currently the protocol
* set function prohibits values above 128, i.e. 50% of liquidity fees.
* (See set ProtocolTakeRate in PoolRegistry.sol)
*
* @param tickSize The minimum granularity of price ticks defining a grid, on which
* range orders may be placed. (Outside off-grid price improvement facility.)
* For example a value of 50 would mean that range order bounds could only
* be placed on every 50th price tick, guaranteeing a minimum separation of
* 0.005% (50 one basis point ticks) between bump points.
*
* @param jitThresh_ Sets the minimum TTL for concentrated LP positions in the pool.
* Represented in units of 10 seconds (as measured by block time)
* E.g. a value of 5 equates to a minimum TTL of 50 seconds.
* Attempts to burn or partially burn an LP position in less than
* N seconds (as measured in block.timestamp) after a position was
* minted (or had its liquidity increased) will revert. If set to
* 0, atomically flashed liquidity that mints->burns in the same
* block is enabled.
*
* @param knockoutBits_ Defines the parameters for where and how knockout liquidity
* is allowed in the pool. (See KnockoutLiq library for a full
* description of the bit field.)
*
* @param oracleFlags_ Bitmap flags to indicate the pool's oracle permission
* requirements. Current implementation only uses the least
* significant bit, which if on checks oracle permission on every
* pool related call. Otherwise pool is permissionless. */
struct Pool {
uint8 schema_;
uint16 feeRate_;
uint8 protocolTake_;
uint16 tickSize_;
uint8 jitThresh_;
uint8 knockoutBits_;
uint8 oracleFlags_;
}
uint8 constant BASE_SCHEMA = 1;
uint8 constant DISABLED_SCHEMA = 0;
/* @notice Convenience struct that's used to gather all useful context about on a
* specific pool.
* @param head_ The full specification for the pool. (See struct Pool comments above.)
* @param hash_ The keccak256 hash used to encode the full pool location.
* @param oracle_ The permission oracle associated with this pool (0 if pool is
* permissionless.) */
struct PoolCursor {
Pool head_;
bytes32 hash_;
address oracle_;
}
/* @notice Given a mapping of pools, a base/quote token pair and a pool type index,
* copies the pool specification to memory. */
function queryPool(
mapping(bytes32 => Pool) storage pools,
address tokenX,
address tokenY,
uint256 poolIdx
) internal view returns (PoolCursor memory specs) {
bytes32 key = encodeKey(tokenX, tokenY, poolIdx);
Pool memory pool = pools[key];
address oracle = oracleForPool(poolIdx, pool.oracleFlags_);
return PoolCursor({ head_: pool, hash_: key, oracle_: oracle });
}
/* @notice Given a mapping of pools, a base/quote token pair and a pool type index,
* retrieves a storage reference to the pool specification. */
function selectPool(
mapping(bytes32 => Pool) storage pools,
address tokenX,
address tokenY,
uint256 poolIdx
) internal view returns (Pool storage specs) {
bytes32 key = encodeKey(tokenX, tokenY, poolIdx);
return pools[key];
}
/* @notice Writes a pool specification for a pair and pool type combination. */
function writePool(
mapping(bytes32 => Pool) storage pools,
address tokenX,
address tokenY,
uint256 poolIdx,
Pool memory val
) internal {
bytes32 key = encodeKey(tokenX, tokenY, poolIdx);
pools[key] = val;
}
/* @notice Hashes the key associated with a pool for a base/quote asset pair and
* a specific pool type index. */
function encodeKey(address tokenX, address tokenY, uint256 poolIdx) internal pure returns (bytes32) {
require(tokenX < tokenY);
return keccak256(abi.encode(tokenX, tokenY, poolIdx));
}
/* @notice Returns the permission oracle associated with the pool (or 0 if pool is
* permissionless.
*
* @dev The oracle (if enabled on pool settings) is always deterministically based
* on the first 160-bits of the pool type value. This means users can know
* ahead of time if a pool can be oracled by checking the bits in the pool
* index. */
function oracleForPool(uint256 poolIdx, uint8 oracleFlags) internal pure returns (address) {
uint8 ORACLE_ENABLED_MASK = 0x1;
bool oracleEnabled = (oracleFlags & ORACLE_ENABLED_MASK == 1);
return oracleEnabled ? address(uint160(poolIdx >> 96)) : address(0);
}
/* @notice Constructs a cryptographically unique virtual address based off a base
* address (either virtual or real), and a salt unique to the base address.
* Can be used to create synthetic tokens, users, etc.
*
* @param base The address of the base root.
* @param salt A salt unique to the base token tracker contract.
*
* @return A synthetic token address corresponding to the specific virtual address. */
function virtualizeAddress(address base, uint256 salt) internal pure returns (address) {
bytes32 hash = keccak256(abi.encode(base, salt));
uint160 hashTrail = uint160((uint256(hash) << 96) >> 96);
return address(hashTrail);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// 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 {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 ERC-20 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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
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).
*/
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;
}
}// SPDX-License-Identifier: GPL-3
pragma solidity >=0.8.23;
/// @title Safe casting methods
/// @notice Contains methods for safely casting between types
library SafeCast {
/// @notice Cast a uint256 to a uint160, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type uint160
function toUint160(uint256 y) internal pure returns (uint160 z) {
unchecked {
// Explicit bounds check
require((z = uint160(y)) == y);
}
}
/// @notice Cast a uint256 to a uint128, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type uint128
function toUint128(uint256 y) internal pure returns (uint128 z) {
unchecked {
// Explicit bounds check
require((z = uint128(y)) == y);
}
}
/// @notice Cast a uint192 to a uint128, revert on overflow
/// @param y The uint192 to be downcasted
/// @return z The downcasted integer, now type uint128
function toUint128By192(uint192 y) internal pure returns (uint128 z) {
unchecked {
// Explicit bounds check
require((z = uint128(y)) == y);
}
}
/// @notice Cast a uint144 to a uint128, revert on overflow
/// @param y The uint144 to be downcasted
/// @return z The downcasted integer, now type uint128
function toUint128By144(uint144 y) internal pure returns (uint128 z) {
unchecked {
// Explicit bounds check
require((z = uint128(y)) == y);
}
}
/// @notice Cast a uint128 to a int128, revert on overflow
/// @param y The uint128 to be casted
/// @return z The casted integer, now type int128
function toInt128Sign(uint128 y) internal pure returns (int128 z) {
unchecked {
// Explicit bounds check
require(y < 2 ** 127);
return int128(y);
}
}
// Unix timestamp can fit into 32-bits until the year 2106. After which, internally
// stored timestamps will stop increasing. Deployed contracts relying on this function
// should be re-evaluated before that date.
function timeUint32() internal view returns (uint32) {
unchecked {
// Explicit bounds check
uint256 time = block.timestamp;
if (time > type(uint32).max) return type(uint32).max;
return uint32(time);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import "./LiquidityAmountsNative.sol";
/// @title Liquidity amount functions
/// @notice Provides functions for computing liquidity amounts from token amounts and prices
/// @dev Note For exact bytecode compatibiility this library uses Uniswap V3 X64.96 price
/// format even though CrocSwap uses X64.64 prices. To use X64.64 prices use the
/// LiquidityAmountsNative library instead.
library LiquidityAmounts {
/// @notice Downcasts uint256 to uint128
/// @param x The uint258 to be downcasted
/// @return y The passed value, downcasted to uint128
function toUint128(uint256 x) private pure returns (uint128 y) {
require((y = uint128(x)) == x);
}
function convertPriceToX64(uint160 sqrtRatioX96) private pure returns (uint128) {
return uint128(sqrtRatioX96 >> 32);
}
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount0 The amount0 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount0(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount0
) internal pure returns (uint128 liquidity) {
return LiquidityAmountsNative.getLiquidityForAmount0(sqrtRatioAX64, sqrtRatioBX64, amount0);
}
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount1 The amount1 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount1(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount1
) internal pure returns (uint128 liquidity) {
return LiquidityAmountsNative.getLiquidityForAmount1(sqrtRatioAX64, sqrtRatioBX64, amount1);
}
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX64 A sqrt price representing the current pool prices
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount0 The amount of token0 being sent in
/// @param amount1 The amount of token1 being sent in
/// @return liquidity The maximum amount of liquidity received
function getLiquidityForAmounts(
uint128 sqrtRatioX64,
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX64 > sqrtRatioBX64) (sqrtRatioAX64, sqrtRatioBX64) = (sqrtRatioBX64, sqrtRatioAX64);
if (sqrtRatioX64 <= sqrtRatioAX64) {
liquidity = getLiquidityForAmount0(sqrtRatioAX64, sqrtRatioBX64, amount0);
} else if (sqrtRatioX64 < sqrtRatioBX64) {
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX64, sqrtRatioBX64, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX64, sqrtRatioX64, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
liquidity = getLiquidityForAmount1(sqrtRatioAX64, sqrtRatioBX64, amount1);
}
}
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
function getAmount0ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0) {
return
LiquidityAmountsNative.getAmount0ForLiquidity(
convertPriceToX64(sqrtRatioAX96),
convertPriceToX64(sqrtRatioBX96),
liquidity
);
}
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount1 The amount of token1
function getAmount1ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount1) {
return
LiquidityAmountsNative.getAmount1ForLiquidity(
convertPriceToX64(sqrtRatioAX96),
convertPriceToX64(sqrtRatioBX96),
liquidity
);
}
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX96 A sqrt price representing the current pool prices
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function getAmountsForLiquidity(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);
} else {
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import "src/libraries/FixedPoint.sol";
import "src/libraries/CurveMath.sol";
import "src/libraries/LiquidityMath.sol";
/// @title Liquidity amount functions
/// @notice Same as LiquidityAmounts.sol library but uses CrocSwap native X64.64 prices instead
/// of Uniswap X64.96 price format
library LiquidityAmountsNative {
/// @notice Downcasts uint256 to uint128
/// @param x The uint258 to be downcasted
/// @return y The passed value, downcasted to uint128
function toUint128(uint256 x) private pure returns (uint128 y) {
require((y = uint128(x)) == x);
}
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount0 The amount0 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount0(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount0
) internal pure returns (uint128 liquidity) {
return
LiquidityMath.shaveRoundLots(
CurveMath.liquiditySupported(toUint128(amount0), false, sqrtRatioAX64, sqrtRatioBX64)
);
}
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount1 The amount1 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount1(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount1
) internal pure returns (uint128 liquidity) {
return
LiquidityMath.shaveRoundLots(
CurveMath.liquiditySupported(toUint128(amount1), true, sqrtRatioAX64, sqrtRatioBX64)
);
}
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX64 A sqrt price representing the current pool prices
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param amount0 The amount of token0 being sent in
/// @param amount1 The amount of token1 being sent in
/// @return liquidity The maximum amount of liquidity received
function getLiquidityForAmounts(
uint128 sqrtRatioX64,
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX64 > sqrtRatioBX64) (sqrtRatioAX64, sqrtRatioBX64) = (sqrtRatioBX64, sqrtRatioAX64);
if (sqrtRatioX64 <= sqrtRatioAX64) {
liquidity = getLiquidityForAmount0(sqrtRatioAX64, sqrtRatioBX64, amount0);
} else if (sqrtRatioX64 < sqrtRatioBX64) {
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX64, sqrtRatioBX64, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX64, sqrtRatioX64, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
liquidity = getLiquidityForAmount1(sqrtRatioAX64, sqrtRatioBX64, amount1);
}
}
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
function getAmount0ForLiquidity(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint128 liquidity
) internal pure returns (uint256 amount0) {
return CurveMath.deltaQuote(liquidity, sqrtRatioAX64, sqrtRatioBX64);
}
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount1 The amount of token1
function getAmount1ForLiquidity(
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint128 liquidity
) internal pure returns (uint256 amount1) {
return CurveMath.deltaBase(liquidity, sqrtRatioAX64, sqrtRatioBX64);
}
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX64 A sqrt price representing the current pool prices
/// @param sqrtRatioAX64 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX64 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function getAmountsForLiquidity(
uint128 sqrtRatioX64,
uint128 sqrtRatioAX64,
uint128 sqrtRatioBX64,
uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
if (sqrtRatioAX64 > sqrtRatioBX64) (sqrtRatioAX64, sqrtRatioBX64) = (sqrtRatioBX64, sqrtRatioAX64);
if (sqrtRatioX64 <= sqrtRatioAX64) {
amount0 = getAmount0ForLiquidity(sqrtRatioAX64, sqrtRatioBX64, liquidity);
} else if (sqrtRatioX64 < sqrtRatioBX64) {
amount0 = getAmount0ForLiquidity(sqrtRatioX64, sqrtRatioBX64, liquidity);
amount1 = getAmount1ForLiquidity(sqrtRatioAX64, sqrtRatioX64, liquidity);
} else {
amount1 = getAmount1ForLiquidity(sqrtRatioAX64, sqrtRatioBX64, liquidity);
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23;
interface IOracle {
function latestAnswer() external view returns (int256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @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 ReentrancyGuard {
// 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;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_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 {
// 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 {
// 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) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return a == 0 ? 0 : (a - 1) / b + 1;
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.UNDER_OVERFLOW);
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, expect 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Ferma's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return x < 0 ? (n - uint256(-x)) : uint256(x); // Wrap the result if it's negative.
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked has failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
/// @solidity memory-safe-assembly
assembly {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 1);
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 1);
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: GPL-3
pragma solidity >=0.8.23;
/// @title FixedPoint128
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
library FixedPoint {
uint256 internal constant Q128 = 0x100000000000000000000000000000000;
uint256 internal constant Q96 = 0x1000000000000000000000000;
uint256 internal constant Q64 = 0x10000000000000000;
uint256 internal constant Q48 = 0x1000000000000;
uint8 internal constant RESOLUTION = 64;
/* @notice Multiplies two Q64.64 numbers by each other. */
function mulQ64(uint128 x, uint128 y) internal pure returns (uint192) {
unchecked {
// 128 bit integers squared will always fit in 256-bits
return uint192((uint256(x) * uint256(y)) >> 64);
}
}
/* @notice Divides one Q64.64 number by another. */
function divQ64(uint128 x, uint128 y) internal pure returns (uint192) {
unchecked {
// No overflow or underflow possible in the below operations
return (uint192(x) << 64) / y;
}
}
/* @notice Multiplies a Q64.64 by a Q16.48. */
function mulQ48(uint128 x, uint64 y) internal pure returns (uint144) {
unchecked {
// 128 bit integers squared will always fit in 256-bits
return uint144((uint256(x) * uint256(y)) >> 48);
}
}
/* @notice Takes the reciprocal of a Q64.64 number. */
function recipQ64(uint128 x) internal pure returns (uint128) {
unchecked {
// Only possible overflow possible is captured with a specific check
uint256 div = uint256(FixedPoint.Q128) / uint256(x);
require(div <= type(uint128).max);
return uint128(div);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.23;
import "src/utils/Errors.sol";
import "src/utils/Variables.sol";
import "src/utils/Constants.sol";
import "src/libraries/TickMath.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { SafeCast } from "./SafeCast.sol";
struct TickParameters {
uint256 oraclePrice;
int24 baseWidth;
int24 limitWidth;
int24 tickSize;
uint8 token1Decimals;
int24 currentTick;
bool isLimitRight;
}
library VaultLibrary {
function _checkTicks(int24 _upperTick, int24 _lowerTick, int24 tickSize) internal pure {
if (_upperTick < _lowerTick || _upperTick % tickSize != 0 || _lowerTick % tickSize != 0) {
revert BadRange();
}
}
function checkLiqParams(int24[] memory _upperTicks, int24[] memory _lowerTicks, int24 tickSize) internal pure {
uint256 lenTicks = _upperTicks.length;
if (lenTicks != _lowerTicks.length) revert BadSetup();
for (uint i; i < lenTicks; ) {
_checkTicks(_upperTicks[i], _lowerTicks[i], tickSize);
unchecked {
++i;
}
}
}
function checkWeights(uint16[] memory _lpWeights) internal pure {
uint16 cumWeight;
uint256 lenWeights = _lpWeights.length;
for (uint i; i < lenWeights; ) {
cumWeight += _lpWeights[i];
unchecked {
++i;
}
}
if (cumWeight != BASE) revert BadSetup();
}
function setTicks(
TickParameters memory params
) external pure returns (int24[] memory newUpperTicks, int24[] memory newLowerTicks) {
newUpperTicks = new int24[](2);
newLowerTicks = new int24[](2);
newUpperTicks[0] =
((TickMath.getTickAtSqrtRatio(
SafeCast.toUint128(Math.sqrt((params.oraclePrice << 128) / (10 ** params.token1Decimals)))
) + params.baseWidth) / params.tickSize) *
params.tickSize;
newLowerTicks[0] =
((TickMath.getTickAtSqrtRatio(
SafeCast.toUint128(Math.sqrt((params.oraclePrice << 128) / (10 ** params.token1Decimals)))
) - params.baseWidth) / params.tickSize) *
params.tickSize;
if (params.isLimitRight) {
newUpperTicks[1] =
((TickMath.getTickAtSqrtRatio(
SafeCast.toUint128(Math.sqrt((params.oraclePrice << 128) / (10 ** params.token1Decimals)))
) + params.limitWidth) / params.tickSize) *
params.tickSize;
newLowerTicks[1] = (params.currentTick / params.tickSize) * params.tickSize + params.tickSize;
} else {
newUpperTicks[1] = (params.currentTick / params.tickSize) * params.tickSize - params.tickSize;
newLowerTicks[1] =
((TickMath.getTickAtSqrtRatio(
SafeCast.toUint128(Math.sqrt((params.oraclePrice << 128) / (10 ** params.token1Decimals)))
) - params.limitWidth) / params.tickSize) *
params.tickSize;
}
return (newUpperTicks, newLowerTicks);
}
}// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.23; uint16 constant BASE = 10_000; uint256 constant CURVE_MAP_SLOT = 65_551;
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.23;
struct StrategyParameters {
string name;
string symbol;
uint8 assetIdx;
uint8 baseLPIdx;
uint16 fee;
uint16 investedPercentage;
uint16 swapSlippage;
address feeRecipient;
address token0;
address token1;
address governor;
address cQuery;
address cSwapDex;
}
struct SymetricStrategyParameters {
string name;
string symbol;
uint8 assetIdx;
uint16 fee;
uint16 investedPercentage;
uint16 swapSlippage;
address feeRecipient;
address token0;
address token1;
address governor;
address cQuery;
address cSwapDex;
address oracle;
}
struct LstParameters {
string name;
string symbol;
uint8 assetIdx;
uint16 fee;
uint16 investedPercentage;
address feeRecipient;
address token0;
address token1;
address governor;
address cQuery;
address cSwapDex;
address oracle;
address unWrappedToken;
address withdrawalQueue;
}
struct LpParam {
int24 upperTick;
int24 lowerTick;
}
struct LstParam {
int24 upperTick;
int24 lowerTick;
uint32 pivot;
}
struct WithdrawalData {
uint256 requestId;
uint256 amount;
}// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.23; error NotEnoughToken(); error WrongMessageValue(); error NotEnoughReceived(); error BadSetup(); error BadRange(); error HighSlippage(); error MinAmount(); error WithdrawExceedsMax(); error LpAlreadyExists(); error NotEnoughLiquidFund();
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: GPL-3
pragma solidity 0.8.23;
pragma experimental ABIEncoderV2;
import "./SafeCast.sol";
import "./FixedPoint.sol";
import "./LiquidityMath.sol";
import "./CompoundMath.sol";
/* @title Curve and swap math library
* @notice Library that defines locally stable constant liquidity curves and
* swap struct, as well as functions to derive impact and aggregate
* liquidity measures on these objects. */
library CurveMath {
using LiquidityMath for uint128;
using CompoundMath for uint256;
using SafeCast for uint256;
using SafeCast for uint192;
/* All CrocSwap swaps occur as legs across locally stable constant-product AMM
* curves. For large moves across tick boundaries, the state of this curve might
* change as range-bound liquidity is kicked in or out of the currently active
* curve. But for small moves within tick boundaries (or between tick boundaries
* with no liquidity bumps), the curve behaves like a classic constant-product AMM.
*
* CrocSwap tracks two types of liquidity. 1) Ambient liquidity that is non-
* range bound and remains active at all prices from zero to infinity, until
* removed by the staking user. 2) Concentrated liquidity that is tied to an
* arbitrary lower<->upper tick range and is kicked out of the curve when the
* price moves out of range.
*
* In the CrocSwap model all collected fees are directly incorporated as expanded
* liquidity onto the curve itself. (See CurveAssimilate.sol for more on the
* mechanics.) All accumulated fees are added as ambient-type liquidity, even those
* fees that belong to the pro-rata share of the active concentrated liquidity.
* This is because on an aggregate level, we can't break down the pro-rata share
* of concentrated rewards to the potentially near infinite concentrated range
* possibilities.
*
* Because of this concentrated liquidity can be flatly represented as 1:1 with
* contributed liquidity. Ambient liquidity, in contrast, deflates over time as
* it accumulates rewards. Therefore it's represented in terms of seed amount,
* i.e. the equivalent of 1 unit of ambient liquidity contributed at the inception
* of the pool. As fees accumulate the conversion rate from seed to liquidity
* continues to increase.
*
* Finally concentrated liquidity rewards are represented in terms of accumulated
* ambient seeds. This automatically takes care of the compounding of ambient
* rewards compounded on top of concentrated rewards.
*
* @param priceRoot_ The square root of the price ratio exchange rate between the
* base and quote-side tokens in the AMM curve. (represented in Q64.64 fixed point)
* @param ambientSeeds_ The total ambient liquidity seeds in the current curve.
* (Inflated by seed deflator to get efective ambient liquidity)
* @param concLiq_ The total concentrated liquidity active and in range at the
* current state of the curve.
* @param seedDeflator_ The cumulative growth rate (represented as Q16.48 fixed
* point) of a hypothetical 1-unit of ambient liquidity held in the pool since
* inception.
* @param concGrowth_ The cumulative rewards growth rate (represented as Q16.48
* fixed point) of hypothetical 1 unit of concentrated liquidity in range in the
* pool since inception.
*
* @dev Price ratio is stored as a square root because it makes reserve calculation
* arithmetic much easier. To be conservative with collateral these growth
* rates should always be rounded down from their real-value results. Some
* minor lower-bound approximation is fine, since all it will result in is
* slightly smaller reward payouts. */
struct CurveState {
uint128 priceRoot_;
uint128 ambientSeeds_;
uint128 concLiq_;
uint64 seedDeflator_;
uint64 concGrowth_;
}
/* @notice Calculates the total amount of liquidity represented by the liquidity
* curve object.
* @dev Result always rounds down from the real value, *assuming* that the fee
* accumulation fields are conservative lower-bound rounded.
* @param curve - The currently active liqudity curve state. Remember this curve
* state is only known to be valid within the current tick.
* @return - The total scalar liquidity. Equivalent to sqrt(X*Y) in an equivalent
* constant-product AMM. */
function activeLiquidity(CurveState memory curve) internal pure returns (uint128) {
uint128 ambient = CompoundMath.inflateLiqSeed(curve.ambientSeeds_, curve.seedDeflator_);
return LiquidityMath.addLiq(ambient, curve.concLiq_);
}
/* @notice Similar to calcLimitFlows(), except returns the max possible flow in the
* *opposite* direction. I.e. if inBaseQty_ is True, returns the quote token flow
* for the swap. And vice versa..
*
* @dev The fixed-point result approximates the real valued formula with close but
* directionally unpredicable precision. It could be slightly above or slightly
* below. In the case of zero flows this could be substantially over. This
* function should not be used in any context with strict directional boundness
* requirements. */
function calcLimitCounter(
CurveState memory curve,
uint128 swapQty,
bool inBaseQty,
uint128 limitPrice
) internal pure returns (uint128) {
bool isBuy = limitPrice > curve.priceRoot_;
uint128 denomFlow = calcLimitFlows(curve, swapQty, inBaseQty, limitPrice);
return invertFlow(activeLiquidity(curve), curve.priceRoot_, denomFlow, isBuy, inBaseQty);
}
/* @notice Calculates the total quantity of tokens that can be swapped on the AMM
* curve until either 1) the limit price is reached or 2) the swap fills its
* entire remaining quantity.
*
* @dev This function does *NOT* account for the possibility of concentrated liq
* being knocked in/out as the price on the AMM curve moves across tick boundaries.
* It's the responsibility of the caller to properly check whether the limit price
* is within the bounds of the locally stable curve.
*
* @dev As long as CurveState's fee accum fields are conservatively lower bounded,
* and as long as limitPrice is accurate, then this function rounds down from the
* true real value. At most this round down loss of precision is tightly bounded at
* 2 wei. (See comments in deltaPriceQuote() function)
*
* @param curve - The current state of the liquidity curve. No guarantee that it's
* liquidity stable through the entire limit range (see @dev above). Note that this
* function does *not* update the curve struct object.
* @param swapQty - The total remaining quantity left in the swap.
* @param inBaseQty - Whether the swap quantity is denomianted in base or quote side
* token.
* @param limitPrice - The highest (lowest) acceptable ending price of the AMM curve
* for a buy (sell) swap. Represented as Q64.64 fixed point square root of the
* price.
*
* @return - The maximum executable swap flow (rounded down by fixed precision).
* Denominated on the token side based on inBaseQty param. Will
* always return unsigned magnitude regardless of the direction. User
* can easily determine based on swap context. */
function calcLimitFlows(
CurveState memory curve,
uint128 swapQty,
bool inBaseQty,
uint128 limitPrice
) internal pure returns (uint128) {
uint128 limitFlow = calcLimitFlows(curve, inBaseQty, limitPrice);
return limitFlow > swapQty ? swapQty : limitFlow;
}
function calcLimitFlows(CurveState memory curve, bool inBaseQty, uint128 limitPrice) private pure returns (uint128) {
uint128 liq = activeLiquidity(curve);
return inBaseQty ? deltaBase(liq, curve.priceRoot_, limitPrice) : deltaQuote(liq, curve.priceRoot_, limitPrice);
}
/* @notice Calculates the change to base token reserves associated with a price
* move along an AMM curve of constant liquidity.
*
* @dev Result is a tight lower-bound for fixed-point precision. Meaning if the
* the returned limit is X, then X will be inside the limit price and (X+1)
* will be outside the limit price. */
function deltaBase(uint128 liq, uint128 priceX, uint128 priceY) internal pure returns (uint128) {
unchecked {
uint128 priceDelta = priceX > priceY ? priceX - priceY : priceY - priceX; // Condition assures never underflows
return reserveAtPrice(liq, priceDelta, true);
}
}
/* @notice Calculates the change to quote token reserves associated with a price
* move along an AMM curve of constant liquidity.
*
* @dev Result is almost always within a fixed-point precision unit from the true
* real value. However in certain rare cases, the result could be up to 2 wei
* below the true mathematical value. Caller should account for this */
function deltaQuote(uint128 liq, uint128 price, uint128 limitPrice) internal pure returns (uint128) {
// For purposes of downstream calculations, we make sure that limit price is
// larger. End result is symmetrical anyway
if (limitPrice > price) {
return calcQuoteDelta(liq, limitPrice, price);
} else {
return calcQuoteDelta(liq, price, limitPrice);
}
}
/* The formula calculated is
* F = L * d / (P*P')
* (where F is the flow to the limit price, where L is liquidity, d is delta,
* P is price and P' is limit price)
*
* Calculating this requires two stacked mulDiv. To meet the function's contract
* we need to compute the result with tight fixed point boundaries at or below
* 2 wei to conform to the function's contract.
*
* The fixed point calculation of flow is
* F = mulDiv(mulDiv(...)) = FR - FF
* (where F is the fixed point result of the formula, FR is the true real valued
* result with inifnite precision, FF is the loss of precision fractional round
* down, mulDiv(...) is a fixed point mulDiv call of the form X*Y/Z)
*
* The individual fixed point terms are
* T1 = mulDiv(X1, Y1, Z1) = T1R - T1F
* T2 = mulDiv(T1, Y2, Z2) = T2R - T2F
* (where T1 and T2 are the fixed point results from the first and second term,
* T1R and T2R are the real valued results from an infinite precision mulDiv,
* T1F and T2F are the fractional round downs, X1/Y1/Z1/Y2/Z2 are the arbitrary
* input terms in the fixed point calculation)
*
* Therefore the total loss of precision is
* FF = T2F + T1F * T2R/T1
*
* To guarantee a 2 wei precision loss boundary:
* FF <= 2
* T2F + T1F * T2R/T1 <= 2
* T1F * T2R/T1 <= 1 (since T2F as a round-down is always < 1)
* T2R/T1 <= 1 (since T1F as a round-down is always < 1)
* Y2/Z2 >= 1
* Z2 >= Y2 */
function calcQuoteDelta(uint128 liq, uint128 priceBig, uint128 priceSmall) private pure returns (uint128) {
uint128 priceDelta = priceBig - priceSmall;
// This is cast to uint256 but is guaranteed to be less than 2^192 based off
// the return type of divQ64
uint256 termOne = FixedPoint.divQ64(liq, priceSmall);
// As long as the final result doesn't overflow from 128-bits, this term is
// guaranteed not to overflow from 256 bits. That's because the final divisor
// can be at most 128-bits, therefore this intermediate term must be 256 bits
// or less.
//
// By definition priceBig is always larger than priceDelta. Therefore the above
// condition of Z2 >= Y2 is satisfied and the equation caps at a maximum of 2
// wei of precision loss.
uint256 termTwo = (termOne * uint256(priceDelta)) / uint256(priceBig);
return termTwo.toUint128();
}
/* @notice Returns the amount of virtual reserves give the price and liquidity of the
* constant-product liquidity curve.
*
* @dev The actual pool probably holds significantly less collateral because of the
* use of concentrated liquidity.
* @dev Results always round down from the precise real-valued mathematical result.
*
* @param liq - The total active liquidity in AMM curve. Represented as sqrt(X*Y)
* @param price - The current active (square root of) price of the AMM curve.
* represnted as Q64.64 fixed point
* @param inBaseQty - The side of the pool to calculate the virtual reserves for.
*
* @returns The virtual reserves of the token (rounded down to nearest integer).
* Equivalent to the amount of tokens that would be held for an equivalent
* classical constant- product AMM without concentrated liquidity. */
function reserveAtPrice(uint128 liq, uint128 price, bool inBaseQty) internal pure returns (uint128) {
return (inBaseQty ? uint256(FixedPoint.mulQ64(liq, price)) : uint256(FixedPoint.divQ64(liq, price))).toUint128();
}
/* @notice Calculated the amount of concentrated liquidity within a price range
* supported by a fixed amount of collateral. Note that this calculates the
* collateral only needed by one side of the pair.
*
* @dev Always rounds fixed-point arithmetic result down.
*
* @param collateral The total amount of token collateral being pledged.
* @param inBase If true, the collateral represents the base-side token in the pair.
* If false the quote side token.
* @param priceX The price boundary of the concentrated liquidity position.
* @param priceY The other price boundary of the concentrated liquidity position.
* @returns The total amount of liquidity supported by the collateral. */
function liquiditySupported(
uint128 collateral,
bool inBase,
uint128 priceX,
uint128 priceY
) internal pure returns (uint128) {
if (!inBase) {
return liquiditySupported(collateral, true, FixedPoint.recipQ64(priceX), FixedPoint.recipQ64(priceY));
} else {
unchecked {
uint128 priceDelta = priceX > priceY ? priceX - priceY : priceY - priceX; // Conditional assures never underflows
return liquiditySupported(collateral, true, priceDelta);
}
}
}
/* @notice Calculated the amount of ambient liquidity supported by a fixed amount of
* collateral. Note that this calculates the collateral only needed by one
* side of the pair.
*
* @dev Always rounds fixed-point arithmetic result down.
*
* @param collateral The total amount of token collateral being pledged.
* @param inBase If true, the collateral represents the base-side token in the pair.
* If false the quote side token.
* @param price The current (square root) price of the curve as Q64.64 fixed point.
* @returns The total amount of ambient liquidity supported by the collateral. */
function liquiditySupported(uint128 collateral, bool inBase, uint128 price) internal pure returns (uint128) {
return
inBase
? FixedPoint.divQ64(collateral, price).toUint128By192()
: FixedPoint.mulQ64(collateral, price).toUint128By192();
}
/* @dev The fixed point arithmetic results in output that's a close approximation
* to the true real value, but could be skewed in either direction. The output
* from this function should not be consumed in any context that requires strict
* boundness. */
function invertFlow(
uint128 liq,
uint128 price,
uint128 denomFlow,
bool isBuy,
bool inBaseQty
) private pure returns (uint128) {
if (liq == 0) {
return 0;
}
uint256 invertReserve = reserveAtPrice(liq, price, !inBaseQty);
uint256 initReserve = reserveAtPrice(liq, price, inBaseQty);
unchecked {
uint256 endReserve = (isBuy == inBaseQty)
? initReserve + denomFlow // Will always fit in 256-bits
: initReserve - denomFlow; // flow is always less than total reserves
if (endReserve == 0) {
return type(uint128).max;
}
uint256 endInvert = (uint256(liq) * uint256(liq)) / endReserve;
return (endInvert > invertReserve ? endInvert - invertReserve : invertReserve - endInvert).toUint128();
}
}
/* @notice Computes the amount of token over-collateralization needed to buffer any
* loss of precision rounding in the fixed price arithmetic on curve price. This
* is necessary because price occurs in different units than tokens, and we can't
* assume a single wei is sufficient to buffer one price unit.
*
* @dev In practice the price unit precision is almost always smaller than the token
* token precision. Therefore the result is usually just 1 wei. The exception are
* pools where liquidity is very high or price is very low.
*
* @param liq The total liquidity in the curve.
* @param price The (square root) price of the curve in Q64.64 fixed point
* @param inBase If true calculate the token precision on the base side of the pair.
* Otherwise, calculate on the quote token side.
*
* @return The conservative upper bound in number of tokens that should be
* burned to over-collateralize a single precision unit of price rounding. If
* the price arithmetic involves multiple units of precision loss, this number
* should be multiplied by that factor. */
function priceToTokenPrecision(uint128 liq, uint128 price, bool inBase) internal pure returns (uint128) {
unchecked {
// To provide more base token collateral than price precision rounding:
// delta(B) >= L * delta(P)
// delta(P) <= 2^-64 (64 bit precision rounding)
// delta(B) >= L * 2^-64
// (where L is liquidity, B is base token reserves, P is price)
if (inBase) {
// Since liq is shifted right by 64 bits, adding one can never overflow
return (liq >> 64) + 1;
} else {
// Calculate the quote reservs at the current price and a one unit price step,
// then take the difference as the minimum required quote tokens needed to
// buffer that price step.
uint192 step = FixedPoint.divQ64(liq, price - 1);
uint192 start = FixedPoint.divQ64(liq, price);
// next reserves will always be equal or greater than start reserves, so the
// subtraction will never underflow.
uint192 delta = step - start;
// Round tokens up conservative.
// This will never overflow because 192 bit nums incremented by 1 will always fit in
// 256 bits.
uint256 deltaRound = uint256(delta) + 1;
return deltaRound.toUint128();
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.23;
import "./SafeCast.sol";
import "./TickMath.sol";
/// @title Math library for liquidity
library LiquidityMath {
/// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows
/// @param x The liquidity before change
/// @param y The delta by which liquidity should be changed
/// @return z The liquidity delta
function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) {
unchecked {
// Arithmetic checks done explicitly
if (y < 0) {
require((z = x - uint128(-y)) < x);
} else {
require((z = x + uint128(y)) >= x);
}
}
}
/// @notice Add an unsigned liquidity delta to liquidity and revert if it overflows or underflows
/// @param x The liquidity before change
/// @param y The delta by which liquidity should be changed
/// @return z The liquidity delta
function addLiq(uint128 x, uint128 y) internal pure returns (uint128 z) {
unchecked {
// Arithmetic checks done explicitly
require((z = x + y) >= x);
}
}
/// @notice Add an unsigned liquidity delta to liquidity and revert if it overflows or underflows
/// @param x The liquidity before change
/// @param y The delta by which liquidity should be changed
/// @return z The liquidity delta
function addLots(uint96 x, uint96 y) internal pure returns (uint96 z) {
unchecked {
// Arithmetic checks done explicitly
require((z = x + y) >= x);
}
}
/// @notice Subtract an unsigned liquidity delta to liquidity and revert if it overflows or underflows
/// @param x The liquidity before change
/// @param y The delta by which liquidity should be changed
/// @return z The liquidity delta
function minusDelta(uint128 x, uint128 y) internal pure returns (uint128 z) {
z = x - y;
}
/* @notice Same as minusDelta, but operates on lots of liquidity rather than outright
* liquiidty. */
function minusLots(uint96 x, uint96 y) internal pure returns (uint96 z) {
z = x - y;
}
/* In certain contexts we need to represent liquidity, but don't have the full 128
* bits or precision. The compromise is to use "lots" of liquidity, which is liquidity
* represented as multiples of 1024. Usually in those contexts, max lots is capped at
* 2^96 (equivalent to 2^106 of liquidity.)
*
* More explanation, along with examples can be found in the documentation at
* docs/LiquidityLots.md in the project respository. */
uint16 constant LOT_SIZE = 1024;
uint8 constant LOT_SIZE_BITS = 10;
/* By utilizing the least significant digit of the liquidity lots value, we can
* support special types of "knockout" liquidity, that when crossed trigger specific
* calls. The aggregate knockout liquidity will always sum to an odd number of lots
* whereas all vanilla resting liquidity will have an even number of lots. That
* means we can test whether any level has knockout liquidity simply by seeing if the
* the total sum is an odd number.
*
* More explanation, along with examples can be found in the documentation at
* docs/LiquidityLots.md in the project respository. */
uint96 constant KNOCKOUT_FLAG_MASK = 0x1;
uint8 constant LOT_ACTIVE_BITS = 11;
/* @notice Converts raw liquidity to lots of resting liquidity. (See comment above
* defining lots. */
function liquidityToLots(uint128 liq) internal pure returns (uint96) {
uint256 lots = liq >> LOT_SIZE_BITS;
uint256 liqTrunc = lots << LOT_SIZE_BITS;
bool hasEmptyMask = (lots & KNOCKOUT_FLAG_MASK == 0);
require(hasEmptyMask && liqTrunc == liq && lots < type(uint96).max, "FD");
return uint96(lots);
}
/* @notice Checks if an aggergate lots counter contains a knockout liquidity component
* by checking the least significant bit.
*
* @dev Note that it's critical that the sum *total* of knockout lots on any
* given level be an odd number. Don't add two odd knockout lots together
* without renormalzing, because they'll sum to an even lot quantity. */
function hasKnockoutLiq(uint96 lots) internal pure returns (bool) {
return lots & KNOCKOUT_FLAG_MASK > 0;
}
/* @notice Truncates an existing liquidity quantity into a quantity that's a multiple
* of the 2048-multiplier defining even-sized lots of liquidity. */
function shaveRoundLots(uint128 liq) internal pure returns (uint128) {
return (liq >> LOT_ACTIVE_BITS) << LOT_ACTIVE_BITS;
}
/* @notice Truncates an existing liquidity quantity into a quantity that's a multiple
* of the 2048-multiplier defining even-sized lots of liquidity, but rounds up
* to the next multiple of 2048. */
function shaveRoundLotsUp(uint128 liq) internal pure returns (uint128 result) {
unchecked {
require((liq & 0xfffffffffffffffffffffffffffff800) != 0xfffffffffffffffffffffffffffff800, "overflow");
// By shifting down 11 bits, adding the one will always fit in 128 bits
uint128 roundUp = (liq >> LOT_ACTIVE_BITS) + 1;
return (roundUp << LOT_ACTIVE_BITS);
}
}
/* @notice Given a number of lots of liquidity converts to raw liquidity value. */
function lotsToLiquidity(uint96 lots) internal pure returns (uint128) {
uint96 realLots = lots & ~KNOCKOUT_FLAG_MASK;
return uint128(realLots) << LOT_SIZE_BITS;
}
/* @notice Given a positive and negative delta lots value net out the raw liquidity
* delta. */
function netLotsOnLiquidity(uint96 incrLots, uint96 decrLots) internal pure returns (int128) {
unchecked {
// Original values are 96-bits, every possible difference will fit in signed-128 bits
return lotToNetLiq(incrLots) - lotToNetLiq(decrLots);
}
}
/* @notice Given an amount of lots of liquidity converts to a signed raw liquidity
* delta. (Which by definition is always positive.) */
function lotToNetLiq(uint96 lots) internal pure returns (int128) {
return int128(lotsToLiquidity(lots));
}
/* @notice Blends the weighted average of two fee reward accumulators based on the
* relative size of two liquidity position.
*
* @dev To be conservative in terms of rewards/collateral, this function always
* rounds up to 2 units of precision. We need mileage rounded up, so reward payouts
* are rounded down. However this could lead to the technically "impossible"
* situation where the mileage on a subsequent rewards burn is smaller than the
* blended mileage in the liquidity postion. Technically this shouldn't happen
* because mileage only increases through time. However this is a non-consequential
* failure. burnPosLiq() just treats it as a zero reward situation, and the staker
* loses an economically non-meaningful amount of rewards on the burn. */
function blendMileage(uint64 mileageX, uint128 liqX, uint64 mileageY, uint128 liqY) internal pure returns (uint64) {
if (liqY == 0) {
return mileageX;
}
if (liqX == 0) {
return mileageY;
}
if (mileageX == mileageY) {
return mileageX;
}
uint64 termX = calcBlend(mileageX, liqX, liqX + liqY);
uint64 termY = calcBlend(mileageY, liqY, liqX + liqY);
// With mileage we want to be conservative on the upside. Under-estimating
// mileage means overpaying rewards. So, round up the fractional weights.
return (termX + 1) + (termY + 1);
}
/* @notice Calculates a weighted blend of adding incremental rewards mileage. */
function calcBlend(uint64 mileage, uint128 weight, uint128 total) private pure returns (uint64) {
unchecked {
// Intermediate results will always fit in 256-bits
// Can safely cast, because result will always be smaller than original since
// weight is less than total.
return uint64((uint256(mileage) * uint256(weight)) / uint256(total));
}
}
/* @dev Computes a rounding safe calculation of the accumulated rewards rate based on
* a beginning and end mileage counter. */
function deltaRewardsRate(uint64 feeMileage, uint64 oldMileage) internal pure returns (uint64) {
uint64 REWARD_ROUND_DOWN = 2;
if (feeMileage > oldMileage + REWARD_ROUND_DOWN) {
return feeMileage - oldMileage - REWARD_ROUND_DOWN;
} else {
return 0;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
/// @solidity memory-safe-assembly
assembly {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
}// SPDX-License-Identifier: GPL-3
pragma solidity 0.8.23;
import "./FixedPoint.sol";
import "./TickMath.sol";
import "./SafeCast.sol";
/* @title Compounding math library
* @notice Library provides convenient math functionality for various transformations
* and reverse transformations related to compound growth. */
library CompoundMath {
using SafeCast for uint256;
/* @notice Provides a safe lower-bound approximation of the square root of (1+x)
* based on a two-term Taylor series expansion. The purpose is to calculate
* the square root for small compound growth rates.
*
* Both the input and output values are passed as the growth rate *excluding*
* the 1.0 multiplier base. For example assume the input (X) is 0.1, then the
* output Y is:
* (1 + Y) = sqrt(1+X)
* (1 + Y) = sqrt(1 + 0.1)
* (1 + Y) = 1.0488 (approximately)
* Y = 0.0488 (approximately)
* In the example the square root of 10% compound growth is 4.88%
*
* Another example, assume the input (X) is 0.6, then the output (Y) is:
* (1 + Y) = sqrt(1+X)
* (1 + Y) = sqrt(1 + 0.6)
* (1 + Y) = 1.264 (approximately)
* Y = 0.264 (approximately)
* In the example the square root of 60% growth is 26.4% compound growth
*
* Another example, assume the input (X) is 0.018, then the output (Y) is:
* (1 + Y) = sqrt(1+X)
* (1 + Y) = sqrt(1 + 0.018)
* (1 + Y) = 1.00896 (approximately)
* Y = 0.00896 (approximately)
* In the example the square root of 1.8% growth is 0.896% compound growth
*
* @dev Due to approximation error, only safe to use on input in the range of
* [0,1). Will always round down from the true real value.
*
* @param x The value of x in (1+x). Represented as a Q16.48 fixed-point
* @returns The value of y for which (1+y) = sqrt(1+x). Represented as Q16.48 fixed point
* */
function approxSqrtCompound(uint64 x64) internal pure returns (uint64) {
// Taylor series error becomes too large above 2.0. Approx is still conservative
// but the angel's share becomes unreasonable.
require(x64 < FixedPoint.Q48);
unchecked {
uint256 x = uint256(x64);
// Shift by 48, to bring x^2 back in fixed point precision
uint256 xSq = (x * x) >> 48; // x * x never overflows 256 bits, because x is 64 bits
uint256 linear = x >> 1; // Linear Taylor series term is x/2
uint256 quad = xSq >> 3; // Quadratic Tayler series term ix x^2/8;
// This will always fit in 64 bits because result is smaller than original/
// Will always be greater than 0, because x^2 < x for x < 1
return uint64(linear - quad);
}
}
/* @notice Computes the result from compounding two cumulative growth rates.
* @dev Rounds down from the real value. Caps the result if type exceeds the max
* fixed-point value.
* @param x The compounded growth rate as in (1+x). Represted as Q16.48 fixed-point.
* @param y The compounded growth rate as in (1+y). Represted as Q16.48 fixed-point.
* @returns The cumulative compounded growth rate as in (1+z) = (1+x)*(1+y).
* Represented as Q16.48 fixed-point. */
function compoundStack(uint64 x, uint64 y) internal pure returns (uint64) {
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 num = (ONE + x) * (ONE + y); // Never overflows 256-bits because x and y are 64 bits
uint256 term = num >> 48; // Divide by 48-bit ONE
uint256 z = term - ONE; // term will always be >= ONE
if (z >= type(uint64).max) {
return type(uint64).max;
}
return uint64(z);
}
}
/* @notice Computes the result from backing out a compounded growth value from
* an existing value. The inverse of compoundStack().
* @dev Rounds down from the real value.
* @param val The fixed price representing the starting value that we want
* to back out a pre-growth seed from.
* @param deflator The compounded growth rate to back out, as in (1+g). Represented
* as Q16.48 fixed-point
* @returns The pre-growth value as in val/(1+g). Rounded down as an unsigned
* integer. */
function compoundShrink(uint64 val, uint64 deflator) internal pure returns (uint64) {
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 multFactor = ONE + deflator; // Never overflows because both fit inside 64 bits
uint256 num = uint256(val) << 48; // multiply by 48-bit ONE
uint256 z = num / multFactor; // multFactor will never be zero because it's bounded by 1
return uint64(z); // Will always fit in 64-bits because shrink can only decrease
}
}
/* @notice Computes the implied compound growth rate based on the division of two
* arbitrary quantities.
* @dev Based on this function's use, calulated growth rate will always be
* capped at 100%. The implied growth rate must always be non-negative.
* @param inflated The larger value to be divided. Any 128-bit integer or fixed point
* @param seed The smaller value to use as a divisor. Any 128-bit integer or fixed
* point.
* @returns The cumulative compounded growth rate as in (1+z) = (1+x)/(1+y).
* Represeted as Q16.48. */
function compoundDivide(uint128 inflated, uint128 seed) internal pure returns (uint64) {
// Otherwise arithmetic doesn't safely fit in 256 -bit
require(inflated < type(uint208).max && inflated >= seed);
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 num = uint256(inflated) << 48;
uint256 z = (num / seed) - ONE; // Never underflows because num is always greater than seed
if (z >= ONE) {
return uint64(ONE);
}
return uint64(z);
}
}
/* @notice Calculates a final price from applying a growth rate to a starting price.
* @dev Always rounds in the direction of @shiftUp
* @param price The starting price to be compounded. Q64.64 fixed point.
* @param growth The compounded growth rate to apply, as in (1+g). Represented
* as Q16.48 fixed-point
* @param shiftUp If true compounds the starting price up, so the result will be
* greater. If false, compounds the price down so the result will be
* smaller than the original price.
* @returns The post-growth price as in price*(1+g) (or price*(1-g) if shiftUp is
* false). Q64.64 always rounded in the direction of shiftUp. */
function compoundPrice(uint128 price, uint64 growth, bool shiftUp) internal pure returns (uint128) {
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 multFactor = ONE + growth; // Guaranteed to fit in 65-bits
if (shiftUp) {
uint256 num = uint256(price) * multFactor; // Guaranteed to fit in 193 bits
uint256 z = num >> 48; // De-scale by the 48-bit growth precision
return (z + 1).toUint128(); // Round in the price shift
} else {
uint256 num = uint256(price) << 48;
// No need to safe cast, since this will be smaller than original price
return uint128(num / multFactor);
}
}
}
/* @notice Inflates a starting value by a cumulative growth rate.
* @dev Rounds down from the real value. Result is capped at max(uint128).
* @param seed The pre-inflated starting value as unsigned integer
* @param growth Cumulative growth rate as Q16.48 fixed-point
* @return The ending value = seed * (1 + growth). Rounded down to nearest
* integer value */
function inflateLiqSeed(uint128 seed, uint64 growth) internal pure returns (uint128) {
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 num = uint256(seed) * uint256(ONE + growth); // Guaranteed to fit in 256
uint256 inflated = num >> 48; // De-scale by the 48-bit growth precision;
if (inflated > type(uint128).max) {
return type(uint128).max;
}
return uint128(inflated);
}
}
/* @notice Deflates a starting value by a cumulative growth rate.
* @dev Rounds down from the real value.
* @param liq The post-inflated liquidity as unsigned integer
* @param growth Cumulative growth rate as Q16.48 fixed-point
* @return The ending value = liq / (1 + growth). Rounded down to nearest
* integer value */
function deflateLiqSeed(uint128 liq, uint64 growth) internal pure returns (uint128) {
unchecked {
uint256 ONE = FixedPoint.Q48;
uint256 num = uint256(liq) << 48;
uint256 deflated = num / (ONE + growth); // Guaranteed to fit in 256-bits
// No need to safe cast-- will allways be smaller than starting
return uint128(deflated);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@prb/test/=lib/prb-test/",
"forge-std/=lib/forge-std/",
"@uniswap/v3-periphery/=lib/v3-periphery/contracts/",
"@uniswap/v3-core/=lib/v3-core/contracts/",
"base64-sol/=node_modules/base64-sol/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"prb-test/=lib/prb-test/src/",
"v3-core/=lib/v3-core/contracts/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 100
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {
"src/libraries/VaultLibrary.sol": {
"VaultLibrary": "0x434b096C9fc3F316490F8B07D7d9b34a2eF39cB6"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"int24","name":"_baseWidth","type":"int24"},{"internalType":"int24","name":"_limitWidth","type":"int24"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"assetIdx","type":"uint8"},{"internalType":"uint16","name":"fee","type":"uint16"},{"internalType":"uint16","name":"investedPercentage","type":"uint16"},{"internalType":"uint16","name":"swapSlippage","type":"uint16"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"governor","type":"address"},{"internalType":"address","name":"cQuery","type":"address"},{"internalType":"address","name":"cSwapDex","type":"address"},{"internalType":"address","name":"oracle","type":"address"}],"internalType":"struct SymetricStrategyParameters","name":"sParams","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"BadRange","type":"error"},{"inputs":[],"name":"BadSetup","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"NotEnoughReceived","type":"error"},{"inputs":[],"name":"NotEnoughToken","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"WrongMessageValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int24","name":"baseWidth","type":"int24"},{"indexed":false,"internalType":"int24","name":"limitWidth","type":"int24"}],"name":"BaseAndLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"FeeRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"fee","type":"uint16"}],"name":"FeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"investedPercentage","type":"uint16"}],"name":"InvestedPercentageSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oracle","type":"address"}],"name":"OracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"padding","type":"uint8"}],"name":"PaddingSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"swapSlippage","type":"uint16"}],"name":"SwapSlippageSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNANCE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseWidth","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crocsQuery","outputs":[{"internalType":"contract CrocsQuery","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crocsSwapDex","outputs":[{"internalType":"contract CrocsSwapDex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTick","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLpParams","outputs":[{"components":[{"internalType":"int24","name":"upperTick","type":"int24"},{"internalType":"int24","name":"lowerTick","type":"int24"}],"internalType":"struct LpParam[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"_upperTick","type":"int24"},{"internalType":"int24","name":"_lowerTick","type":"int24"}],"name":"getPosition","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPositions","outputs":[{"internalType":"uint256","name":"amount0Invested","type":"uint256"},{"internalType":"uint256","name":"amount1Invested","type":"uint256"},{"internalType":"uint256","name":"amount0Idle","type":"uint256"},{"internalType":"uint256","name":"amount1Idle","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenAddresses","outputs":[{"internalType":"address[2]","name":"","type":"address[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"investDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"investedPercentage","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitWidth","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"padding","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"minimumReceive","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_fee","type":"uint16"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_investedPercentage","type":"uint16"}],"name":"setInvestedPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_padding","type":"uint8"}],"name":"setPadding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_swapSlippage","type":"uint16"}],"name":"setSwapSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapSlippage","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"_baseWidth","type":"int24"},{"internalType":"int24","name":"_limitWidth","type":"int24"}],"name":"updateBaseAndLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"minimumReceive","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610100806040523462000da25762006b1d80380380916200002182856200193d565b8339810160608282031262000da2576200003b8262001961565b916200004a6020820162001961565b60408201519091906001600160401b03811162000da2576101a0938482840182031262000da2576040519485016001600160401b0381118682101762000cba57604052828201516001600160401b03811162000da25781620000b091848601016200198c565b855282820160200151906001600160401b03821162000da257620000d891838501016200198c565b806020860152620000ee604083850101620019f7565b60408601526200010360608385010162001a06565b60608601526200011860808385010162001a06565b60808601526200012d60a08385010162001a06565b60a08601526200014260c08385010162001a16565b60c08601526200015760e08385010162001a16565b60e08601526200016d6101008385010162001a16565b610100860152620001846101208385010162001a16565b610120860152620001c761018061014093620001a4858288010162001a16565b8589015261016095620001bb878383010162001a16565b878a0152010162001a16565b610180860152845160016000558051906001600160401b03821162000cba5760045490600182811c92168015620018fa575b6020831014620017cc5781601f84931162001888575b50602090601f8311600114620017f957600092620017ed575b50508160011b916000199060031b1c1916176004555b8051906001600160401b03821162000cba5760055490600182811c92168015620017e2575b6020831014620017cc5781601f84931162001776575b50602090601f8311600114620016e757600092620016db575b50508160011b916000199060031b1c1916176005555b6007805461ff0019166104001790556101208401516001600160a01b0316158015620016c5575b8015620016ae575b80156200168e575b80156200167a575b801562001666575b801562001652575b62000e49578301516001600160a01b0390811660e081815292850151821660c052828501516101008601516040516001623a707b60e21b03198152918416600483015290921660248301526101a46044830152909190829060649082905afa90811562000db05760009162001589575b506060015160e083015161ffff90911660010b93906001600160a01b031680620015155750600460125b61010085015160405163313ce56760e01b81529260209184919082906001600160a01b03165afa801562000db057600090620014d3575b61018086015160405163313ce56760e01b81529350602090849060049082906001600160a01b03165afa91821562000db0576000926200148f575b6101808701516040516350d25bcd60e01b81529450602090859060049082906001600160a01b03165afa93841562000db05760009462001452575b506200044a9062001a2b565b9183838102048314841517156200143c57620004669062001a2b565b908115620010e25760e0870151600b80546001600160a01b03199081166001600160a01b039384169081179092556101008a0151600c80549092169316928317905590808281811162001430575b50506001600160a01b03818116908316101562000da257604080516001600160a01b039384166020820190815293909216908201526101a46060808301919091528152620005028162001921565b5190206040805160208101929092526201000f828201528152916001600160401b03606084019081119084111762000cba57606083016040819052835160208086019190912060c0516302ce8af360e01b8452606487019190915290919060249082906001600160a01b03165afa92831562000db057600093620013f0575b50620100026001600160801b038416101580620013cd575b1562000da2576001600160401b600160c01b03604085901b166001600160801b03811160071b81811c6001600160401b03811160061b81811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c9182118a1b82811c9a909a119590971793909317919091171784178617919091179484939091608087106200136a575050505050607e1982011c5b808002607f1c81800260ff1c1c808002607f1c81800260ff1c1c808002607f1c81800260ff1c1c808002607f1c81800260ff1c1c808002607f1c81800260ff1c1c808002607f1c81800260ff1c1c90818002607f1c82800260ff1c1c92838002607f1c84800260ff1c1c94858002607f1c86800260ff1c1c96878002607f1c88800260ff1c1c98898002607f1c8a800260ff1c1c9a8b8002607f1c8c800260ff1c1c9c8d808002607f1c90800260ff1c1c800260cd1c6604000000000000169d800260cc1c6608000000000000169c800260cb1c6610000000000000169b800260ca1c6620000000000000169a800260c91c66400000000000001699800260c81c66800000000000001698800260c71c6701000000000000001697800260c61c6702000000000000001696800260c51c6704000000000000001695800260c41c6708000000000000001694800260c31c6710000000000000001693800260c21c6720000000000000001692800260c11c6740000000000000001691800260c01c6780000000000000001690607f190160401b1717171717171717171717171717693627a301d71055774c85026fdb2df09e81959a81455e260799a0632f810160801d60020b6f028f6481ab7f045a5af012a19d003aa919820160801d60020b1460001462000ecd576f028f6481ab7f045a5af012a19d003aa9190160801d60020b9360ff93505b60405195620008518762001905565b020484528460020b60208501528560020b604085015287606085015216608083015260020b60a0820152600160c082015260c060405191630377eb8760e21b835280516004840152602081015160020b6024840152604081015160020b6044840152606081015160020b606484015260ff608082015116608484015260a081015160020b60a48401520151151560c482015260008160e48173434b096c9fc3f316490f8b07d7d9b34a2ef39cb65af494851562000db05760009160009662000e5a575b508151908651820362000e495760005b82811062000dbc5750505060ff60408501511660805260ff604085015116600281101562000ca457600b01546001600160a01b031662000d185760125b60a05260095460006009558062000cd0575b5080519060005b82811062000bf45762000b0486868660018060a01b0360e0840151168062000bd3575b5061010083015160c051620009bf916001600160a01b03918216911662001ac9565b60018060a01b0360c08401511660018060a01b0319600a541617600a556affffff000000000000000060608401519260075465ffff00000000608087015160201b169063ffff000067ffff00000000000060a089015160301b169360581b6dffffff0000000000000000000000169660101b169062010000600160701b0319161717179160401b16171760075560018060a01b036101808201511660018060a01b0319600854161760085560008051602062006afd83398151915280600052600660205260016040600020018181549155817fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff918183600080a47f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8806000526001604060002001918383549355600080a461012001516001600160a01b031662001c39565b50604051614cdb908162001e2282396080518181816106fa015281816107d601528181610c1601528181610c9601528181610cbd01528181610d2c01528181610e3e01528181610ea601528181610eec015281816110ed01528181611ad6015281816125ec0152613d94015260a0518161155e015260c051818181610a0301528181611ec70152818161344d01528181614103015281816141e7015261481e015260e05181818161048201528181610f7d0152818161292d01528181612afc01528181613504015261438e0152f35b60c05162000bed916001600160a01b039091169062001ac9565b846200099d565b62000c00818362001ab4565b5160020b9062000c11818962001ab4565b5160020b6040519283604081011060018060401b0360408601111762000cba576040840160405283526020830152600954916801000000000000000083101562000cba57600183018060095583101562000ca45760019260096000526020600020019080519062ffffff6020845492015160181b65ffffff0000001692169065ffffffffffff191617179055016200097a565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60096000527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af90815b818301811062000d0b57505062000973565b6000815560010162000cf9565b60ff604085015116600281101562000ca457600b015460405163313ce56760e01b815290602090829060049082906001600160a01b03165afa90811562000db05760009162000d69575b5062000961565b90506020813d60201162000da7575b8162000d87602093836200193d565b8101031262000da25762000d9b90620019f7565b3862000d62565b600080fd5b3d915062000d78565b6040513d6000823e3d90fd5b62000dc8818562001ab4565b5160020b8262000dd9838b62001ab4565b5160020b80831292831562000e2d575b50821562000e14575b505062000e025760010162000924565b6040516309aab2bb60e41b8152600490fd5b62000e20925062001cdc565b60020b1515823862000df2565b62000e3c919350829062001cdc565b60020b1515913862000de9565b60405162de0e3560e11b8152600490fd5b915094503d806000833e62000e7081836200193d565b604082828101031262000da25781516001600160401b03811162000da25762000e9f9082840190840162001a3d565b60208301519092906001600160401b03811162000da25762000ec5928201910162001a3d565b943862000914565b620a276d196fdb2df09e81959a81455e260799a0632f820160801d60020b12158062001344575b1562000da25760006fdb2df09e81959a81455e260799a0632f820160801d60020b121562001324576fdb2df09e81959a81455e260799a0632f810160801d60020b600003935b600185161562001319576ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b03169460028116620012fc575b60048116620012df575b60088116620012c2575b60108116620012a5575b6020811662001288575b604081166200126b575b608081166200124e575b610100811662001231575b610200811662001214575b6104008116620011f7575b6108008116620011da575b6110008116620011bd575b6120008116620011a0575b614000811662001183575b618000811662001166575b62010000811662001149575b6202000081166200112d575b62040000811662001111575b6208000016620010f8575b60006fdb2df09e81959a81455e260799a0632f830160801d60020b13620010cd575b60ff94906001600160401b038216620010c4576000905b6001600160801b0390811660409390931c918716919091011611620010a5576fdb2df09e81959a81455e260799a0632f0160801d60020b5b9362000842565b6f028f6481ab7f045a5af012a19d003aa9190160801d60020b6200109e565b60019062001066565b8415620010e25760001994909404936200104f565b634e487b7160e01b600052601260045260246000fd5b936b048a170391f7dc42444e8fa20260801c936200102d565b6d2216e584f5fa1ea926041bedfe9890950260801c9462001022565b946e5d6af8dedb81196699c329225ee6040260801c9462001016565b946f09aa508b5b7a84e1c677de54f3e99bc90260801c946200100a565b946f31be135f97d08fd981231505542fcfa60260801c9462000ffe565b946f70d869a156d2a1b890bb3df62baf32f70260801c9462000ff3565b946fa9f746462d870fdf8a65dc1f90e061e50260801c9462000fe8565b946fd097f3bdfd2022b8845ad8f792aa58250260801c9462000fdd565b946fe7159475a2c29b7443b29c7fa6e889d90260801c9462000fd2565b946ff3392b0822b70005940c7a398e4b70f30260801c9462000fc7565b946ff987a7253ac413176f2b074cf7815e540260801c9462000fbc565b946ffcbe86c7900a88aedcffc83b479aa3a40260801c9462000fb1565b946ffe5dee046a99a2a811c461f1969c30530260801c9462000fa6565b946fff2ea16466c96a3843ec78b326b528610260801c9462000f9c565b946fff973b41fa98c081472e6896dfb254c00260801c9462000f92565b946fffcb9843d60f6159c9db58835c9266440260801c9462000f88565b946fffe5caca7e10e4e61c3624eaa0941cd00260801c9462000f7e565b946ffff2e50f5f656932ef12357cf3c7fdcc0260801c9462000f74565b946ffff97272373d413259a46990580e213a0260801c9462000f6a565b600160801b62000f56565b6fdb2df09e81959a81455e260799a0632f810160801d60020b9362000f3a565b50620cb14a6fdb2df09e81959a81455e260799a0632f820160801d60020b131562000ef4565b600190831c1160ff6001600160401b03808611600690811b87901c63ffffffff811160051b90811c61ffff811160041b90811c9490941160031b97909210901b6001600160801b03881160071b17171793909317171717607f031b90506200063b565b506f0ffff5433e2b3d8211706e6102aa94726001600160801b0384161062000599565b9092506020813d60201162001427575b8162001412602093606084016200193d565b8101031262000da25760600151913862000581565b3d915062001400565b915091503880620004b4565b634e487b7160e01b600052601160045260246000fd5b9093506020813d60201162001486575b8162001471602093836200193d565b8101031262000da25751926200044a6200043e565b3d915062001462565b91506020833d602011620014ca575b81620014ad602093836200193d565b8101031262000da257620014c3600493620019f7565b9162000403565b3d91506200149e565b506020823d6020116200150c575b81620014f0602093836200193d565b8101031262000da25762001506600492620019f7565b620003c8565b3d9150620014e1565b60206004916040519283809263313ce56760e01b82525afa801562000db05760009062001547575b6004915062000391565b506020813d60201162001580575b8162001564602093836200193d565b8101031262000da2576200157a600491620019f7565b6200153d565b3d915062001555565b905060e0813d60e01162001649575b81620015a760e093836200193d565b8101031262000da257606061ffff916200163c60c060405192620015cb8462001905565b620015d681620019f7565b8452620015e66020820162001a06565b6020850152620015f960408201620019f7565b60408501526200160b85820162001a06565b858501526200161d60808201620019f7565b60808501526200163060a08201620019f7565b60a085015201620019f7565b60c0820152915062000367565b3d915062001598565b5061271061ffff60a08601511611620002f7565b5061271061ffff60808601511611620002ef565b5061271061ffff60608601511611620002e7565b5060e08401516101008501516001600160a01b03918216911610620002df565b506101808401516001600160a01b031615620002d7565b5060c08401516001600160a01b031615620002cf565b01519050388062000292565b6005600090815293507f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091905b601f19841685106200175a576001945083601f1981161062001740575b505050811b01600555620002a8565b015160001960f88460031b161c1916905538808062001731565b8181015183556020948501946001909301929091019062001714565b90915060056000526020600020601f840160051c810160208510620017c4575b90849392915b601f830160051c82018110620017b457505062000279565b600081558594506001016200179c565b508062001796565b634e487b7160e01b600052602260045260246000fd5b91607f169162000263565b01519050388062000228565b6004600090815293507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b91905b601f19841685106200186c576001945083601f1981161062001852575b505050811b016004556200023e565b015160001960f88460031b161c1916905538808062001843565b8181015183556020948501946001909301929091019062001826565b60046000529091507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f840160051c810160208510620018f2575b90849392915b601f830160051c82018110620018e25750506200020f565b60008155859450600101620018ca565b5080620018c4565b91607f1691620001f9565b60e081019081106001600160401b0382111762000cba57604052565b608081019081106001600160401b0382111762000cba57604052565b601f909101601f19168101906001600160401b0382119082101762000cba57604052565b51908160020b820362000da257565b6001600160401b03811162000cba57601f01601f191660200190565b9080601f8301121562000da257815190620019a78262001970565b92620019b760405194856200193d565b8284526020916020848301011162000da25760005b838110620019e35750505060206000918301015290565b8181018301518582018401528201620019cc565b519060ff8216820362000da257565b519061ffff8216820362000da257565b51906001600160a01b038216820362000da257565b60ff16604d81116200143c57600a0a90565b81601f8201121562000da2578051916020916001600160401b03841162000cba578360051b906040519462001a75858401876200193d565b8552838086019282010192831162000da2578301905b82821062001a9a575050505090565b83809162001aa88462001961565b81520191019062001a8b565b805182101562000ca45760209160051b010190565b604051636eb1769f60e11b81523060048201526001600160a01b0392831660248201819052928216919060208082604481875afa91821562000db05760009262001c04575b5060001982018092116200143c576040519360008083870163095ea7b360e01b958682528960248a015260448901526044885262001b4c8862001921565b87519082855af19062001b5e62001cef565b8262001bcc575b508162001bc0575b501562001b7c575b5050505050565b62001bb59462001baf92604051928301526024820152600060448201526044815262001ba88162001921565b8262001d3e565b62001d3e565b388080808062001b75565b90503b15153862001b6d565b80919250519083821592831562001be9575b505050903862001b65565b62001bfb935082018101910162001d24565b38838162001bde565b9080925081813d831162001c31575b62001c1f81836200193d565b8101031262000da25751903862001b0e565b503d62001c13565b6001600160a01b031660008181527fab4ab2000706c1edca36921176badacea74d146983214a5caf9b3c51b4b34356602052604081205490919060008051602062006afd8339815191529060ff1662001cd75780835260066020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b9060020b908115620010e25760020b0790565b3d1562001d1f573d9062001d038262001970565b9162001d1360405193846200193d565b82523d6000602084013e565b606090565b9081602091031262000da25751801515810362000da25790565b60008062001d6b9260018060a01b03169360208151910182865af162001d6362001cef565b908362001db9565b805190811515918262001d9b575b505062001d835750565b60249060405190635274afe760e01b82526004820152fd5b62001db0925060208091830101910162001d24565b15388062001d79565b9062001de2575080511562001dd057805190602001fd5b60405163d6bda27560e01b8152600490fd5b8151158062001e17575b62001df5575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562001dec56fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80630192a31e1461195357806301e1d1141461193857806301ffc9a7146118e2578063065e5360146118bc57806306fdde031461181457806307a2d13a146117ee578063095ea7b3146117365780630a28a4771461029c5780630db09f9114611712578063115c28ad146116ee5780631374df0b146116ca57806318160ddd146116ac5780631aedeabe146116875780631b71ff411461166357806323b872dd1461162b578063248a9ca3146115fc57806324ea54f4146115c15780632f2ff15d14611582578063313ce5671461154457806336568abe146114fd5780633b58b89e1461149257806346904840146114695780634a3a6b65146114405780634e9321e2146113ec5780635181d38f146113835780636e553f6514610b9f57806370a0823114610b655780637adbf97314610af55780637d7c2a1c14610abb5780637dc0d1d014610a925780638027586014610a3257806383451259146109ed5780638d73ea4c1461093c57806391d14854146108ef57806395d89b41146107fc5780639f40a7b314610764578063a217fddf14610748578063a318c1a41461067e578063a9059cbb1461064d578063b3035a0b146105d3578063b61d27f61461052a578063c6e6f5921461029c578063ca1123c2146104b1578063cbcbc7fd1461046c578063d547741f1461042d578063dd62ed3e146103dc578063ddca3f43146103b7578063e5df8b8414610381578063e74b981b14610300578063ee8c24b8146102a1578063ef8b30f71461029c5763f36c8f5c0361000e57346102975760003660031901126102975760206040517f35a7846a2a701fff6f9d61a46ebff5da578c5dcee8bdf361c569f9ea4ee647718152f35b600080fd5b611a42565b3461029757600036600319011261029757604080516102bf81611d90565b3690376102ca6121a8565b60405190600090825b600283106102e057604084f35b81516001600160a01b0316815260019290920191602091820191016102d3565b3461029757602036600319011261029757610319611a16565b610321612464565b6001600160a01b0316801561037057600a80546001600160a01b031916821790556040519081527fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb32390602090a1005b60405162de0e3560e11b8152600490fd5b3461029757602036600319011261029757600435600281101561029757600b01546040516001600160a01b039091168152602090f35b3461029757600036600319011261029757602061ffff60075460101c16604051908152f35b34610297576040366003190112610297576103f5611a16565b6103fd611a2c565b9060018060a01b038091166000526002602052604060002091166000526020526020604060002054604051908152f35b346102975760403660031901126102975761001960043561044c611a2c565b9080600052600660205261046760016040600020015461253a565b612857565b34610297576000366003190112610297576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346102975760203660031901126102975760043561ffff811690818103610297576104da612464565b6127108211610370577f51632c70eb300357eeb084d66c71fab660ab452e9be56eb1390ece79f8aa06e29160209163ffff00006007549160101b169063ffff0000191617600755604051908152a1005b60603660031901126102975761053e611a16565b6044356001600160401b039182821161029757366023830112156102975781600401359283116102975736602484840101116102975760246000939284936105846128ce565b61058c612464565b8060405193849301833781018481520391602435905af16105ab612434565b9060016000556105cf604051928392151583526040602084015260408301906119f1565b0390f35b346102975760203660031901126102975760043561ffff811690818103610297576105fc612464565b6127108211610370576007805465ffff000000001916602092831b65ffff00000000161790556040519182527f15d91b4d718db1855b9f7ecf5157156ed93b2d3c478384aa28f5457c6b84cea191a1005b3461029757604036600319011261029757610673610669611a16565b6024359033612722565b602060405160018152f35b346102975761068c36611a80565b916106989391936128ce565b6106a06121ff565b926106a96121a8565b906106e3826106dc60018060a01b03966106d388600a541661ffff60075460101c1690858c612bcc565b505050506125d8565b8097613d1f565b9081106107365760209561072994610720879460ff7f00000000000000000000000000000000000000000000000000000000000000001690612321565b51169333613eb2565b6001600055604051908152f35b604051632d65aa3b60e11b8152600490fd5b3461029757600036600319011261029757602060405160008152f35b346102975761077236611a80565b9161077e9391936128ce565b6107866121ff565b9161078f6121a8565b6107bf818360018060a01b03966107b688600a541661ffff60075460101c16908584612bcc565b50505050613d1f565b9485106107365760209561072994610720879360ff7f00000000000000000000000000000000000000000000000000000000000000001690612321565b346102975760003660031901126102975760405160006005549060018260011c91600184169182156108e5575b60209485851084146108cf5785879486865291826000146108af57505060011461086f575b5061085b92500383611dfd565b6105cf6040519282849384528301906119f1565b849150600560005281600020906000915b85831061089757505061085b93508201018561084e565b80548389018501528794508693909201918101610880565b60ff19168582015261085b95151560051b850101925087915061084e9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610829565b3461029757604036600319011261029757610908611a2c565b600435600052600660205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b3461029757604036600319011261029757610955611a60565b61095d611a70565b6109656128ce565b61096d6124de565b8160020b918215610370578160020b9283156103705760407ff377d6a9f671aab6c79113d6ee02cf6ec5f8de70d8e6a14e8b899bbe4852969f916109e6956007548660581b62ffffff60581b169062ffffff851b87861b169065ffffffffffff861b1916171760075582519182526020820152a16134bf565b6001600055005b34610297576000366003190112610297576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610297576000366003190112610297576080610a5e610a506121ff565b610a586121a8565b90613b92565b909150600180841b03610a6f613c0c565b906020825192015192816040519516855216602084015260408301526060820152f35b34610297576000366003190112610297576008546040516001600160a01b039091168152602090f35b3461029757600036600319011261029757610ad46128ce565b610adc6124de565b6109e66007548060581c60020b9060401c60020b6134bf565b3461029757602036600319011261029757610b0e611a16565b610b16612464565b6001600160a01b0316801561037057600880546001600160a01b031916821790556040519081527f3f32684a32a11dabdbb8c0177de80aa3ae36a004d75210335b49e544e48cd0aa90602090a1005b34610297576020366003190112610297576001600160a01b03610b86611a16565b1660005260016020526020604060002054604051908152f35b604036600319011261029757610bb3611a2c565b600160ff196007541617600755610bc86128ce565b610bd0612290565b90610bd96121a8565b610bf960018060a01b03600a541661ffff60075460101c16908386612bcc565b50505050610c086004356125d8565b926001600160a01b03610c3e7f000000000000000000000000000000000000000000000000000000000000000060ff1684612321565b51168061131d5750600435340361130b575b610c6561ffff60075460201c16600435612d0e565b91610c6f82612332565b5151906020610c7d84612332565b5101516008546001600160a01b03169290600290810b907f000000000000000000000000000000000000000000000000000000000000000010156112f5577f0000000000000000000000000000000000000000000000000000000000000000600b8101546001600160a01b03169190610cf590612ead565b60028110156112f557610d6f9388610d509260018060a01b0390600b01541693610d1d611e1e565b610d256121a8565b9360020b907f00000000000000000000000000000000000000000000000000000000000000006142f0565b9060405192610d5e84611dab565b8352602083015260408201526146e7565b6004610d7b8288612353565b600c5460405163313ce56760e01b81529196919260209184919082906001600160a01b03165afa918215611177576000926112b9575b50600b546001600160a01b03168061125157506012905b6040516350d25bcd60e01b815291602083600481855afa9283156111775760009361121b575b50610e06600493610e0060209361256e565b9061257f565b916040519384809263313ce56760e01b82525afa918215611177576000926111da575b50610e36610e3c9261256e565b90612592565b7f000000000000000000000000000000000000000000000000000000000000000060ff166111c25790610e36610e75610e7b938661257f565b9161256e565b935b610e9b60075495610e9561ffff8860301c168a612d0e565b926125b2565b106111b057610f73937f000000000000000000000000000000000000000000000000000000000000000060ff1661119e5760ff83915b60081c1690818082111561119457610ee891612353565b905b7f000000000000000000000000000000000000000000000000000000000000000060ff1661118d57610f1c8389612353565b905b8082111561118357610f2f91612353565b905b84516020860151604051638e56c1c160e01b81526001600160a01b039283166004820152911660248201526101a460448201529560a090879081906064820190565b0381600180851b037f0000000000000000000000000000000000000000000000000000000000000000165afa95861561117757600096611140575b5094516001600160801b0395610ff692918716610fda6020610fcf8b612332565b51015160020b612ebe565b610ff0610fe68b612332565b515160020b612ebe565b9161322e565b9384166110b5575b50505050505060018060a01b031690811561109c57602091611022826003546125b2565b60035580600052600183526040600020828154019055806000600080516020614caf83398151915285604051868152a3604051600435815282848201527fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600160005560ff1960075416600755604051908152f35b60405163ec442f0560e01b815260006004820152602490fd5b6111239560206110d26110c788612332565b515160020b97612332565b510151935160029490940b936001600160a01b0316611135577f000000000000000000000000000000000000000000000000000000000000000060ff1661112e5761111d9250612353565b92613361565b828080808080610ffe565b505061111d565b505050600092613361565b610ff6929196506111689060a03d60a011611170575b6111608183611dfd565b81019061239e565b959091610fae565b503d611156565b6040513d6000823e3d90fd5b5050600090610f31565b8390610f1e565b5050600090610eea565b60ff6111aa8389612353565b91610ed1565b60405163e472516760e01b8152600490fd5b6111ce6111d49261256e565b84612e37565b93610e7d565b91506020823d602011611213575b816111f560209383611dfd565b8101031261029757610e3661120c610e3c93612560565b9250610e29565b3d91506111e8565b92506020833d602011611249575b8161123660209383611dfd565b8101031261029757915191610e06610dee565b3d9150611229565b60206004916040519283809263313ce56760e01b82525afa9081156111775760009161127f575b5090610dc8565b90506020813d6020116112b1575b8161129a60209383611dfd565b81010312610297576112ab90612560565b8b611278565b3d915061128d565b9091506020813d6020116112ed575b816112d560209383611dfd565b81010312610297576112e690612560565b908a610db1565b3d91506112c8565b634e487b7160e01b600052603260045260246000fd5b604051635f97a42560e11b8152600490fd5b6040516323b872dd60e01b602082015233602482015230604482015260043560648201526064815260a08101918183106001600160401b0384111761136d5761136892604052614a53565b610c50565b634e487b7160e01b600052604160045260246000fd5b346102975760003660031901126102975761139c6121ff565b6040516020918282018383528151809152836040840192019360005b8281106113c55784840385f35b85518051600290810b865290830151900b84830152948101946040909301926001016113b8565b3461029757604036600319011261029757606061142061140a611a60565b611412611a70565b61141a6121a8565b91612aa3565b6040519260018060801b0392838092168552166020840152166040820152f35b34610297576000366003190112610297576114596128ce565b6114616124de565b6109e66128f1565b3461029757600036600319011261029757600a546040516001600160a01b039091168152602090f35b346102975760203660031901126102975760043560ff811690818103610297577fa01055c07e9a8558cde074fef9285f3ec21371ba0fe0caaf5a49bd704a09c3c0916020916114df612464565b61ff006007549160081b169061ff00191617600755604051908152a1005b3461029757604036600319011261029757611516611a2c565b336001600160a01b038216036115325761001990600435612857565b60405163334bd91960e11b8152600490fd5b3461029757600036600319011261029757602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610297576040366003190112610297576100196004356115a1611a2c565b908060005260066020526115bc60016040600020015461253a565b6127d7565b346102975760003660031901126102975760206040517f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe88152f35b346102975760203660031901126102975760043560005260066020526020600160406000200154604051908152f35b3461029757606036600319011261029757610673611647611a16565b61164f611a2c565b6044359161165e83338361264f565b612722565b3461029757600036600319011261029757602060075460401c60020b604051908152f35b3461029757600036600319011261029757602061ffff60075460301c16604051908152f35b34610297576000366003190112610297576020600354604051908152f35b3461029757600036600319011261029757602060ff60075460081c16604051908152f35b3461029757600036600319011261029757602060075460581c60020b604051908152f35b3461029757600036600319011261029757602060075461ffff60405191831c168152f35b346102975760403660031901126102975761174f611a16565b6024359033156117d5576001600160a01b03169081156117bc57336000526002602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b604051634a1406b160e11b815260006004820152602490fd5b60405163e602df0560e01b815260006004820152602490fd5b3461029757602036600319011261029757602061180c6004356125bf565b604051908152f35b346102975760003660031901126102975760405160006004549060018260011c91600184169182156118b2575b60209485851084146108cf5785879486865291826000146108af575050600114611872575061085b92500383611dfd565b849150600460005281600020906000915b85831061189a57505061085b93508201018561084e565b80548389018501528794508693909201918101611883565b92607f1692611841565b346102975760003660031901126102975760206118d7611e1e565b6040519060020b8152f35b346102975760203660031901126102975760043563ffffffff60e01b811680910361029757602090637965db0b60e01b8114908115611927575b506040519015158152f35b6301ffc9a760e01b1490508261191c565b3461029757600036600319011261029757602061180c611ab9565b346102975760203660031901126102975760043561ffff8116908181036102975761197c612464565b6127108211610370577f86859aa19974f9f3f3d9843f10b1b02adb9d30ca2f4e8d4d4d875a4baf2166379160209161ffff60301b6007549160301b169061ffff60301b191617600755604051908152a1005b60005b8381106119e15750506000910152565b81810151838201526020016119d1565b90602091611a0a815180928185528580860191016119ce565b601f01601f1916010190565b600435906001600160a01b038216820361029757565b602435906001600160a01b038216820361029757565b3461029757602036600319011261029757602061180c6004356125d8565b600435908160020b820361029757565b602435908160020b820361029757565b608090600319011261029757600435906001600160a01b0390602435828116810361029757916044359081168103610297579060643590565b600c546040805163313ce56760e01b8082526001600160a01b03937f000000000000000000000000000000000000000000000000000000000000000060ff1615936020939290918490849060049082908a165afa928315611d8557600093611d4e575b50600b5460009087168581611ce55750505060125b611b39613c0c565b9480865196015197600854169184516350d25bcd60e01b81528281600481875afa908115611cda57908391600091611ca9575b50610e00611b7a929361256e565b93600486518095819382525afa938415611c9f5750600093611c64575b5050610e36611ba59261256e565b91611bb1610a50612290565b9391509385600014611c5d5786915b8615611c3657611be792611be190610e75906001600160801b0388166125b2565b91612e37565b945b8415611c2e5750925b15611c165750611c1392611c0e916001600160801b03166125b2565b6125b2565b90565b611c1393611c0e9250906001600160801b03166125b2565b905092611bf2565b611c5792611c5190610e75906001600160801b0389166125b2565b90612e37565b94611be9565b8291611bc0565b90809350813d8311611c98575b611c7b8183611dfd565b8101031261029757610e36611c92611ba593612560565b92611b97565b503d611c71565b513d6000823e3d90fd5b82819392503d8311611cd3575b611cc08183611dfd565b8101031261029757518290610e00611b6c565b503d611cb6565b86513d6000823e3d90fd5b6004918551928380928782525afa918215611d43578092611d08575b5050611b31565b9091508582813d8311611d3c575b611d208183611dfd565b81010312611d395750611d3290612560565b3880611d01565b80fd5b503d611d16565b8451903d90823e3d90fd5b9092508381813d8311611d7e575b611d668183611dfd565b8101031261029757611d7790612560565b9138611b1c565b503d611d5c565b82513d6000823e3d90fd5b604081019081106001600160401b0382111761136d57604052565b606081019081106001600160401b0382111761136d57604052565b60e081019081106001600160401b0382111761136d57604052565b61018081019081106001600160401b0382111761136d57604052565b90601f801991011681019081106001600160401b0382111761136d57604052565b600b54600c546001600160a01b03918216919081168080841161219f575b50818116828416101561029757604080516001600160a01b03948516602080830191825293909516918101919091526101a4606080830191909152815290928391611e88608082611dfd565b5190206040518281019182526201000f604082015260408152611eaa81611dab565b5190206024604051809481936302ce8af360e01b835260048301527f0000000000000000000000000000000000000000000000000000000000000000165afa91821561117757600092612171575b506001600160801b039180831691506201000282101580612158575b1561029757600160401b600160c01b039060401b168083811160071b9181831c926001600160401b03841160061b93841c9363ffffffff851160051b94851c9461ffff861160041b95861c60ff9687821160031b91821c92600f841160021b93841c94600160038711811b96871c11961717171717171791608083101560001461214c5750607e1982011c5b8002607f928392828493841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c80029081881c82881c1c80029283891c84891c1c800294858a1c868a1c1c800296878b1c888b1c1c800298898c1c8a8c1c1c80029a8b8d1c8c821c1c8002809d1c8d821c1c8002809e81901c90821c1c80029e8f80911c911c1c800260cd1c6604000000000000169d60cc1c6608000000000000169c60cb1c6610000000000000169b60ca1c6620000000000000169a60c91c6640000000000000169960c81c66800000000000001698600160381b9060c71c1697600160391b9060c61c16966001603a1b9060c51c16956001603b1b9060c41c16946001603c1b9060c31c16936001603d1b9060c21c16926001603e1b9060c11c16916001603f1b9060c01c1690607f190160401b1717171717171717171717171717693627a301d71055774c8502906f028f6481ab7f045a5af012a19d003aa919820160801d60020b916fdb2df09e81959a81455e260799a0632f0160801d60020b92838314600014612134575050905090565b61213d84612ebe565b1611612147575090565b905090565b905081607f031b611fa0565b506f0ffff5433e2b3d8211706e6102aa94728210611f14565b90809250813d8311612198575b6121888183611dfd565b8101031261029757513880611ef8565b503d61217e565b92905038611e3c565b60405190600b6000835b600282106121c8575050506121c682611d90565b565b82546001600160a01b0316815260019283019291909101906020016121b2565b6001600160401b03811161136d5760051b60200190565b6009549061220c826121e8565b91604061221c6040519485611dfd565b81845260096000908152906020907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af908287015b85851061225f57505050505050565b6001848192845161226f81611d90565b865460029080820b835260181c900b83820152815201930194019391612250565b6009549061229d826121e8565b9160406122ad6040519485611dfd565b81845260096000908152906020907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af908287015b8585106122f057505050505050565b6001848192845161230081611d90565b865460029080820b835260181c900b838201528152019301940193916122e1565b9060028110156112f55760051b0190565b8051156112f55760200190565b80518210156112f55760209160051b010190565b9190820391821161236057565b634e487b7160e01b600052601160045260246000fd5b51906001600160801b038216820361029757565b51906001600160401b038216820361029757565b908160a0910312610297576040519060a082018281106001600160401b0382111761136d57612411916080916040526123d681612376565b84526123e460208201612376565b60208501526123f560408201612376565b60408501526124066060820161238a565b60608501520161238a565b608082015290565b6001600160401b03811161136d57601f01601f191660200190565b3d1561245f573d9061244582612419565b916124536040519384611dfd565b82523d6000602084013e565b606090565b3360009081527fab4ab2000706c1edca36921176badacea74d146983214a5caf9b3c51b4b3435660205260409020547f35a7846a2a701fff6f9d61a46ebff5da578c5dcee8bdf361c569f9ea4ee647719060ff16156124c05750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b3360009081527fba39d2e119d4075e56dadcfd5cd5b862305d2c4d32649e4866948958647d49cf60205260409020547f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe89060ff16156124c05750565b80600052600660205260406000203360005260205260ff60406000205416156124c05750565b519060ff8216820361029757565b60ff16604d811161236057600a0a90565b8181029291811591840414171561236057565b811561259c570490565b634e487b7160e01b600052601260045260246000fd5b9190820180921161236057565b60035480156125d457611c1391611c51611ab9565b5090565b60035480156125d4576125e9611ab9565b907f000000000000000000000000000000000000000000000000000000000000000060028110156112f557600b01546001600160a01b03161580612643575b61263557611c1392612e37565b611be183611c139493612353565b5060ff60075416612628565b9160018060a01b03809316916000938385526002602052604093848620918316918287526020528486205492600019840361268e575b50505050505050565b8484106126f2575080156126da5781156126c257855260026020528385209085526020520391205538808080808080612685565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b916001600160a01b038084169283156127be571692831561109c57600090838252600160205260408220549083821061278c57509160408282600080516020614caf83398151915295876020965260018652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b604051634b637e8f60e11b815260006004820152602490fd5b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416156000146128525780835260066020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416600014612852578083526006602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b6002600054146128df576002600055565b604051633ee5aeb560e01b8152600490fd5b600b54600c54604051638e56c1c160e01b81526001600160a01b03928316600482015290821660248201526101a460448201529060a0826064817f000000000000000000000000000000000000000000000000000000000000000085165afa91821561117757600092612a82575b50612968612290565b906009549260005b84811061297e575050505050565b8151600191906001600160801b03908116612999838861233f565b5151600292602090816129ac878c61233f565b510151850b9389612a1b6129be613c0c565b926129c76121a8565b966129de6129d660009a612ebe565b918b0b612ebe565b8588015160075460081c60ff1692908380821115612a79576129ff91612353565b925b87519080821115612a7057612a1591612353565b9361322e565b94511615612a67575b508216612a36575b5050505001612970565b612a5e93612a44868b61233f565b5151810b91612a53878c61233f565b510151900b90613361565b38808080612a2c565b51935038612a24565b50508a9361322e565b50508a92612a01565b612a9c91925060a03d60a011611170576111608183611dfd565b903861295f565b825160209093015160405163d7fd8d0f60e01b81523060048201526001600160a01b03948516602482015290841660448201526101a46064820152600292830b6084820152910b60a482015290606090829060c49082907f0000000000000000000000000000000000000000000000000000000000000000165afa9081156111775760009182918391612b37575b50909192565b929150506060823d606011612b87575b81612b5460609383611dfd565b81010312611d395750612b6681612376565b612b7e6040612b7760208501612376565b9301612376565b90919038612b31565b3d9150612b47565b600f91820b910b019060016001607f1b0319821260016001607f1b0383131761236057565b600f0b60016001607f1b031981146123605760000390565b909193600094600093849585809560095482915b818310612cbe575050508089600f0b12612c43575b87600f0b12612c0357505050565b9193506121c691612c2b9061ffff6001600160801b03612c228a612bb4565b16911690612d0e565b602090910151909384916001600160a01b031661428f565b9550612c656001600160801b03612c598a612bb4565b1661ffff831690612d0e565b95808760018060a01b0386818751168015600014612cac575050828092819282908215612ca2575b8a1690f1612bf5575b604051903d90823e3d90fd5b6108fc9150612c8d565b909150612cb9935061428f565b612bf5565b9091999a612d05600191612cff612cf6898f612cda818961233f565b51516020612cea6002938b61233f565b510151820b910b61402c565b93909150612b8f565b9d612b8f565b9a019190612be0565b908082029060001981840990828083109203918083039214612d7f576127109082821115612d6c577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b634e487b7160005260116020526024601cfd5b505061271091500490565b90670de0b6b3a7640000808302919060001981850993838086109503948086039514612e2a5784831115612e0a579082910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82612e235760125b634e487b716000526020526024601cfd5b6011612e12565b505090611c139250612592565b918183029160001981850993838086109503948086039514612e2a5784831115612e0a579082910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b60ff166001039060ff821161236057565b60020b620a276d1981121580613221575b1561029757600081121561321b5780600003905b6001821615613211576ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b031691600281166131f5575b600481166131d9575b600881166131bd575b601081166131a1575b60208116613185575b60408116613169575b60809081811661314e575b6101008116613133575b6102008116613118575b61040081166130fd575b61080081166130e2575b61100081166130c7575b61200081166130ac575b6140008116613091575b6180008116613076575b62010000811661305b575b620200008116613041575b620400008116613027575b620800001661300c575b50600012612ffd575b6001600160401b038116612ff5576000905b60401c60ff91909116016001600160801b031690565b600190612fdf565b801561259c5760001904612fcd565b6b048a170391f7dc42444e8fa26000929302901c9190612fc4565b6d2216e584f5fa1ea926041bedfe98909302811c92612fba565b926e5d6af8dedb81196699c329225ee60402811c92612faf565b926f09aa508b5b7a84e1c677de54f3e99bc902811c92612fa4565b926f31be135f97d08fd981231505542fcfa602811c92612f99565b926f70d869a156d2a1b890bb3df62baf32f702811c92612f8f565b926fa9f746462d870fdf8a65dc1f90e061e502811c92612f85565b926fd097f3bdfd2022b8845ad8f792aa582502811c92612f7b565b926fe7159475a2c29b7443b29c7fa6e889d902811c92612f71565b926ff3392b0822b70005940c7a398e4b70f302811c92612f67565b926ff987a7253ac413176f2b074cf7815e5402811c92612f5d565b926ffcbe86c7900a88aedcffc83b479aa3a402811c92612f53565b926ffe5dee046a99a2a811c461f1969c305302811c92612f49565b916fff2ea16466c96a3843ec78b326b528610260801c91612f3e565b916fff973b41fa98c081472e6896dfb254c00260801c91612f35565b916fffcb9843d60f6159c9db58835c9266440260801c91612f2c565b916fffe5caca7e10e4e61c3624eaa0941cd00260801c91612f23565b916ffff2e50f5f656932ef12357cf3c7fdcc0260801c91612f1a565b916ffff97272373d413259a46990580e213a0260801c91612f11565b600160801b612efe565b80612ee3565b50620cb14a811315612ecf565b929390926001600160801b039190838316838616116132fb575b808316858416811161327b57505050831692830361029757610800600160801b03926132779290600090614ad9565b1690565b83859693959792949716116000146132d55785811690810361029757610800600160801b039485916132b291908590600090614ad9565b169483169283036102975760016132c893614ad9565b1680821015612147575090565b509291809491501692830361029757610800600160801b03926132779290600190614ad9565b939293613248565b602081830312610297578051906001600160401b038211610297570181601f8201121561029757805161333581612419565b926133436040519485611dfd565b8184526020828401011161029757611c1391602080850191016119ce565b600b54600c546007546001600160a01b03928316956001600160801b039593949285169390861660209290921c61ffff1691909102808616929190830361236057604051936001602086015287604086015260608501526101a4608085015260020b60a084015260020b60c0830152612710610800600160801b0391041660e0820152600094859384610100840152610120830152836101408301526101608481840152825261341082611de1565b8394156134a6575b50906134499160405194858094819363a15112f960e01b8352608060048401526040602484015260448301906119f1565b03927f0000000000000000000000000000000000000000000000000000000000000000165af1801561349b5761347d575050565b613498913d8091833e6134908183611dfd565b810190613303565b50565b6040513d84823e3d90fd5b9350613449613418565b519061ffff8216820361029757565b9060018060a01b039182600b54169280600c541693604091825193633fc58f8560e21b85526004928386015260249660248601526101a4604486015260e085606481857f0000000000000000000000000000000000000000000000000000000000000000165afa8015613b6e57600090613ac4575b6060015160019761ffff918216890b96509061354e612290565b9061357061355a6121a8565b9186600a54169060075460101c16908385612bcc565b505050508151918a60005b848110613a635750505050508260085416926135956121a8565b93818551168660009180156000146139f0575050506012915b602080960151168751928684898163313ce56760e01b958682525afa9384156139e5576000946139ae575b5088516350d25bcd60e01b815287818a81875afa9081156139a357908891600091613972575b50610e0061360d929361256e565b91888a518095819382525afa9182156139675760009261392b575b50610e366136359261256e565b9060ff613640613c0c565b9161365a613651858986015161257f565b610e368361256e565b613662611e1e565b9351109389519061367282611dc6565b81528781019b600297880b8d528a820190880b815260608201918c835284608082019416845260a0810195890b865260c0810196875260248c519e8f92630377eb8760e21b8452518d840152518a0b91015251870b60448d015251860b60648c0152511660848a015251830b60a489015251151560c488015260008760e48173434b096c9fc3f316490f8b07d7d9b34a2ef39cb65af49586156139205760009788976138bc575b50875190875182036138ad5760005b828110613835575050506009918254600084558061380d575b5087519760005b8981106137625750505050505050505050506121c66128f1565b61376c818361233f565b51830b613779828b61233f565b51840b89519161378883611d90565b82528782019081528654600160401b8110156137f9578d81018089558110156137e557908d93929188600052896000200191519062ffffff8354915160181b65ffffff0000001692169065ffffffffffff19161717905501613748565b8660328b634e487b7160e01b600052526000fd5b8660418b634e487b7160e01b600052526000fd5b836000528985600020918201915b828110613829575050613741565b60008155018a9061381b565b61383f818b61233f565b51850b8261384d838c61233f565b51870b808312928315613895575b508215613880575b5050613870578a01613728565b87516309aab2bb60e41b81528790fd5b61388a9250614c17565b850b15158238613863565b6138a29193508290614c17565b870b1515913861385b565b865162de0e3560e11b81528690fd5b9096503d8089833e6138ce8183611dfd565b810190868183031261391c578051906001600160401b039182811161391857836138f99183016149e8565b9986820151928311611d3957506139119291016149e8565b9538613719565b8a80fd5b8880fd5b85513d6000823e3d90fd5b91508582813d8311613960575b6139428183611dfd565b8101031261029757610e3661395961363593612560565b9250613628565b503d613938565b88513d6000823e3d90fd5b82819392503d831161399c575b6139898183611dfd565b8101031261029757518790610e006135ff565b503d61397f565b8a513d6000823e3d90fd5b9093508681813d83116139de575b6139c68183611dfd565b81010312610297576139d790612560565b92386135d9565b503d6139bc565b89513d6000823e3d90fd5b6020908a519283809263313ce56760e01b82525afa918215613a58578092613a1b575b5050916135ae565b9091506020823d602011613a50575b81613a3760209383611dfd565b81010312611d395750613a4990612560565b3880613a13565b3d9150613a2a565b8951903d90823e3d90fd5b613abc84613a71838661233f565b5151600290613a958360209283613a88898c61233f565b510151850b90850b612aa3565b505091613aa2868961233f565b5151810b91613ab1878a61233f565b510151900b90614b50565b018b9061357b565b5060e0853d60e011613b66575b81613ade60e09383611dfd565b8101031261029757606094613b5c60c0865192613afa84611dc6565b613b0381612560565b8452613b11602082016134b0565b6020850152613b21888201612560565b88850152613b308982016134b0565b89850152613b4060808201612560565b6080850152613b5160a08201612560565b60a085015201612560565b60c0820152613534565b3d9150613ad1565b84513d6000823e3d90fd5b6001600160801b03918216908216019190821161236057565b906000926000926000928151906000925b828410613bb05750505050565b909192949596613c02613bf6613bfc600193613bed878b613bd1818a61233f565b51516020613be16002938c61233f565b510151820b910b612aa3565b94919092613b79565b9b613b79565b98613b79565b9501929190613ba3565b6040808051613c1a81611d90565b369037805190613c2982611d90565b600b546001600160a01b0390600090821680613cb15750506020602491475b8552600c54168351928380926370a0823160e01b82523060048301525afa918215611c9f5750600091613c7f575b50602082015290565b90506020813d602011613ca9575b81613c9a60209383611dfd565b81010312610297575138613c76565b3d9150613c8d565b60206024918551928380926370a0823160e01b82523060048301525afa918215611d43578092613ce9575b5050602491602091613c48565b9091506020823d602011613d17575b81613d0560209383611dfd565b81010312611d39575051816020613cdc565b3d9150613cf8565b90613d28613c0c565b928351926020809501519160039360035492613d50613d4885848a612e37565b948387612e37565b9581519260009160005b858110613e235750505050505050613d929291613d8c611c0e92611c0e613d7f613c0c565b9789895199015198612353565b94612353565b7f000000000000000000000000000000000000000000000000000000000000000060ff16613dfa57600c54600b54604051611c1395613df494919391926001600160a01b039081169216613de585611dab565b845283015260408201526146e7565b506125b2565b90611c1392613df49160018060a01b039182600b541692600c54169060405193613de585611dab565b8b613e4e88613e32848961233f565b5151600293613e41868b61233f565b510151840b90840b612aa3565b505083546001600160801b039291613e6a919087908516612e37565b91808311613e9e578e8493613e98938c93613e876001988d61233f565b5151820b921692613ab1878d61233f565b01613d5a565b634e487b7160e01b87526001600452602487fd5b6001600160a01b03808216968185169493919287868a0361400d575b505084156127be5760009085825260016020526040948583205490898210613fdc5750908885928885526001602052038684205588600354036003558287600080516020614caf833981519152602089518d8152a31680613fa057508080878015613f96575b82809291819288881690f115613f8b57509160a09593917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9795935b825196875216602086015284015260608301526080820152a1565b8351903d90823e3d90fd5b6108fc9150613f34565b60a0979593915091613fd787827ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9b99979561428f565b613f70565b865163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101899052606490fd5b614017918661264f565b3887613ece565b519081600f0b820361029757565b92919061403a828286612aa3565b50909490506001600160801b0385161561427f57906140fe929160018060a01b03835116916000602085019360018060a01b038551166040519160026020840152604083015260608201526101a460808201528260020b60a08201528360020b60c08201528160e08201528161010082015260018060801b03610120820152816101408201528161016082015261016081526140d581611de1565b6040518097819263a15112f960e01b8352608060048401526040602484015260448301906119f1565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1938415611177576141e295600095614265575b5051925160408051600560208201526001600160a01b0395861691810191909152931660608401526101a46080840152600290810b60a08401520b60c082015260e0810182905261010081018290526001600160801b03610120820152610140810182905261016080820183905281526141b981611de1565b6040518093819263a15112f960e01b8352608060048401526040602484015260448301906119f1565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156111775760009161424a575b5060408180518101031261029757614246604061423f6020840161401e565b920161401e565b9091565b61425f91503d806000833e6134908183611dfd565b38614220565b614278903d8088833e6134908183611dfd565b5038614140565b5050509050600090600090600090565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815260808101916001600160401b0383118284101761136d576121c692604052614a53565b60ff60129116019060ff821161236057565b9195949060020b8660020b81136146d5578360020b136146bb5780516000966001600160a01b0393918416806146445750602096975083876012945b0151166040519788809263313ce56760e01b825260049a8b915afa9081156111775760009161460a575b5084600b54169460a081600c54169660648b6040519485938492638e56c1c160e01b845283015260249a8b8301526101a460448301527f0000000000000000000000000000000000000000000000000000000000000000165afa908115611177576000916145eb575b50516001600160801b03908116906143ef6143e66143dd848061257f565b610e008661256e565b60801c98612ebe565b916143f98761256e565b9282841693840361029757610800600160801b0393614429918591614422918591600190614ad9565b1695612ebe565b906144338561256e565b92831692830361029757600061444893614ad9565b169260009060ff166144d15750509061446091612d8a565b91670de0b6b3a764000095868602958087048814901517156144be575050916144af6144b49285611be161449f61449a6144ba99986142de565b61256e565b6144a9868561257f565b906125b2565b61257f565b90612353565b0490565b601190634e487b7160e01b600052526000fd5b9394989792916144e96144ef929888611be18961256e565b92612d8a565b60ff85168060120160ff81116145d95761450b6145119161256e565b8461257f565b9061452761452161449a8b6142de565b8961257f565b9060ff8a160160ff81116145c7576145509392916144a961454a611be19361256e565b8561257f565b670de0b6b3a764000096878302928084048914901517156145b557916144b461457f92610e006145859561256e565b9361256e565b938581029581870414901517156145a3575050611c13939450612e37565b634e487b7160e01b8252601190528590fd5b634e487b7160e01b8552601184528985fd5b634e487b7160e01b8752601186528b87fd5b634e487b7160e01b8652601185528a86fd5b614604915060a03d60a011611170576111608183611dfd565b386143bf565b906020823d60201161463c575b8161462460209383611dfd565b81010312611d39575061463690612560565b38614356565b3d9150614617565b60206004916040519283809263313ce56760e01b82525afa988915612c96578099614678575b50508360208098999461432c565b9098506020893d6020116146b3575b8161469460209383611dfd565b81010312611d3957508360206146ab81999a612560565b99985061466a565b3d9150614687565b50611c1393945060ff91506146cf90612ead565b1661257f565b5050611c1393945060ff91501661257f565b9060408083018051156149dc578351602080860180519194926001600160a01b0392831691908316828110156149d45760015b614722613c0c565b93858b511686600b5416146000146149c85788855195015194975b516001600160801b038082169190818303610297578b9385156149bd57896f0ffff5433e2b3d8211706e6102aa9471915b818d51991680978a0152168b8801526101a4938460608901528615158060808a015260a089015260c0880152600060e0880152166101008601526000610120860152610140600081870152855261016092838601948686106001600160401b0387111761136d5760009386938492838e528694816149b4575b506149ac575b5063a15112f960e01b825260016101648901528b6101848901528761481861015f19928201826119f1565b0301918a7f0000000000000000000000000000000000000000000000000000000000000000165af180156149a15790869493929161497b575b5050505116856000918015600014614902575050506148709047612353565b9551600091168061488a57505050611c1391504790612353565b90846024928451938480926370a0823160e01b82523060048301525afa9283156148f8575080926148c3575b5050611c13925090612353565b9150919282813d83116148f1575b6148db8183611dfd565b81010312611d39575090611c13915138806148b6565b503d6148d1565b51903d90823e3d90fd5b85516370a0823160e01b81523060048201529190829060249082905afa91821561497057809261493e575b50509061493991612353565b614870565b9091508682813d8311614969575b6149568183611dfd565b81010312611d395750516149393861492d565b503d61494c565b8551903d90823e3d90fd5b614998923d90816000853e6149908285611dfd565b010190613303565b50388080614851565b87513d6000823e3d90fd5b9250386147ed565b905015386147e7565b89620100029161476e565b8451948901519761473d565b91600061471a565b50509050600090600090565b9080601f8301121561029757815190602091614a03816121e8565b93614a116040519586611dfd565b81855260208086019260051b82010192831161029757602001905b828210614a3a575050505090565b81518060020b8103610297578152908301908301614a2c565b60018060a01b031690614a7d600080836020829551910182875af1614a76612434565b9084614c4b565b908151918215159283614aad575b505050614a955750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312614ad5576020015190811591821503611d395750388080614a8b565b5080fd5b9190614afd57916001614af7614af1611c1395614c29565b92614c29565b92614ad9565b6001600160801b039283918291908183168184161115614b485703165b1690811561259c5760401b600160401b600160c01b031604908116906001600160c01b031681036102975790565b900316614b1a565b9092916001600160801b039182821615614c105760018060a01b039485602081875116960151166040519560026020880152604087015260608601526101a4608086015260020b60a085015260020b60c0840152610800600160801b031660e08301526134496000938385949385610100819601526101208201528361014082015261016084818301528152614be581611de1565b60405194858094819363a15112f960e01b8352608060048401526040602484015260448301906119f1565b5050505050565b9060020b90811561259c5760020b0790565b6001600160801b03908116801561259c57600160801b04818111610297571690565b90614c725750805115614c6057805190602001fd5b60405163d6bda27560e01b8152600490fd5b81511580614ca5575b614c83575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c7b56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c6343000817000a35a7846a2a701fff6f9d61a46ebff5da578c5dcee8bdf361c569f9ea4ee6477100000000000000000000000000000000000000000000000000000000000005dc0000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000251c0000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a40000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a7410600000000000000000000000068b9e8b700f19b879b90e8485a00dd7a3044a214000000000000000000000000000000000000000000000000000000000000002154454d504553542053594d204554482d55534443204c502045544820417373657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001854454d504553545f53594d5f4554485f555344435f4554480000000000000000
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80630192a31e1461195357806301e1d1141461193857806301ffc9a7146118e2578063065e5360146118bc57806306fdde031461181457806307a2d13a146117ee578063095ea7b3146117365780630a28a4771461029c5780630db09f9114611712578063115c28ad146116ee5780631374df0b146116ca57806318160ddd146116ac5780631aedeabe146116875780631b71ff411461166357806323b872dd1461162b578063248a9ca3146115fc57806324ea54f4146115c15780632f2ff15d14611582578063313ce5671461154457806336568abe146114fd5780633b58b89e1461149257806346904840146114695780634a3a6b65146114405780634e9321e2146113ec5780635181d38f146113835780636e553f6514610b9f57806370a0823114610b655780637adbf97314610af55780637d7c2a1c14610abb5780637dc0d1d014610a925780638027586014610a3257806383451259146109ed5780638d73ea4c1461093c57806391d14854146108ef57806395d89b41146107fc5780639f40a7b314610764578063a217fddf14610748578063a318c1a41461067e578063a9059cbb1461064d578063b3035a0b146105d3578063b61d27f61461052a578063c6e6f5921461029c578063ca1123c2146104b1578063cbcbc7fd1461046c578063d547741f1461042d578063dd62ed3e146103dc578063ddca3f43146103b7578063e5df8b8414610381578063e74b981b14610300578063ee8c24b8146102a1578063ef8b30f71461029c5763f36c8f5c0361000e57346102975760003660031901126102975760206040517f35a7846a2a701fff6f9d61a46ebff5da578c5dcee8bdf361c569f9ea4ee647718152f35b600080fd5b611a42565b3461029757600036600319011261029757604080516102bf81611d90565b3690376102ca6121a8565b60405190600090825b600283106102e057604084f35b81516001600160a01b0316815260019290920191602091820191016102d3565b3461029757602036600319011261029757610319611a16565b610321612464565b6001600160a01b0316801561037057600a80546001600160a01b031916821790556040519081527fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb32390602090a1005b60405162de0e3560e11b8152600490fd5b3461029757602036600319011261029757600435600281101561029757600b01546040516001600160a01b039091168152602090f35b3461029757600036600319011261029757602061ffff60075460101c16604051908152f35b34610297576040366003190112610297576103f5611a16565b6103fd611a2c565b9060018060a01b038091166000526002602052604060002091166000526020526020604060002054604051908152f35b346102975760403660031901126102975761001960043561044c611a2c565b9080600052600660205261046760016040600020015461253a565b612857565b34610297576000366003190112610297576040517f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf6001600160a01b03168152602090f35b346102975760203660031901126102975760043561ffff811690818103610297576104da612464565b6127108211610370577f51632c70eb300357eeb084d66c71fab660ab452e9be56eb1390ece79f8aa06e29160209163ffff00006007549160101b169063ffff0000191617600755604051908152a1005b60603660031901126102975761053e611a16565b6044356001600160401b039182821161029757366023830112156102975781600401359283116102975736602484840101116102975760246000939284936105846128ce565b61058c612464565b8060405193849301833781018481520391602435905af16105ab612434565b9060016000556105cf604051928392151583526040602084015260408301906119f1565b0390f35b346102975760203660031901126102975760043561ffff811690818103610297576105fc612464565b6127108211610370576007805465ffff000000001916602092831b65ffff00000000161790556040519182527f15d91b4d718db1855b9f7ecf5157156ed93b2d3c478384aa28f5457c6b84cea191a1005b3461029757604036600319011261029757610673610669611a16565b6024359033612722565b602060405160018152f35b346102975761068c36611a80565b916106989391936128ce565b6106a06121ff565b926106a96121a8565b906106e3826106dc60018060a01b03966106d388600a541661ffff60075460101c1690858c612bcc565b505050506125d8565b8097613d1f565b9081106107365760209561072994610720879460ff7f00000000000000000000000000000000000000000000000000000000000000001690612321565b51169333613eb2565b6001600055604051908152f35b604051632d65aa3b60e11b8152600490fd5b3461029757600036600319011261029757602060405160008152f35b346102975761077236611a80565b9161077e9391936128ce565b6107866121ff565b9161078f6121a8565b6107bf818360018060a01b03966107b688600a541661ffff60075460101c16908584612bcc565b50505050613d1f565b9485106107365760209561072994610720879360ff7f00000000000000000000000000000000000000000000000000000000000000001690612321565b346102975760003660031901126102975760405160006005549060018260011c91600184169182156108e5575b60209485851084146108cf5785879486865291826000146108af57505060011461086f575b5061085b92500383611dfd565b6105cf6040519282849384528301906119f1565b849150600560005281600020906000915b85831061089757505061085b93508201018561084e565b80548389018501528794508693909201918101610880565b60ff19168582015261085b95151560051b850101925087915061084e9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610829565b3461029757604036600319011261029757610908611a2c565b600435600052600660205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b3461029757604036600319011261029757610955611a60565b61095d611a70565b6109656128ce565b61096d6124de565b8160020b918215610370578160020b9283156103705760407ff377d6a9f671aab6c79113d6ee02cf6ec5f8de70d8e6a14e8b899bbe4852969f916109e6956007548660581b62ffffff60581b169062ffffff851b87861b169065ffffffffffff861b1916171760075582519182526020820152a16134bf565b6001600055005b34610297576000366003190112610297576040517f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a741066001600160a01b03168152602090f35b34610297576000366003190112610297576080610a5e610a506121ff565b610a586121a8565b90613b92565b909150600180841b03610a6f613c0c565b906020825192015192816040519516855216602084015260408301526060820152f35b34610297576000366003190112610297576008546040516001600160a01b039091168152602090f35b3461029757600036600319011261029757610ad46128ce565b610adc6124de565b6109e66007548060581c60020b9060401c60020b6134bf565b3461029757602036600319011261029757610b0e611a16565b610b16612464565b6001600160a01b0316801561037057600880546001600160a01b031916821790556040519081527f3f32684a32a11dabdbb8c0177de80aa3ae36a004d75210335b49e544e48cd0aa90602090a1005b34610297576020366003190112610297576001600160a01b03610b86611a16565b1660005260016020526020604060002054604051908152f35b604036600319011261029757610bb3611a2c565b600160ff196007541617600755610bc86128ce565b610bd0612290565b90610bd96121a8565b610bf960018060a01b03600a541661ffff60075460101c16908386612bcc565b50505050610c086004356125d8565b926001600160a01b03610c3e7f000000000000000000000000000000000000000000000000000000000000000060ff1684612321565b51168061131d5750600435340361130b575b610c6561ffff60075460201c16600435612d0e565b91610c6f82612332565b5151906020610c7d84612332565b5101516008546001600160a01b03169290600290810b907f000000000000000000000000000000000000000000000000000000000000000010156112f5577f0000000000000000000000000000000000000000000000000000000000000000600b8101546001600160a01b03169190610cf590612ead565b60028110156112f557610d6f9388610d509260018060a01b0390600b01541693610d1d611e1e565b610d256121a8565b9360020b907f00000000000000000000000000000000000000000000000000000000000000006142f0565b9060405192610d5e84611dab565b8352602083015260408201526146e7565b6004610d7b8288612353565b600c5460405163313ce56760e01b81529196919260209184919082906001600160a01b03165afa918215611177576000926112b9575b50600b546001600160a01b03168061125157506012905b6040516350d25bcd60e01b815291602083600481855afa9283156111775760009361121b575b50610e06600493610e0060209361256e565b9061257f565b916040519384809263313ce56760e01b82525afa918215611177576000926111da575b50610e36610e3c9261256e565b90612592565b7f000000000000000000000000000000000000000000000000000000000000000060ff166111c25790610e36610e75610e7b938661257f565b9161256e565b935b610e9b60075495610e9561ffff8860301c168a612d0e565b926125b2565b106111b057610f73937f000000000000000000000000000000000000000000000000000000000000000060ff1661119e5760ff83915b60081c1690818082111561119457610ee891612353565b905b7f000000000000000000000000000000000000000000000000000000000000000060ff1661118d57610f1c8389612353565b905b8082111561118357610f2f91612353565b905b84516020860151604051638e56c1c160e01b81526001600160a01b039283166004820152911660248201526101a460448201529560a090879081906064820190565b0381600180851b037f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf165afa95861561117757600096611140575b5094516001600160801b0395610ff692918716610fda6020610fcf8b612332565b51015160020b612ebe565b610ff0610fe68b612332565b515160020b612ebe565b9161322e565b9384166110b5575b50505050505060018060a01b031690811561109c57602091611022826003546125b2565b60035580600052600183526040600020828154019055806000600080516020614caf83398151915285604051868152a3604051600435815282848201527fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a3600160005560ff1960075416600755604051908152f35b60405163ec442f0560e01b815260006004820152602490fd5b6111239560206110d26110c788612332565b515160020b97612332565b510151935160029490940b936001600160a01b0316611135577f000000000000000000000000000000000000000000000000000000000000000060ff1661112e5761111d9250612353565b92613361565b828080808080610ffe565b505061111d565b505050600092613361565b610ff6929196506111689060a03d60a011611170575b6111608183611dfd565b81019061239e565b959091610fae565b503d611156565b6040513d6000823e3d90fd5b5050600090610f31565b8390610f1e565b5050600090610eea565b60ff6111aa8389612353565b91610ed1565b60405163e472516760e01b8152600490fd5b6111ce6111d49261256e565b84612e37565b93610e7d565b91506020823d602011611213575b816111f560209383611dfd565b8101031261029757610e3661120c610e3c93612560565b9250610e29565b3d91506111e8565b92506020833d602011611249575b8161123660209383611dfd565b8101031261029757915191610e06610dee565b3d9150611229565b60206004916040519283809263313ce56760e01b82525afa9081156111775760009161127f575b5090610dc8565b90506020813d6020116112b1575b8161129a60209383611dfd565b81010312610297576112ab90612560565b8b611278565b3d915061128d565b9091506020813d6020116112ed575b816112d560209383611dfd565b81010312610297576112e690612560565b908a610db1565b3d91506112c8565b634e487b7160e01b600052603260045260246000fd5b604051635f97a42560e11b8152600490fd5b6040516323b872dd60e01b602082015233602482015230604482015260043560648201526064815260a08101918183106001600160401b0384111761136d5761136892604052614a53565b610c50565b634e487b7160e01b600052604160045260246000fd5b346102975760003660031901126102975761139c6121ff565b6040516020918282018383528151809152836040840192019360005b8281106113c55784840385f35b85518051600290810b865290830151900b84830152948101946040909301926001016113b8565b3461029757604036600319011261029757606061142061140a611a60565b611412611a70565b61141a6121a8565b91612aa3565b6040519260018060801b0392838092168552166020840152166040820152f35b34610297576000366003190112610297576114596128ce565b6114616124de565b6109e66128f1565b3461029757600036600319011261029757600a546040516001600160a01b039091168152602090f35b346102975760203660031901126102975760043560ff811690818103610297577fa01055c07e9a8558cde074fef9285f3ec21371ba0fe0caaf5a49bd704a09c3c0916020916114df612464565b61ff006007549160081b169061ff00191617600755604051908152a1005b3461029757604036600319011261029757611516611a2c565b336001600160a01b038216036115325761001990600435612857565b60405163334bd91960e11b8152600490fd5b3461029757600036600319011261029757602060405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b34610297576040366003190112610297576100196004356115a1611a2c565b908060005260066020526115bc60016040600020015461253a565b6127d7565b346102975760003660031901126102975760206040517f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe88152f35b346102975760203660031901126102975760043560005260066020526020600160406000200154604051908152f35b3461029757606036600319011261029757610673611647611a16565b61164f611a2c565b6044359161165e83338361264f565b612722565b3461029757600036600319011261029757602060075460401c60020b604051908152f35b3461029757600036600319011261029757602061ffff60075460301c16604051908152f35b34610297576000366003190112610297576020600354604051908152f35b3461029757600036600319011261029757602060ff60075460081c16604051908152f35b3461029757600036600319011261029757602060075460581c60020b604051908152f35b3461029757600036600319011261029757602060075461ffff60405191831c168152f35b346102975760403660031901126102975761174f611a16565b6024359033156117d5576001600160a01b03169081156117bc57336000526002602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b604051634a1406b160e11b815260006004820152602490fd5b60405163e602df0560e01b815260006004820152602490fd5b3461029757602036600319011261029757602061180c6004356125bf565b604051908152f35b346102975760003660031901126102975760405160006004549060018260011c91600184169182156118b2575b60209485851084146108cf5785879486865291826000146108af575050600114611872575061085b92500383611dfd565b849150600460005281600020906000915b85831061189a57505061085b93508201018561084e565b80548389018501528794508693909201918101611883565b92607f1692611841565b346102975760003660031901126102975760206118d7611e1e565b6040519060020b8152f35b346102975760203660031901126102975760043563ffffffff60e01b811680910361029757602090637965db0b60e01b8114908115611927575b506040519015158152f35b6301ffc9a760e01b1490508261191c565b3461029757600036600319011261029757602061180c611ab9565b346102975760203660031901126102975760043561ffff8116908181036102975761197c612464565b6127108211610370577f86859aa19974f9f3f3d9843f10b1b02adb9d30ca2f4e8d4d4d875a4baf2166379160209161ffff60301b6007549160301b169061ffff60301b191617600755604051908152a1005b60005b8381106119e15750506000910152565b81810151838201526020016119d1565b90602091611a0a815180928185528580860191016119ce565b601f01601f1916010190565b600435906001600160a01b038216820361029757565b602435906001600160a01b038216820361029757565b3461029757602036600319011261029757602061180c6004356125d8565b600435908160020b820361029757565b602435908160020b820361029757565b608090600319011261029757600435906001600160a01b0390602435828116810361029757916044359081168103610297579060643590565b600c546040805163313ce56760e01b8082526001600160a01b03937f000000000000000000000000000000000000000000000000000000000000000060ff1615936020939290918490849060049082908a165afa928315611d8557600093611d4e575b50600b5460009087168581611ce55750505060125b611b39613c0c565b9480865196015197600854169184516350d25bcd60e01b81528281600481875afa908115611cda57908391600091611ca9575b50610e00611b7a929361256e565b93600486518095819382525afa938415611c9f5750600093611c64575b5050610e36611ba59261256e565b91611bb1610a50612290565b9391509385600014611c5d5786915b8615611c3657611be792611be190610e75906001600160801b0388166125b2565b91612e37565b945b8415611c2e5750925b15611c165750611c1392611c0e916001600160801b03166125b2565b6125b2565b90565b611c1393611c0e9250906001600160801b03166125b2565b905092611bf2565b611c5792611c5190610e75906001600160801b0389166125b2565b90612e37565b94611be9565b8291611bc0565b90809350813d8311611c98575b611c7b8183611dfd565b8101031261029757610e36611c92611ba593612560565b92611b97565b503d611c71565b513d6000823e3d90fd5b82819392503d8311611cd3575b611cc08183611dfd565b8101031261029757518290610e00611b6c565b503d611cb6565b86513d6000823e3d90fd5b6004918551928380928782525afa918215611d43578092611d08575b5050611b31565b9091508582813d8311611d3c575b611d208183611dfd565b81010312611d395750611d3290612560565b3880611d01565b80fd5b503d611d16565b8451903d90823e3d90fd5b9092508381813d8311611d7e575b611d668183611dfd565b8101031261029757611d7790612560565b9138611b1c565b503d611d5c565b82513d6000823e3d90fd5b604081019081106001600160401b0382111761136d57604052565b606081019081106001600160401b0382111761136d57604052565b60e081019081106001600160401b0382111761136d57604052565b61018081019081106001600160401b0382111761136d57604052565b90601f801991011681019081106001600160401b0382111761136d57604052565b600b54600c546001600160a01b03918216919081168080841161219f575b50818116828416101561029757604080516001600160a01b03948516602080830191825293909516918101919091526101a4606080830191909152815290928391611e88608082611dfd565b5190206040518281019182526201000f604082015260408152611eaa81611dab565b5190206024604051809481936302ce8af360e01b835260048301527f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a74106165afa91821561117757600092612171575b506001600160801b039180831691506201000282101580612158575b1561029757600160401b600160c01b039060401b168083811160071b9181831c926001600160401b03841160061b93841c9363ffffffff851160051b94851c9461ffff861160041b95861c60ff9687821160031b91821c92600f841160021b93841c94600160038711811b96871c11961717171717171791608083101560001461214c5750607e1982011c5b8002607f928392828493841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c80029081881c82881c1c80029283891c84891c1c800294858a1c868a1c1c800296878b1c888b1c1c800298898c1c8a8c1c1c80029a8b8d1c8c821c1c8002809d1c8d821c1c8002809e81901c90821c1c80029e8f80911c911c1c800260cd1c6604000000000000169d60cc1c6608000000000000169c60cb1c6610000000000000169b60ca1c6620000000000000169a60c91c6640000000000000169960c81c66800000000000001698600160381b9060c71c1697600160391b9060c61c16966001603a1b9060c51c16956001603b1b9060c41c16946001603c1b9060c31c16936001603d1b9060c21c16926001603e1b9060c11c16916001603f1b9060c01c1690607f190160401b1717171717171717171717171717693627a301d71055774c8502906f028f6481ab7f045a5af012a19d003aa919820160801d60020b916fdb2df09e81959a81455e260799a0632f0160801d60020b92838314600014612134575050905090565b61213d84612ebe565b1611612147575090565b905090565b905081607f031b611fa0565b506f0ffff5433e2b3d8211706e6102aa94728210611f14565b90809250813d8311612198575b6121888183611dfd565b8101031261029757513880611ef8565b503d61217e565b92905038611e3c565b60405190600b6000835b600282106121c8575050506121c682611d90565b565b82546001600160a01b0316815260019283019291909101906020016121b2565b6001600160401b03811161136d5760051b60200190565b6009549061220c826121e8565b91604061221c6040519485611dfd565b81845260096000908152906020907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af908287015b85851061225f57505050505050565b6001848192845161226f81611d90565b865460029080820b835260181c900b83820152815201930194019391612250565b6009549061229d826121e8565b9160406122ad6040519485611dfd565b81845260096000908152906020907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af908287015b8585106122f057505050505050565b6001848192845161230081611d90565b865460029080820b835260181c900b838201528152019301940193916122e1565b9060028110156112f55760051b0190565b8051156112f55760200190565b80518210156112f55760209160051b010190565b9190820391821161236057565b634e487b7160e01b600052601160045260246000fd5b51906001600160801b038216820361029757565b51906001600160401b038216820361029757565b908160a0910312610297576040519060a082018281106001600160401b0382111761136d57612411916080916040526123d681612376565b84526123e460208201612376565b60208501526123f560408201612376565b60408501526124066060820161238a565b60608501520161238a565b608082015290565b6001600160401b03811161136d57601f01601f191660200190565b3d1561245f573d9061244582612419565b916124536040519384611dfd565b82523d6000602084013e565b606090565b3360009081527fab4ab2000706c1edca36921176badacea74d146983214a5caf9b3c51b4b3435660205260409020547f35a7846a2a701fff6f9d61a46ebff5da578c5dcee8bdf361c569f9ea4ee647719060ff16156124c05750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b3360009081527fba39d2e119d4075e56dadcfd5cd5b862305d2c4d32649e4866948958647d49cf60205260409020547f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe89060ff16156124c05750565b80600052600660205260406000203360005260205260ff60406000205416156124c05750565b519060ff8216820361029757565b60ff16604d811161236057600a0a90565b8181029291811591840414171561236057565b811561259c570490565b634e487b7160e01b600052601260045260246000fd5b9190820180921161236057565b60035480156125d457611c1391611c51611ab9565b5090565b60035480156125d4576125e9611ab9565b907f000000000000000000000000000000000000000000000000000000000000000060028110156112f557600b01546001600160a01b03161580612643575b61263557611c1392612e37565b611be183611c139493612353565b5060ff60075416612628565b9160018060a01b03809316916000938385526002602052604093848620918316918287526020528486205492600019840361268e575b50505050505050565b8484106126f2575080156126da5781156126c257855260026020528385209085526020520391205538808080808080612685565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b916001600160a01b038084169283156127be571692831561109c57600090838252600160205260408220549083821061278c57509160408282600080516020614caf83398151915295876020965260018652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b604051634b637e8f60e11b815260006004820152602490fd5b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416156000146128525780835260066020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416600014612852578083526006602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b6002600054146128df576002600055565b604051633ee5aeb560e01b8152600490fd5b600b54600c54604051638e56c1c160e01b81526001600160a01b03928316600482015290821660248201526101a460448201529060a0826064817f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf85165afa91821561117757600092612a82575b50612968612290565b906009549260005b84811061297e575050505050565b8151600191906001600160801b03908116612999838861233f565b5151600292602090816129ac878c61233f565b510151850b9389612a1b6129be613c0c565b926129c76121a8565b966129de6129d660009a612ebe565b918b0b612ebe565b8588015160075460081c60ff1692908380821115612a79576129ff91612353565b925b87519080821115612a7057612a1591612353565b9361322e565b94511615612a67575b508216612a36575b5050505001612970565b612a5e93612a44868b61233f565b5151810b91612a53878c61233f565b510151900b90613361565b38808080612a2c565b51935038612a24565b50508a9361322e565b50508a92612a01565b612a9c91925060a03d60a011611170576111608183611dfd565b903861295f565b825160209093015160405163d7fd8d0f60e01b81523060048201526001600160a01b03948516602482015290841660448201526101a46064820152600292830b6084820152910b60a482015290606090829060c49082907f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf165afa9081156111775760009182918391612b37575b50909192565b929150506060823d606011612b87575b81612b5460609383611dfd565b81010312611d395750612b6681612376565b612b7e6040612b7760208501612376565b9301612376565b90919038612b31565b3d9150612b47565b600f91820b910b019060016001607f1b0319821260016001607f1b0383131761236057565b600f0b60016001607f1b031981146123605760000390565b909193600094600093849585809560095482915b818310612cbe575050508089600f0b12612c43575b87600f0b12612c0357505050565b9193506121c691612c2b9061ffff6001600160801b03612c228a612bb4565b16911690612d0e565b602090910151909384916001600160a01b031661428f565b9550612c656001600160801b03612c598a612bb4565b1661ffff831690612d0e565b95808760018060a01b0386818751168015600014612cac575050828092819282908215612ca2575b8a1690f1612bf5575b604051903d90823e3d90fd5b6108fc9150612c8d565b909150612cb9935061428f565b612bf5565b9091999a612d05600191612cff612cf6898f612cda818961233f565b51516020612cea6002938b61233f565b510151820b910b61402c565b93909150612b8f565b9d612b8f565b9a019190612be0565b908082029060001981840990828083109203918083039214612d7f576127109082821115612d6c577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e91940990828211900360fc1b910360041c170290565b634e487b7160005260116020526024601cfd5b505061271091500490565b90670de0b6b3a7640000808302919060001981850993838086109503948086039514612e2a5784831115612e0a579082910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82612e235760125b634e487b716000526020526024601cfd5b6011612e12565b505090611c139250612592565b918183029160001981850993838086109503948086039514612e2a5784831115612e0a579082910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b60ff166001039060ff821161236057565b60020b620a276d1981121580613221575b1561029757600081121561321b5780600003905b6001821615613211576ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b031691600281166131f5575b600481166131d9575b600881166131bd575b601081166131a1575b60208116613185575b60408116613169575b60809081811661314e575b6101008116613133575b6102008116613118575b61040081166130fd575b61080081166130e2575b61100081166130c7575b61200081166130ac575b6140008116613091575b6180008116613076575b62010000811661305b575b620200008116613041575b620400008116613027575b620800001661300c575b50600012612ffd575b6001600160401b038116612ff5576000905b60401c60ff91909116016001600160801b031690565b600190612fdf565b801561259c5760001904612fcd565b6b048a170391f7dc42444e8fa26000929302901c9190612fc4565b6d2216e584f5fa1ea926041bedfe98909302811c92612fba565b926e5d6af8dedb81196699c329225ee60402811c92612faf565b926f09aa508b5b7a84e1c677de54f3e99bc902811c92612fa4565b926f31be135f97d08fd981231505542fcfa602811c92612f99565b926f70d869a156d2a1b890bb3df62baf32f702811c92612f8f565b926fa9f746462d870fdf8a65dc1f90e061e502811c92612f85565b926fd097f3bdfd2022b8845ad8f792aa582502811c92612f7b565b926fe7159475a2c29b7443b29c7fa6e889d902811c92612f71565b926ff3392b0822b70005940c7a398e4b70f302811c92612f67565b926ff987a7253ac413176f2b074cf7815e5402811c92612f5d565b926ffcbe86c7900a88aedcffc83b479aa3a402811c92612f53565b926ffe5dee046a99a2a811c461f1969c305302811c92612f49565b916fff2ea16466c96a3843ec78b326b528610260801c91612f3e565b916fff973b41fa98c081472e6896dfb254c00260801c91612f35565b916fffcb9843d60f6159c9db58835c9266440260801c91612f2c565b916fffe5caca7e10e4e61c3624eaa0941cd00260801c91612f23565b916ffff2e50f5f656932ef12357cf3c7fdcc0260801c91612f1a565b916ffff97272373d413259a46990580e213a0260801c91612f11565b600160801b612efe565b80612ee3565b50620cb14a811315612ecf565b929390926001600160801b039190838316838616116132fb575b808316858416811161327b57505050831692830361029757610800600160801b03926132779290600090614ad9565b1690565b83859693959792949716116000146132d55785811690810361029757610800600160801b039485916132b291908590600090614ad9565b169483169283036102975760016132c893614ad9565b1680821015612147575090565b509291809491501692830361029757610800600160801b03926132779290600190614ad9565b939293613248565b602081830312610297578051906001600160401b038211610297570181601f8201121561029757805161333581612419565b926133436040519485611dfd565b8184526020828401011161029757611c1391602080850191016119ce565b600b54600c546007546001600160a01b03928316956001600160801b039593949285169390861660209290921c61ffff1691909102808616929190830361236057604051936001602086015287604086015260608501526101a4608085015260020b60a084015260020b60c0830152612710610800600160801b0391041660e0820152600094859384610100840152610120830152836101408301526101608481840152825261341082611de1565b8394156134a6575b50906134499160405194858094819363a15112f960e01b8352608060048401526040602484015260448301906119f1565b03927f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a74106165af1801561349b5761347d575050565b613498913d8091833e6134908183611dfd565b810190613303565b50565b6040513d84823e3d90fd5b9350613449613418565b519061ffff8216820361029757565b9060018060a01b039182600b54169280600c541693604091825193633fc58f8560e21b85526004928386015260249660248601526101a4604486015260e085606481857f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf165afa8015613b6e57600090613ac4575b6060015160019761ffff918216890b96509061354e612290565b9061357061355a6121a8565b9186600a54169060075460101c16908385612bcc565b505050508151918a60005b848110613a635750505050508260085416926135956121a8565b93818551168660009180156000146139f0575050506012915b602080960151168751928684898163313ce56760e01b958682525afa9384156139e5576000946139ae575b5088516350d25bcd60e01b815287818a81875afa9081156139a357908891600091613972575b50610e0061360d929361256e565b91888a518095819382525afa9182156139675760009261392b575b50610e366136359261256e565b9060ff613640613c0c565b9161365a613651858986015161257f565b610e368361256e565b613662611e1e565b9351109389519061367282611dc6565b81528781019b600297880b8d528a820190880b815260608201918c835284608082019416845260a0810195890b865260c0810196875260248c519e8f92630377eb8760e21b8452518d840152518a0b91015251870b60448d015251860b60648c0152511660848a015251830b60a489015251151560c488015260008760e48173434b096c9fc3f316490f8b07d7d9b34a2ef39cb65af49586156139205760009788976138bc575b50875190875182036138ad5760005b828110613835575050506009918254600084558061380d575b5087519760005b8981106137625750505050505050505050506121c66128f1565b61376c818361233f565b51830b613779828b61233f565b51840b89519161378883611d90565b82528782019081528654600160401b8110156137f9578d81018089558110156137e557908d93929188600052896000200191519062ffffff8354915160181b65ffffff0000001692169065ffffffffffff19161717905501613748565b8660328b634e487b7160e01b600052526000fd5b8660418b634e487b7160e01b600052526000fd5b836000528985600020918201915b828110613829575050613741565b60008155018a9061381b565b61383f818b61233f565b51850b8261384d838c61233f565b51870b808312928315613895575b508215613880575b5050613870578a01613728565b87516309aab2bb60e41b81528790fd5b61388a9250614c17565b850b15158238613863565b6138a29193508290614c17565b870b1515913861385b565b865162de0e3560e11b81528690fd5b9096503d8089833e6138ce8183611dfd565b810190868183031261391c578051906001600160401b039182811161391857836138f99183016149e8565b9986820151928311611d3957506139119291016149e8565b9538613719565b8a80fd5b8880fd5b85513d6000823e3d90fd5b91508582813d8311613960575b6139428183611dfd565b8101031261029757610e3661395961363593612560565b9250613628565b503d613938565b88513d6000823e3d90fd5b82819392503d831161399c575b6139898183611dfd565b8101031261029757518790610e006135ff565b503d61397f565b8a513d6000823e3d90fd5b9093508681813d83116139de575b6139c68183611dfd565b81010312610297576139d790612560565b92386135d9565b503d6139bc565b89513d6000823e3d90fd5b6020908a519283809263313ce56760e01b82525afa918215613a58578092613a1b575b5050916135ae565b9091506020823d602011613a50575b81613a3760209383611dfd565b81010312611d395750613a4990612560565b3880613a13565b3d9150613a2a565b8951903d90823e3d90fd5b613abc84613a71838661233f565b5151600290613a958360209283613a88898c61233f565b510151850b90850b612aa3565b505091613aa2868961233f565b5151810b91613ab1878a61233f565b510151900b90614b50565b018b9061357b565b5060e0853d60e011613b66575b81613ade60e09383611dfd565b8101031261029757606094613b5c60c0865192613afa84611dc6565b613b0381612560565b8452613b11602082016134b0565b6020850152613b21888201612560565b88850152613b308982016134b0565b89850152613b4060808201612560565b6080850152613b5160a08201612560565b60a085015201612560565b60c0820152613534565b3d9150613ad1565b84513d6000823e3d90fd5b6001600160801b03918216908216019190821161236057565b906000926000926000928151906000925b828410613bb05750505050565b909192949596613c02613bf6613bfc600193613bed878b613bd1818a61233f565b51516020613be16002938c61233f565b510151820b910b612aa3565b94919092613b79565b9b613b79565b98613b79565b9501929190613ba3565b6040808051613c1a81611d90565b369037805190613c2982611d90565b600b546001600160a01b0390600090821680613cb15750506020602491475b8552600c54168351928380926370a0823160e01b82523060048301525afa918215611c9f5750600091613c7f575b50602082015290565b90506020813d602011613ca9575b81613c9a60209383611dfd565b81010312610297575138613c76565b3d9150613c8d565b60206024918551928380926370a0823160e01b82523060048301525afa918215611d43578092613ce9575b5050602491602091613c48565b9091506020823d602011613d17575b81613d0560209383611dfd565b81010312611d39575051816020613cdc565b3d9150613cf8565b90613d28613c0c565b928351926020809501519160039360035492613d50613d4885848a612e37565b948387612e37565b9581519260009160005b858110613e235750505050505050613d929291613d8c611c0e92611c0e613d7f613c0c565b9789895199015198612353565b94612353565b7f000000000000000000000000000000000000000000000000000000000000000060ff16613dfa57600c54600b54604051611c1395613df494919391926001600160a01b039081169216613de585611dab565b845283015260408201526146e7565b506125b2565b90611c1392613df49160018060a01b039182600b541692600c54169060405193613de585611dab565b8b613e4e88613e32848961233f565b5151600293613e41868b61233f565b510151840b90840b612aa3565b505083546001600160801b039291613e6a919087908516612e37565b91808311613e9e578e8493613e98938c93613e876001988d61233f565b5151820b921692613ab1878d61233f565b01613d5a565b634e487b7160e01b87526001600452602487fd5b6001600160a01b03808216968185169493919287868a0361400d575b505084156127be5760009085825260016020526040948583205490898210613fdc5750908885928885526001602052038684205588600354036003558287600080516020614caf833981519152602089518d8152a31680613fa057508080878015613f96575b82809291819288881690f115613f8b57509160a09593917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9795935b825196875216602086015284015260608301526080820152a1565b8351903d90823e3d90fd5b6108fc9150613f34565b60a0979593915091613fd787827ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9b99979561428f565b613f70565b865163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101899052606490fd5b614017918661264f565b3887613ece565b519081600f0b820361029757565b92919061403a828286612aa3565b50909490506001600160801b0385161561427f57906140fe929160018060a01b03835116916000602085019360018060a01b038551166040519160026020840152604083015260608201526101a460808201528260020b60a08201528360020b60c08201528160e08201528161010082015260018060801b03610120820152816101408201528161016082015261016081526140d581611de1565b6040518097819263a15112f960e01b8352608060048401526040602484015260448301906119f1565b0381837f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a741066001600160a01b03165af1938415611177576141e295600095614265575b5051925160408051600560208201526001600160a01b0395861691810191909152931660608401526101a46080840152600290810b60a08401520b60c082015260e0810182905261010081018290526001600160801b03610120820152610140810182905261016080820183905281526141b981611de1565b6040518093819263a15112f960e01b8352608060048401526040602484015260448301906119f1565b0381837f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a741066001600160a01b03165af19081156111775760009161424a575b5060408180518101031261029757614246604061423f6020840161401e565b920161401e565b9091565b61425f91503d806000833e6134908183611dfd565b38614220565b614278903d8088833e6134908183611dfd565b5038614140565b5050509050600090600090600090565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815260808101916001600160401b0383118284101761136d576121c692604052614a53565b60ff60129116019060ff821161236057565b9195949060020b8660020b81136146d5578360020b136146bb5780516000966001600160a01b0393918416806146445750602096975083876012945b0151166040519788809263313ce56760e01b825260049a8b915afa9081156111775760009161460a575b5084600b54169460a081600c54169660648b6040519485938492638e56c1c160e01b845283015260249a8b8301526101a460448301527f00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf165afa908115611177576000916145eb575b50516001600160801b03908116906143ef6143e66143dd848061257f565b610e008661256e565b60801c98612ebe565b916143f98761256e565b9282841693840361029757610800600160801b0393614429918591614422918591600190614ad9565b1695612ebe565b906144338561256e565b92831692830361029757600061444893614ad9565b169260009060ff166144d15750509061446091612d8a565b91670de0b6b3a764000095868602958087048814901517156144be575050916144af6144b49285611be161449f61449a6144ba99986142de565b61256e565b6144a9868561257f565b906125b2565b61257f565b90612353565b0490565b601190634e487b7160e01b600052526000fd5b9394989792916144e96144ef929888611be18961256e565b92612d8a565b60ff85168060120160ff81116145d95761450b6145119161256e565b8461257f565b9061452761452161449a8b6142de565b8961257f565b9060ff8a160160ff81116145c7576145509392916144a961454a611be19361256e565b8561257f565b670de0b6b3a764000096878302928084048914901517156145b557916144b461457f92610e006145859561256e565b9361256e565b938581029581870414901517156145a3575050611c13939450612e37565b634e487b7160e01b8252601190528590fd5b634e487b7160e01b8552601184528985fd5b634e487b7160e01b8752601186528b87fd5b634e487b7160e01b8652601185528a86fd5b614604915060a03d60a011611170576111608183611dfd565b386143bf565b906020823d60201161463c575b8161462460209383611dfd565b81010312611d39575061463690612560565b38614356565b3d9150614617565b60206004916040519283809263313ce56760e01b82525afa988915612c96578099614678575b50508360208098999461432c565b9098506020893d6020116146b3575b8161469460209383611dfd565b81010312611d3957508360206146ab81999a612560565b99985061466a565b3d9150614687565b50611c1393945060ff91506146cf90612ead565b1661257f565b5050611c1393945060ff91501661257f565b9060408083018051156149dc578351602080860180519194926001600160a01b0392831691908316828110156149d45760015b614722613c0c565b93858b511686600b5416146000146149c85788855195015194975b516001600160801b038082169190818303610297578b9385156149bd57896f0ffff5433e2b3d8211706e6102aa9471915b818d51991680978a0152168b8801526101a4938460608901528615158060808a015260a089015260c0880152600060e0880152166101008601526000610120860152610140600081870152855261016092838601948686106001600160401b0387111761136d5760009386938492838e528694816149b4575b506149ac575b5063a15112f960e01b825260016101648901528b6101848901528761481861015f19928201826119f1565b0301918a7f000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a74106165af180156149a15790869493929161497b575b5050505116856000918015600014614902575050506148709047612353565b9551600091168061488a57505050611c1391504790612353565b90846024928451938480926370a0823160e01b82523060048301525afa9283156148f8575080926148c3575b5050611c13925090612353565b9150919282813d83116148f1575b6148db8183611dfd565b81010312611d39575090611c13915138806148b6565b503d6148d1565b51903d90823e3d90fd5b85516370a0823160e01b81523060048201529190829060249082905afa91821561497057809261493e575b50509061493991612353565b614870565b9091508682813d8311614969575b6149568183611dfd565b81010312611d395750516149393861492d565b503d61494c565b8551903d90823e3d90fd5b614998923d90816000853e6149908285611dfd565b010190613303565b50388080614851565b87513d6000823e3d90fd5b9250386147ed565b905015386147e7565b89620100029161476e565b8451948901519761473d565b91600061471a565b50509050600090600090565b9080601f8301121561029757815190602091614a03816121e8565b93614a116040519586611dfd565b81855260208086019260051b82010192831161029757602001905b828210614a3a575050505090565b81518060020b8103610297578152908301908301614a2c565b60018060a01b031690614a7d600080836020829551910182875af1614a76612434565b9084614c4b565b908151918215159283614aad575b505050614a955750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312614ad5576020015190811591821503611d395750388080614a8b565b5080fd5b9190614afd57916001614af7614af1611c1395614c29565b92614c29565b92614ad9565b6001600160801b039283918291908183168184161115614b485703165b1690811561259c5760401b600160401b600160c01b031604908116906001600160c01b031681036102975790565b900316614b1a565b9092916001600160801b039182821615614c105760018060a01b039485602081875116960151166040519560026020880152604087015260608601526101a4608086015260020b60a085015260020b60c0840152610800600160801b031660e08301526134496000938385949385610100819601526101208201528361014082015261016084818301528152614be581611de1565b60405194858094819363a15112f960e01b8352608060048401526040602484015260448301906119f1565b5050505050565b9060020b90811561259c5760020b0790565b6001600160801b03908116801561259c57600160801b04818111610297571690565b90614c725750805115614c6057805190602001fd5b60405163d6bda27560e01b8152600490fd5b81511580614ca5575b614c83575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15614c7b56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c6343000817000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000005dc0000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000002710000000000000000000000000000000000000000000000000000000000000251c0000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a40000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a7410600000000000000000000000068b9e8b700f19b879b90e8485a00dd7a3044a214000000000000000000000000000000000000000000000000000000000000002154454d504553542053594d204554482d55534443204c502045544820417373657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001854454d504553545f53594d5f4554485f555344435f4554480000000000000000
-----Decoded View---------------
Arg [0] : _baseWidth (int24): 1500
Arg [1] : _limitWidth (int24): 5000
Arg [2] : sParams (tuple):
Arg [1] : name (string): TEMPEST SYM ETH-USDC LP ETH Asset
Arg [2] : symbol (string): TEMPEST_SYM_ETH_USDC_ETH
Arg [3] : assetIdx (uint8): 0
Arg [4] : fee (uint16): 1000
Arg [5] : investedPercentage (uint16): 10000
Arg [6] : swapSlippage (uint16): 9500
Arg [7] : feeRecipient (address): 0x9aC6Cd80f41bDfd22F1133E14539549a93ef528A
Arg [8] : token0 (address): 0x0000000000000000000000000000000000000000
Arg [9] : token1 (address): 0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4
Arg [10] : governor (address): 0x9aC6Cd80f41bDfd22F1133E14539549a93ef528A
Arg [11] : cQuery (address): 0x62223e90605845Cf5CC6DAE6E0de4CDA130d6DDf
Arg [12] : cSwapDex (address): 0xaaaaAAAACB71BF2C8CaE522EA5fa455571A74106
Arg [13] : oracle (address): 0x68b9e8b700f19B879b90E8485a00DD7A3044A214
-----Encoded View---------------
21 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000005dc
Arg [1] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [7] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [8] : 000000000000000000000000000000000000000000000000000000000000251c
Arg [9] : 0000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 00000000000000000000000006efdbff2a14a7c8e15944d1f4a48f9f95f663a4
Arg [12] : 0000000000000000000000009ac6cd80f41bdfd22f1133e14539549a93ef528a
Arg [13] : 00000000000000000000000062223e90605845cf5cc6dae6e0de4cda130d6ddf
Arg [14] : 000000000000000000000000aaaaaaaacb71bf2c8cae522ea5fa455571a74106
Arg [15] : 00000000000000000000000068b9e8b700f19b879b90e8485a00dd7a3044a214
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000021
Arg [17] : 54454d504553542053594d204554482d55534443204c50204554482041737365
Arg [18] : 7400000000000000000000000000000000000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [20] : 54454d504553545f53594d5f4554485f555344435f4554480000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.