Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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:
YieldClaimerSlipstream
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.30;
import { AbstractBase } from "../base/AbstractBase.sol";
import { PositionState } from "../state/PositionState.sol";
import { Slipstream } from "../base/Slipstream.sol";
import { YieldClaimer } from "./YieldClaimer.sol";
/**
* @title Yield Claimer for Slipstream Liquidity Positions.
* @author Pragma Labs
*/
contract YieldClaimerSlipstream is YieldClaimer, Slipstream {
/* //////////////////////////////////////////////////////////////
CONSTRUCTOR
////////////////////////////////////////////////////////////// */
/**
* @param owner_ The address of the Owner.
* @param arcadiaFactory The contract address of the Arcadia Factory.
* @param positionManager The contract address of the Slipstream Position Manager.
* @param cLFactory The contract address of the Slipstream Factory.
* @param poolImplementation The contract address of the Slipstream Pool Implementation.
* @param rewardToken The contract address of the Reward Token (Aero).
* @param stakedSlipstreamAm The contract address of the Staked Slipstream Asset Module.
* @param stakedSlipstreamWrapper The contract address of the Staked Slipstream Wrapper.
*/
constructor(
address owner_,
address arcadiaFactory,
address positionManager,
address cLFactory,
address poolImplementation,
address rewardToken,
address stakedSlipstreamAm,
address stakedSlipstreamWrapper
)
YieldClaimer(owner_, arcadiaFactory)
Slipstream(
positionManager, cLFactory, poolImplementation, rewardToken, stakedSlipstreamAm, stakedSlipstreamWrapper
)
{ }
/* ///////////////////////////////////////////////////////////////
STAKING LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Stakes a Liquidity Position.
* param balances The balances of the underlying tokens.
* param positionManager The contract address of the Position Manager.
* param position A struct with position and pool related variables.
*/
function _stake(uint256[] memory, address, PositionState memory) internal override(AbstractBase, Slipstream) { }
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { PositionState } from "../state/PositionState.sol";
/**
* @title Abstract base implementation for managing Liquidity Positions.
*/
abstract contract AbstractBase {
/* //////////////////////////////////////////////////////////////
EVENTS
////////////////////////////////////////////////////////////// */
event FeePaid(address indexed account, address indexed receiver, address indexed asset, uint256 amount);
event YieldClaimed(address indexed account, address indexed asset, uint256 amount);
/* ///////////////////////////////////////////////////////////////
POSITION VALIDATION
/////////////////////////////////////////////////////////////// */
/**
* @notice Returns if a position manager matches the position manager(s) of the protocol.
* @param positionManager The contract address of the position manager to check.
* @return isPositionManager_ Bool indicating if the position manager matches.
*/
function isPositionManager(address positionManager) public view virtual returns (bool isPositionManager_);
/* ///////////////////////////////////////////////////////////////
GETTERS
/////////////////////////////////////////////////////////////// */
/**
* @notice Returns the underlying assets of the pool.
* @param positionManager The contract address of the Position Manager.
* @param id The id of the Liquidity Position.
* @return token0 The contract address of token0.
* @return token1 The contract address of token1.
*/
function _getUnderlyingTokens(address positionManager, uint256 id)
internal
view
virtual
returns (address token0, address token1);
/**
* @notice Returns the position and pool related state.
* @param positionManager The contract address of the Position Manager.
* @param id The id of the Liquidity Position.
* @return position A struct with position and pool related variables.
*/
function _getPositionState(address positionManager, uint256 id)
internal
view
virtual
returns (PositionState memory position);
/**
* @notice Returns the liquidity of the Pool.
* @param position A struct with position and pool related variables.
* @return liquidity The liquidity of the Pool.
*/
function _getPoolLiquidity(PositionState memory position) internal view virtual returns (uint128 liquidity);
/**
* @notice Returns the sqrtPrice of the Pool.
* @param position A struct with position and pool related variables.
* @return sqrtPrice The sqrtPrice of the Pool.
*/
function _getSqrtPrice(PositionState memory position) internal view virtual returns (uint160 sqrtPrice);
/* ///////////////////////////////////////////////////////////////
CLAIM LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Claims fees/rewards from a Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param fees The fees of the underlying tokens to be paid to the initiator.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @dev Must update the balances after the claim.
*/
function _claim(
uint256[] memory balances,
uint256[] memory fees,
address positionManager,
PositionState memory position,
uint256 claimFee
) internal virtual;
/* ///////////////////////////////////////////////////////////////
STAKING LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Stakes a Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
*/
function _stake(uint256[] memory balances, address positionManager, PositionState memory position) internal virtual;
/**
* @notice Unstakes a Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
*/
function _unstake(uint256[] memory balances, address positionManager, PositionState memory position)
internal
virtual;
/* ///////////////////////////////////////////////////////////////
BURN LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Burns the Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @dev Must update the balances after the burn.
*/
function _burn(uint256[] memory balances, address positionManager, PositionState memory position) internal virtual;
/* ///////////////////////////////////////////////////////////////
SWAP LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Swaps one token for another, directly through the pool itself.
* @param balances The balances of the underlying tokens.
* @param position A struct with position and pool related variables.
* @param zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @param amountOut The amount of tokenOut that must be swapped to.
* @dev Must update the balances and sqrtPrice after the swap.
*/
function _swapViaPool(uint256[] memory balances, PositionState memory position, bool zeroToOne, uint256 amountOut)
internal
virtual;
/* ///////////////////////////////////////////////////////////////
MINT LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Mints a new Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param amount0Desired The desired amount of token0 to mint as liquidity.
* @param amount1Desired The desired amount of token1 to mint as liquidity.
* @dev Must update the balances and liquidity and id after the mint.
*/
function _mint(
uint256[] memory balances,
address positionManager,
PositionState memory position,
uint256 amount0Desired,
uint256 amount1Desired
) internal virtual;
/* ///////////////////////////////////////////////////////////////
INCREASE LIQUIDITY LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Swaps one token for another to rebalance the Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param amount0Desired The desired amount of token0 to add as liquidity.
* @param amount1Desired The desired amount of token1 to add as liquidity.
* @dev Must update the balances and delta liquidity after the increase.
*/
function _increaseLiquidity(
uint256[] memory balances,
address positionManager,
PositionState memory position,
uint256 amount0Desired,
uint256 amount1Desired
) internal virtual;
/* ///////////////////////////////////////////////////////////////
ERC721 HANDLER FUNCTION
/////////////////////////////////////////////////////////////// */
/**
* @notice Returns the onERC721Received selector.
* @dev Required to receive ERC721 tokens via safeTransferFrom.
*/
// forge-lint: disable-next-item(mixed-case-function)
function onERC721Received(address, address, uint256, bytes calldata) public pure returns (bytes4) {
return this.onERC721Received.selector;
}
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
// A struct with the position and pool state.
struct PositionState {
// The contract address of the pool.
address pool;
// The id of the position.
uint256 id;
// The fee of the pool
uint24 fee;
// The tick spacing of the pool.
int24 tickSpacing;
// The current tick of the pool.
int24 tickCurrent;
// The lower tick of the position.
int24 tickUpper;
// The upper tick of the position.
int24 tickLower;
// The liquidity of the position.
uint128 liquidity;
// The sqrtPrice of the pool.
uint256 sqrtPrice;
// The underlying tokens of the pool.
address[] tokens;
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { AbstractBase } from "./AbstractBase.sol";
import { ICLPositionManager } from "../interfaces/ICLPositionManager.sol";
import { CLMath } from "../libraries/CLMath.sol";
import { ERC20, SafeTransferLib } from "../../../lib/accounts-v2/lib/solmate/src/utils/SafeTransferLib.sol";
import { FixedPointMathLib } from "../../../lib/accounts-v2/lib/solmate/src/utils/FixedPointMathLib.sol";
import { ICLPool } from "../interfaces/ICLPool.sol";
import { IStakedSlipstream } from "../interfaces/IStakedSlipstream.sol";
import { PositionState } from "../state/PositionState.sol";
import { SlipstreamLogic } from "../libraries/SlipstreamLogic.sol";
import { SafeApprove } from "../../libraries/SafeApprove.sol";
/**
* @title Base implementation for managing Slipstream Liquidity Positions.
*/
abstract contract Slipstream is AbstractBase {
using FixedPointMathLib for uint256;
using SafeApprove for ERC20;
using SafeTransferLib for ERC20;
/* //////////////////////////////////////////////////////////////
CONSTANTS
////////////////////////////////////////////////////////////// */
// The contract address of the Slipstream Factory.
address internal immutable CL_FACTORY;
// The contract address of the Slipstream Position Manager.
ICLPositionManager internal immutable POSITION_MANAGER;
// The contract address of the Slipstream Pool Implementation.
address internal immutable POOL_IMPLEMENTATION;
// The contract address of the Reward Token (Aero).
address internal immutable REWARD_TOKEN;
// The contract address of the Staked Slipstream Asset Module.
address internal immutable STAKED_SLIPSTREAM_AM;
// The contract address of the Staked Slipstream Wrapper.
address internal immutable STAKED_SLIPSTREAM_WRAPPER;
/* //////////////////////////////////////////////////////////////
ERRORS
////////////////////////////////////////////////////////////// */
error OnlyPool();
/* //////////////////////////////////////////////////////////////
CONSTRUCTOR
////////////////////////////////////////////////////////////// */
/**
* @param positionManager The contract address of the Slipstream Position Manager.
* @param cLFactory The contract address of the Slipstream Factory.
* @param poolImplementation The contract address of the Slipstream Pool Implementation.
* @param rewardToken The contract address of the Reward Token (Aero).
* @param stakedSlipstreamAm The contract address of the Staked Slipstream Asset Module.
* @param stakedSlipstreamWrapper The contract address of the Staked Slipstream Wrapper.
*/
constructor(
address positionManager,
address cLFactory,
address poolImplementation,
address rewardToken,
address stakedSlipstreamAm,
address stakedSlipstreamWrapper
) {
POSITION_MANAGER = ICLPositionManager(positionManager);
CL_FACTORY = cLFactory;
POOL_IMPLEMENTATION = poolImplementation;
REWARD_TOKEN = rewardToken;
STAKED_SLIPSTREAM_AM = stakedSlipstreamAm;
STAKED_SLIPSTREAM_WRAPPER = stakedSlipstreamWrapper;
}
/* ///////////////////////////////////////////////////////////////
POSITION VALIDATION
/////////////////////////////////////////////////////////////// */
/**
* @notice Returns if a position manager matches the position manager(s) of Slipstream.
* @param positionManager the contract address of the position manager to check.
*/
function isPositionManager(address positionManager) public view virtual override returns (bool) {
return (positionManager == address(STAKED_SLIPSTREAM_AM)
|| positionManager == address(STAKED_SLIPSTREAM_WRAPPER)
|| positionManager == address(POSITION_MANAGER));
}
/* ///////////////////////////////////////////////////////////////
GETTERS
/////////////////////////////////////////////////////////////// */
/**
* @notice Returns the underlying assets of the pool.
* param positionManager The contract address of the Position Manager.
* @param id The id of the Liquidity Position.
* @return token0 The contract address of token0.
* @return token1 The contract address of token1.
*/
function _getUnderlyingTokens(address, uint256 id)
internal
view
virtual
override
returns (address token0, address token1)
{
(,, token0, token1,,,,,,,,) = POSITION_MANAGER.positions(id);
}
/**
* @notice Returns the position and pool related state.
* @param positionManager The contract address of the Position Manager.
* @param id The id of the Liquidity Position.
* @return position A struct with position and pool related variables.
*/
function _getPositionState(address positionManager, uint256 id)
internal
view
virtual
override
returns (PositionState memory position)
{
// Get data of the Liquidity Position.
position.id = id;
address token0;
address token1;
(,, token0, token1, position.tickSpacing, position.tickLower, position.tickUpper, position.liquidity,,,,) =
POSITION_MANAGER.positions(id);
// If it is a non staked position, or the position is staked and the reward token is the same as one of the underlying tokens,
// there are two underlying assets, otherwise there are three.
if (positionManager == address(POSITION_MANAGER) || token0 == REWARD_TOKEN || token1 == REWARD_TOKEN) {
// Positions have two underlying tokens.
position.tokens = new address[](2);
} else {
// Positions have three underlying tokens.
position.tokens = new address[](3);
position.tokens[2] = REWARD_TOKEN;
}
position.tokens[0] = token0;
position.tokens[1] = token1;
// Get data of the Liquidity Pool.
position.pool =
SlipstreamLogic.computeAddress(POOL_IMPLEMENTATION, CL_FACTORY, token0, token1, position.tickSpacing);
(position.sqrtPrice, position.tickCurrent,,,,) = ICLPool(position.pool).slot0();
position.fee = ICLPool(position.pool).fee();
}
/**
* @notice Returns the liquidity of the Pool.
* @param position A struct with position and pool related variables.
* @return liquidity The liquidity of the Pool.
*/
function _getPoolLiquidity(PositionState memory position)
internal
view
virtual
override
returns (uint128 liquidity)
{
liquidity = ICLPool(position.pool).liquidity();
}
/**
* @notice Returns the sqrtPrice of the Pool.
* @param position A struct with position and pool related variables.
* @return sqrtPrice The sqrtPrice of the Pool.
*/
function _getSqrtPrice(PositionState memory position) internal view virtual override returns (uint160 sqrtPrice) {
(sqrtPrice,,,,,) = ICLPool(position.pool).slot0();
}
/* ///////////////////////////////////////////////////////////////
CLAIM LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Claims fees/rewards from a Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param fees The fees of the underlying tokens to be paid to the initiator.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param claimFee The fee charged on the claimed fees of the liquidity position, with 18 decimals precision.
*/
function _claim(
uint256[] memory balances,
uint256[] memory fees,
address positionManager,
PositionState memory position,
uint256 claimFee
) internal virtual override {
if (positionManager != address(POSITION_MANAGER)) {
// If position is a staked slipstream position, claim the rewards.
uint256 rewards = IStakedSlipstream(positionManager).claimReward(position.id);
uint256 fee = rewards.mulDivDown(claimFee, 1e18);
if (balances.length == 3) {
(balances[2], fees[2]) = (balances[2] + rewards, fees[2] + fee);
emit YieldClaimed(msg.sender, position.tokens[2], rewards);
}
// If rewardToken is an underlying token of the position, add it to the balances.
else if (position.tokens[0] == REWARD_TOKEN) {
(balances[0], fees[0]) = (balances[0] + rewards, fees[0] + fee);
emit YieldClaimed(msg.sender, position.tokens[0], rewards);
} else {
(balances[1], fees[1]) = (balances[1] + rewards, fees[1] + fee);
emit YieldClaimed(msg.sender, position.tokens[1], rewards);
}
} else {
// We assume that the amount of tokens to collect never exceeds type(uint128).max.
(uint256 amount0, uint256 amount1) = POSITION_MANAGER.collect(
ICLPositionManager.CollectParams({
tokenId: position.id,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
balances[0] += amount0;
balances[1] += amount1;
// Calculate claim fees.
fees[0] += amount0.mulDivDown(claimFee, 1e18);
fees[1] += amount1.mulDivDown(claimFee, 1e18);
emit YieldClaimed(msg.sender, position.tokens[0], amount0);
emit YieldClaimed(msg.sender, position.tokens[1], amount1);
}
}
/* ///////////////////////////////////////////////////////////////
STAKING LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Stakes a Liquidity Position.
* param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
*/
function _stake(uint256[] memory, address positionManager, PositionState memory position)
internal
virtual
override
{
// If position is a staked slipstream position, stake the position.
if (positionManager != address(POSITION_MANAGER)) {
POSITION_MANAGER.approve(positionManager, position.id);
IStakedSlipstream(positionManager).mint(position.id);
}
}
/**
* @notice Unstakes a Liquidity Position.
* @param balances The balances of the underlying tokens.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @dev Does not emit YieldClaimed event, if necessary first call _claim() to emit the event before unstaking.
*/
function _unstake(uint256[] memory balances, address positionManager, PositionState memory position)
internal
virtual
override
{
// If position is a staked slipstream position, unstake the position.
if (positionManager != address(POSITION_MANAGER)) {
uint256 rewards = IStakedSlipstream(positionManager).burn(position.id);
if (rewards > 0) {
if (balances.length == 3) balances[2] = rewards;
// If rewardToken is an underlying token of the position, add it to the balances.
else if (position.tokens[0] == REWARD_TOKEN) balances[0] += rewards;
else balances[1] += rewards;
}
}
}
/* ///////////////////////////////////////////////////////////////
BURN LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Burns the Liquidity Position.
* @param balances The balances of the underlying tokens.
* param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @dev Does not emit YieldClaimed event, if necessary first call _claim() to emit the event before unstaking.
*/
function _burn(uint256[] memory balances, address, PositionState memory position) internal virtual override {
// Remove liquidity of the position and claim outstanding fees.
POSITION_MANAGER.decreaseLiquidity(
ICLPositionManager.DecreaseLiquidityParams({
tokenId: position.id,
liquidity: position.liquidity,
amount0Min: 0,
amount1Min: 0,
deadline: block.timestamp
})
);
// We assume that the amount of tokens to collect never exceeds type(uint128).max.
(uint256 amount0, uint256 amount1) = POSITION_MANAGER.collect(
ICLPositionManager.CollectParams({
tokenId: position.id,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
balances[0] += amount0;
balances[1] += amount1;
// Burn the position.
POSITION_MANAGER.burn(position.id);
}
/* ///////////////////////////////////////////////////////////////
SWAP LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Swaps one token for another, directly through the pool itself.
* @param balances The balances of the underlying tokens.
* @param position A struct with position and pool related variables.
* @param zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @param amountOut The amount of tokenOut that must be swapped to.
*/
// forge-lint: disable-next-item(unsafe-typecast)
function _swapViaPool(uint256[] memory balances, PositionState memory position, bool zeroToOne, uint256 amountOut)
internal
virtual
override
{
// Do the swap.
(int256 deltaAmount0, int256 deltaAmount1) = ICLPool(position.pool)
.swap(
address(this),
zeroToOne,
-int256(amountOut),
zeroToOne ? CLMath.MIN_SQRT_PRICE_LIMIT : CLMath.MAX_SQRT_PRICE_LIMIT,
abi.encode(position.tokens[0], position.tokens[1], position.tickSpacing)
);
// Update the balances.
balances[0] = zeroToOne ? balances[0] - uint256(deltaAmount0) : balances[0] + uint256(-deltaAmount0);
balances[1] = zeroToOne ? balances[1] + uint256(-deltaAmount1) : balances[1] - uint256(deltaAmount1);
}
/**
* @notice Callback after executing a swap via ICLPool.swap.
* @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
* the end of the swap. If positive, the callback must send that amount of token0 to the position.
* @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
* the end of the swap. If positive, the callback must send that amount of token1 to the position.
* @param data Any data passed by this contract via the ICLPool.swap() call.
*/
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external virtual {
// Check that callback came from an actual Slipstream Pool.
(address token0, address token1, int24 tickSpacing) = abi.decode(data, (address, address, int24));
if (SlipstreamLogic.computeAddress(POOL_IMPLEMENTATION, CL_FACTORY, token0, token1, tickSpacing) != msg.sender)
{
revert OnlyPool();
}
// forge-lint: disable-next-item(unsafe-typecast)
if (amount0Delta > 0) {
ERC20(token0).safeTransfer(msg.sender, uint256(amount0Delta));
} else if (amount1Delta > 0) {
ERC20(token1).safeTransfer(msg.sender, uint256(amount1Delta));
}
}
/* ///////////////////////////////////////////////////////////////
MINT LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Mints a new Liquidity Position.
* @param balances The balances of the underlying tokens.
* param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param amount0Desired The desired amount of token0 to mint as liquidity.
* @param amount1Desired The desired amount of token1 to mint as liquidity.
*/
function _mint(
uint256[] memory balances,
address,
PositionState memory position,
uint256 amount0Desired,
uint256 amount1Desired
) internal virtual override {
ERC20(position.tokens[0]).safeApproveWithRetry(address(POSITION_MANAGER), amount0Desired);
ERC20(position.tokens[1]).safeApproveWithRetry(address(POSITION_MANAGER), amount1Desired);
uint256 amount0;
uint256 amount1;
(position.id, position.liquidity, amount0, amount1) = POSITION_MANAGER.mint(
ICLPositionManager.MintParams({
token0: position.tokens[0],
token1: position.tokens[1],
tickSpacing: position.tickSpacing,
tickLower: position.tickLower,
tickUpper: position.tickUpper,
amount0Desired: amount0Desired,
amount1Desired: amount1Desired,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp,
sqrtPrice: 0
})
);
balances[0] -= amount0;
balances[1] -= amount1;
}
/* ///////////////////////////////////////////////////////////////
INCREASE LIQUIDITY LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Swaps one token for another to rebalance the Liquidity Position.
* @param balances The balances of the underlying tokens.
* param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param amount0Desired The desired amount of token0 to add as liquidity.
* @param amount1Desired The desired amount of token1 to add as liquidity.
*/
function _increaseLiquidity(
uint256[] memory balances,
address,
PositionState memory position,
uint256 amount0Desired,
uint256 amount1Desired
) internal virtual override {
ERC20(position.tokens[0]).safeApproveWithRetry(address(POSITION_MANAGER), amount0Desired);
ERC20(position.tokens[1]).safeApproveWithRetry(address(POSITION_MANAGER), amount1Desired);
uint256 amount0;
uint256 amount1;
(position.liquidity, amount0, amount1) = POSITION_MANAGER.increaseLiquidity(
ICLPositionManager.IncreaseLiquidityParams({
tokenId: position.id,
amount0Desired: amount0Desired,
amount1Desired: amount1Desired,
amount0Min: 0,
amount1Min: 0,
deadline: block.timestamp
})
);
balances[0] -= amount0;
balances[1] -= amount1;
}
/* ///////////////////////////////////////////////////////////////
NATIVE ETH HANDLER
/////////////////////////////////////////////////////////////// */
/**
* @notice Receives native ether.
*/
receive() external payable { }
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { AbstractBase } from "../base/AbstractBase.sol";
import { ActionData, IActionBase } from "../../../lib/accounts-v2/src/interfaces/IActionBase.sol";
import { ArcadiaLogic } from "../libraries/ArcadiaLogic.sol";
import { ERC20, SafeTransferLib } from "../../../lib/accounts-v2/lib/solmate/src/utils/SafeTransferLib.sol";
import { ERC721 } from "../../../lib/accounts-v2/lib/solmate/src/tokens/ERC721.sol";
import { Guardian } from "../../guardian/Guardian.sol";
import { IAccount } from "../../interfaces/IAccount.sol";
import { IArcadiaFactory } from "../../interfaces/IArcadiaFactory.sol";
import { PositionState } from "../state/PositionState.sol";
import { SafeApprove } from "../../libraries/SafeApprove.sol";
/**
* @title Abstract Yield Claimer for concentrated Liquidity Positions.
* @author Pragma Labs
*/
abstract contract YieldClaimer is IActionBase, AbstractBase, Guardian {
using SafeApprove for ERC20;
using SafeTransferLib for ERC20;
/* //////////////////////////////////////////////////////////////
CONSTANTS
////////////////////////////////////////////////////////////// */
// The contract address of the Arcadia Factory.
IArcadiaFactory public immutable ARCADIA_FACTORY;
/* //////////////////////////////////////////////////////////////
STORAGE
////////////////////////////////////////////////////////////// */
// The Account to rebalance the fees for, used as transient storage.
address internal account;
// A mapping from account to account specific information.
mapping(address account => AccountInfo) public accountInfo;
// A mapping from account to custom metadata.
mapping(address account => bytes data) public metaData;
// A mapping that sets the approved initiator per owner per account.
mapping(address accountOwner => mapping(address account => address initiator)) public accountToInitiator;
// A struct with the account specific parameters.
struct AccountInfo {
// The address of the recipient of the claimed fees.
address feeRecipient;
// The maximum fee charged on the claimed fees of the liquidity position, with 18 decimals precision.
uint64 maxClaimFee;
}
// A struct with the initiator parameters.
struct InitiatorParams {
// The contract address of the position manager.
address positionManager;
// The id of the position.
uint96 id;
// The fee charged on the claimed fees of the liquidity position, with 18 decimals precision.
uint64 claimFee;
}
/* //////////////////////////////////////////////////////////////
ERRORS
////////////////////////////////////////////////////////////// */
error InvalidInitiator();
error InvalidAccountVersion();
error InvalidPositionManager();
error InvalidRecipient();
error InvalidValue();
error NotAnAccount();
error OnlyAccount();
error OnlyAccountOwner();
error Reentered();
/* //////////////////////////////////////////////////////////////
EVENTS
////////////////////////////////////////////////////////////// */
event AccountInfoSet(address indexed account, address indexed initiator);
event Claimed(address indexed account, address indexed positionManager, uint256 id);
event YieldTransferred(address indexed account, address indexed receiver, address indexed asset, uint256 amount);
/* //////////////////////////////////////////////////////////////
CONSTRUCTOR
////////////////////////////////////////////////////////////// */
/**
* @param owner_ The address of the Owner.
* @param arcadiaFactory The contract address of the Arcadia Factory.
*/
constructor(address owner_, address arcadiaFactory) Guardian(owner_) {
ARCADIA_FACTORY = IArcadiaFactory(arcadiaFactory);
}
/* ///////////////////////////////////////////////////////////////
ACCOUNT LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Optional hook called by the Arcadia Account when calling "setAssetManager()".
* @param accountOwner The current owner of the Arcadia Account.
* param status Bool indicating if the Asset Manager is enabled or disabled.
* @param data Operator specific data, passed by the Account owner.
* @dev No need to check that the Account version is 3 or greater (versions with cross account reentrancy guard),
* since version 1 and 2 don't support the onSetAssetManager hook.
*/
function onSetAssetManager(address accountOwner, bool, bytes calldata data) external {
if (account != address(0)) revert Reentered();
if (!ARCADIA_FACTORY.isAccount(msg.sender)) revert NotAnAccount();
(address initiator, address feeRecipient, uint256 maxClaimFee, bytes memory metaData_) =
abi.decode(data, (address, address, uint256, bytes));
_setAccountInfo(msg.sender, accountOwner, initiator, feeRecipient, maxClaimFee, metaData_);
}
/**
* @notice Sets the required information for an Account.
* @param account_ The contract address of the Arcadia Account to set the information for.
* @param initiator The address of the initiator.
* @param feeRecipient The address of the recipient of the claimed fees.
* @param maxClaimFee The maximum fee charged on the claimed fees of the liquidity position, with 18 decimals precision.
* @param metaData_ Custom metadata to be stored with the account.
*/
function setAccountInfo(
address account_,
address initiator,
address feeRecipient,
uint256 maxClaimFee,
bytes calldata metaData_
) external {
if (account != address(0)) revert Reentered();
if (!ARCADIA_FACTORY.isAccount(account_)) revert NotAnAccount();
address accountOwner = IAccount(account_).owner();
if (msg.sender != accountOwner) revert OnlyAccountOwner();
// Block Account versions without cross account reentrancy guard.
if (IAccount(account_).ACCOUNT_VERSION() < 3) revert InvalidAccountVersion();
_setAccountInfo(account_, accountOwner, initiator, feeRecipient, maxClaimFee, metaData_);
}
/**
* @notice Sets the required information for an Account.
* @param account_ The contract address of the Arcadia Account to set the information for.
* @param accountOwner The current owner of the Arcadia Account.
* @param initiator The address of the initiator.
* @param feeRecipient The address of the recipient of the claimed fees.
* @param maxClaimFee The maximum fee charged on the claimed fees of the liquidity position, with 18 decimals precision.
* @param metaData_ Custom metadata to be stored with the account.
*/
function _setAccountInfo(
address account_,
address accountOwner,
address initiator,
address feeRecipient,
uint256 maxClaimFee,
bytes memory metaData_
) internal {
if (feeRecipient == address(0)) revert InvalidRecipient();
if (maxClaimFee > 1e18) revert InvalidValue();
accountToInitiator[accountOwner][account_] = initiator;
// unsafe cast: maxClaimFee <= 1e18 < type(uint64).max.
// forge-lint: disable-next-line(unsafe-typecast)
accountInfo[account_] = AccountInfo({ feeRecipient: feeRecipient, maxClaimFee: uint64(maxClaimFee) });
metaData[account_] = metaData_;
emit AccountInfoSet(account_, initiator);
}
/* ///////////////////////////////////////////////////////////////
CLAIMING LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Claims accrued fees/rewards from a Liquidity Position, owned by an Arcadia Account.
* @param account_ The contract address of the account.
* @param initiatorParams A struct with the initiator parameters.
*/
function claim(address account_, InitiatorParams calldata initiatorParams) external whenNotPaused {
// Store Account address, used to validate the caller of the executeAction() callback and serves as a reentrancy guard.
if (account != address(0)) revert Reentered();
account = account_;
// If the initiator is set, account_ is an actual Arcadia Account.
if (accountToInitiator[IAccount(account_).owner()][account_] != msg.sender) revert InvalidInitiator();
if (!isPositionManager(initiatorParams.positionManager)) revert InvalidPositionManager();
// Encode data for the flash-action.
bytes memory actionData = ArcadiaLogic._encodeAction(
initiatorParams.positionManager,
initiatorParams.id,
address(0),
address(0),
0,
0,
abi.encode(msg.sender, initiatorParams)
);
// Call flashAction() with this contract as actionTarget.
IAccount(account_).flashAction(address(this), actionData);
// Reset account.
account = address(0);
}
/**
* @notice Callback function called by the Arcadia Account during the flashAction.
* @param actionTargetData A bytes object containing the initiator and initiatorParams.
* @return depositData A struct with the asset data of the Liquidity Position and with the leftovers after mint, if any.
* @dev The Liquidity Position is already transferred to this contract before executeAction() is called.
* @dev When rebalancing we will burn the current Liquidity Position and mint a new one with a new tokenId.
*/
function executeAction(bytes calldata actionTargetData) external override returns (ActionData memory depositData) {
// Caller should be the Account, provided as input in rebalance().
if (msg.sender != account) revert OnlyAccount();
// Cache accountInfo.
AccountInfo memory accountInfo_ = accountInfo[msg.sender];
// Decode actionTargetData.
(address initiator, InitiatorParams memory initiatorParams) =
abi.decode(actionTargetData, (address, InitiatorParams));
address positionManager = initiatorParams.positionManager;
// Validate initiatorParams.
if (initiatorParams.claimFee > accountInfo_.maxClaimFee) revert InvalidValue();
// Get all pool and position related state.
PositionState memory position = _getPositionState(positionManager, initiatorParams.id);
uint256[] memory balances = new uint256[](position.tokens.length);
uint256[] memory fees = new uint256[](balances.length);
// Claim pending yields and update balances.
_claim(balances, fees, positionManager, position, initiatorParams.claimFee);
// If native eth was claimed, wrap it.
_stake(balances, positionManager, position);
// Approve the liquidity position handle the claimed yields and transfer the initiator fees to the initiator.
uint256 count =
_approveAndTransfer(initiator, balances, fees, positionManager, position, accountInfo_.feeRecipient);
// Encode deposit data for the flash-action.
depositData = ArcadiaLogic._encodeDeposit(positionManager, position.id, position.tokens, balances, count);
emit Claimed(msg.sender, positionManager, position.id);
}
/* ///////////////////////////////////////////////////////////////
APPROVE AND TRANSFER LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Approves the liquidity position and handles the claimed yields.
* @param initiator The address of the initiator.
* @param balances The balances of the underlying tokens held by the YieldClaimer.
* @param fees The fees of the underlying tokens to be paid to the initiator.
* @param positionManager The contract address of the Position Manager.
* @param position A struct with position and pool related variables.
* @param recipient The address to which the collected fees will be sent.
* @return count The number of assets approved.
*/
function _approveAndTransfer(
address initiator,
uint256[] memory balances,
uint256[] memory fees,
address positionManager,
PositionState memory position,
address recipient
) internal returns (uint256 count) {
// Approve the Liquidity Position.
ERC721(positionManager).approve(msg.sender, position.id);
// Transfer Initiator fees and handle the claimed yields.
count = 1;
address token;
uint256 amount;
for (uint256 i; i < balances.length; i++) {
token = position.tokens[i];
// Handle the claimed yields.
if (balances[i] > fees[i]) {
amount = balances[i] - fees[i];
if (recipient == msg.sender) {
// If feeRecipient is the Account itself, deposit yield back into the Account.
balances[i] = amount;
ERC20(token).safeApproveWithRetry(msg.sender, amount);
count++;
} else {
// Else, send the yield to the fee recipient.
ERC20(token).safeTransfer(recipient, amount);
balances[i] = 0;
}
} else {
amount = 0;
fees[i] = balances[i];
balances[i] = 0;
}
// Transfer Initiator fees to the initiator.
if (fees[i] > 0) ERC20(token).safeTransfer(initiator, fees[i]);
emit FeePaid(msg.sender, initiator, token, fees[i]);
if (recipient != msg.sender) emit YieldTransferred(msg.sender, recipient, token, amount);
}
}
/* ///////////////////////////////////////////////////////////////
SKIM LOGIC
/////////////////////////////////////////////////////////////// */
/**
* @notice Recovers any native or ERC20 tokens left on the contract.
* @param token The contract address of the token, or address(0) for native tokens.
*/
function skim(address token) external onlyOwner whenNotPaused {
if (account != address(0)) revert Reentered();
if (token == address(0)) {
(bool success, bytes memory result) = payable(msg.sender).call{ value: address(this).balance }("");
require(success, string(result));
} else {
ERC20(token).safeTransfer(msg.sender, ERC20(token).balanceOf(address(this)));
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
interface ICLPositionManager {
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct MintParams {
address token0;
address token1;
int24 tickSpacing;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
uint160 sqrtPrice;
}
function approve(address spender, uint256 tokenId) external;
function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);
function burn(uint256 tokenId) external payable;
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
function increaseLiquidity(IncreaseLiquidityParams calldata params)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
int24 tickSpacing,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function mint(MintParams calldata params)
external
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { FixedPoint96 } from "../../../lib/accounts-v2/lib/v4-periphery/lib/v4-core/src/libraries/FixedPoint96.sol";
import { FixedPointMathLib } from "../../../lib/accounts-v2/lib/solmate/src/utils/FixedPointMathLib.sol";
import { FullMath } from "../../../lib/accounts-v2/lib/v4-periphery/lib/v4-core/src/libraries/FullMath.sol";
import { TickMath } from "../../../lib/accounts-v2/lib/v4-periphery/lib/v4-core/src/libraries/TickMath.sol";
library CLMath {
using FixedPointMathLib for uint256;
/* //////////////////////////////////////////////////////////////
CONSTANTS
////////////////////////////////////////////////////////////// */
// The minimum sqrtPriceLimit for a swap.
uint160 internal constant MIN_SQRT_PRICE_LIMIT = TickMath.MIN_SQRT_PRICE + 1;
// The maximum sqrtPriceLimit for a swap.
uint160 internal constant MAX_SQRT_PRICE_LIMIT = TickMath.MAX_SQRT_PRICE - 1;
// The binary precision of sqrtPrice squared.
uint256 internal constant Q192 = FixedPoint96.Q96 ** 2;
/* //////////////////////////////////////////////////////////////
MATHS
////////////////////////////////////////////////////////////// */
/**
* @notice Calculates the swap parameters, calculated based on a hypothetical swap (in the pool itself with fees but without slippage).
* that maximizes the amount of liquidity that can be added to the positions (no leftovers of either token0 or token1).
* @param sqrtPrice The square root of the price (token1/token0), with 96 binary precision.
* @param sqrtRatioLower The square root price of the lower tick of the liquidity position, with 96 binary precision.
* @param sqrtRatioUpper The square root price of the upper tick of the liquidity position, with 96 binary precision.
* @param balance0 The amount of token0 that is available for the rebalance.
* @param balance1 The amount of token1 that is available for the rebalance.
* @param fee The swapping fees, with 18 decimals precision.
* @return zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @return amountIn An approximation of the amount of tokenIn, based on the optimal swap through the pool itself without slippage.
* @return amountOut An approximation of the amount of tokenOut, based on the optimal swap through the pool itself without slippage.
* @dev The swap parameters are derived as follows:
* 1) First we check if the position is in or out of range.
* - If the current price is above the position, the solution is trivial: we swap the full position to token1.
* - If the current price is below the position, similar, we swap the full position to token0.
* - If the position is in range we proceed with step 2.
*
* 2) If the position is in range, we start with calculating the "Target Ratio" and "Current Ratio".
* Both ratio's are defined as the value of the amount of token1 compared to the total value of the position:
* R = valueToken1 / [valueToken0 + valueToken1]
* If we express all values in token1 and use the current pool price to denominate token0 in token1:
* R = amount1 / [amount0 * sqrtPrice² + amount1]
*
* a) The "Target Ratio" (R_target) is the ratio of the new liquidity position.
* It is calculated with the current price and the upper and lower prices of the liquidity position,
* see _getTargetRatio() for the derivation.
* To maximize the liquidity of the new position, the balances after the swap should approximate it as close as possible to not have any leftovers.
* b) The "Current Ratio" (R_current) is the ratio of the current token balances, it is calculated as follows:
* R_current = balance1 / [balance0 * sqrtPrice² + balance1].
*
* 3) From R_target and R_current we can finally derive the direction of the swap, amountIn and amountOut.
* If R_current is smaller than R_target, we have to swap an amount of token0 to token1, and vice versa.
* amountIn and amountOut can be found by solving the following equalities:
* a) The ratio of the token balances after the swap equal the "Target Ratio".
* b) The swap between token0 and token1 is done in the pool itself,
* taking into account fees, but ignoring slippage (-> sqrtPrice remains constant).
*
* If R_current < R_target (swap token0 to token1):
* a) R_target = [amount1 + amountOut] / [(amount0 - amountIn) * sqrtPrice² + (amount1 + amountOut)].
* b) amountOut = (1 - fee) * amountIn * sqrtPrice².
* => amountOut = [(R_target - R_current) * (amount0 * sqrtPrice² + amount1)] / [1 + R_target * fee / (1 - fee)].
*
* If R_current > R_target (swap token1 to token0):
* a) R_target = [(amount1 - amountIn)] / [(amount0 + amountOut) * sqrtPrice² + (amount1 - amountIn)].
* b) amountOut = (1 - fee) * amountIn / sqrtPrice².
* => amountIn = [(R_current - R_target) * (amount0 * sqrtPrice² + amount1)] / (1 - R_target * fee).
*/
function _getSwapParams(
uint256 sqrtPrice,
uint256 sqrtRatioLower,
uint256 sqrtRatioUpper,
uint256 balance0,
uint256 balance1,
uint256 fee
) internal pure returns (bool zeroToOne, uint256 amountIn, uint256 amountOut) {
if (sqrtPrice >= sqrtRatioUpper) {
// New position is out of range and fully in token 1.
// Rebalance to a single-sided liquidity position in token 1.
zeroToOne = true;
amountIn = balance0;
amountOut = _getAmountOut(sqrtPrice, true, balance0, fee);
} else if (sqrtPrice <= sqrtRatioLower) {
// New position is out of range and fully in token 0.
// Rebalance to a single-sided liquidity position in token 0.
amountIn = balance1;
amountOut = _getAmountOut(sqrtPrice, false, balance1, fee);
} else {
// Get target ratio in token1 terms.
uint256 targetRatio = _getTargetRatio(sqrtPrice, sqrtRatioLower, sqrtRatioUpper);
// Calculate the total position value in token1 equivalent:
uint256 token0ValueInToken1 = _getSpotValue(sqrtPrice, true, balance0);
uint256 totalValueInToken1 = balance1 + token0ValueInToken1;
unchecked {
// Calculate the current ratio of liquidity in token1 terms.
uint256 currentRatio = balance1.mulDivDown(1e18, totalValueInToken1);
if (currentRatio < targetRatio) {
// Swap token0 partially to token1.
zeroToOne = true;
{
uint256 denominator = 1e18 + targetRatio.mulDivDown(fee, 1e18 - fee);
amountOut = (targetRatio - currentRatio).mulDivDown(totalValueInToken1, denominator);
}
amountIn = _getAmountIn(sqrtPrice, true, amountOut, fee);
} else {
// Swap token1 partially to token0.
zeroToOne = false;
{
uint256 denominator = 1e18 - targetRatio.mulDivDown(fee, 1e18);
amountIn = (currentRatio - targetRatio).mulDivDown(totalValueInToken1, denominator);
}
amountOut = _getAmountOut(sqrtPrice, false, amountIn, fee);
}
}
}
}
/**
* @notice Calculates the value of one token in the other token for a given amountIn and sqrtPrice.
* Does not take into account slippage and fees.
* @param sqrtPrice The square root of the price (token1/token0), with 96 binary precision.
* @param zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @param amountIn The amount that of tokenIn that must be swapped to tokenOut.
* @return amountOut The amount of tokenOut.
* @dev Function will revert for all pools where the sqrtPrice is bigger than type(uint128).max.
* type(uint128).max is currently more than enough for all supported pools.
* If ever the sqrtPrice of a pool exceeds type(uint128).max, a different contract has to be deployed,
* which does two consecutive mulDivs.
*/
function _getSpotValue(uint256 sqrtPrice, bool zeroToOne, uint256 amountIn)
internal
pure
returns (uint256 amountOut)
{
amountOut = zeroToOne
? FullMath.mulDiv(amountIn, sqrtPrice ** 2, Q192)
: FullMath.mulDiv(amountIn, Q192, sqrtPrice ** 2);
}
/**
* @notice Calculates the amountOut for a given amountIn and sqrtPrice for a hypothetical
* swap though the pool itself with fees but without slippage.
* @param sqrtPrice The square root of the price (token1/token0), with 96 binary precision.
* @param zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @param amountIn The amount of tokenIn that must be swapped to tokenOut.
* @param fee The total fee on amountIn, with 18 decimals precision.
* @return amountOut The amount of tokenOut.
* @dev Function will revert for all pools where the sqrtPrice is bigger than type(uint128).max.
* type(uint128).max is currently more than enough for all supported pools.
* If ever the sqrtPrice of a pool exceeds type(uint128).max, a different contract has to be deployed,
* which does two consecutive mulDivs.
*/
function _getAmountOut(uint256 sqrtPrice, bool zeroToOne, uint256 amountIn, uint256 fee)
internal
pure
returns (uint256 amountOut)
{
require(sqrtPrice <= type(uint128).max);
unchecked {
uint256 amountInWithoutFees = (1e18 - fee).mulDivDown(amountIn, 1e18);
amountOut = zeroToOne
? FullMath.mulDiv(amountInWithoutFees, sqrtPrice ** 2, Q192)
: FullMath.mulDiv(amountInWithoutFees, Q192, sqrtPrice ** 2);
}
}
/**
* @notice Calculates the amountIn for a given amountOut and sqrtPrice for a hypothetical
* swap though the pool itself with fees but without slippage.
* @param sqrtPrice The square root of the price (token1/token0), with 96 binary precision.
* @param zeroToOne Bool indicating if token0 has to be swapped to token1 or opposite.
* @param amountOut The amount that tokenOut that must be swapped.
* @param fee The total fee on amountIn, with 18 decimals precision.
* @return amountIn The amount of tokenIn.
* @dev Function will revert for all pools where the sqrtPrice is bigger than type(uint128).max.
* type(uint128).max is currently more than enough for all supported pools.
* If ever the sqrtPrice of a pool exceeds type(uint128).max, a different contract has to be deployed,
* which does two consecutive mulDivs.
*/
function _getAmountIn(uint256 sqrtPrice, bool zeroToOne, uint256 amountOut, uint256 fee)
internal
pure
returns (uint256 amountIn)
{
require(sqrtPrice <= type(uint128).max);
unchecked {
uint256 amountInWithoutFees = zeroToOne
? FullMath.mulDiv(amountOut, Q192, sqrtPrice ** 2)
: FullMath.mulDiv(amountOut, sqrtPrice ** 2, Q192);
amountIn = amountInWithoutFees.mulDivDown(1e18, 1e18 - fee);
}
}
/**
* @notice Calculates the ratio of how much of the total value of a liquidity position has to be provided in token1.
* @param sqrtPrice The square root of the current pool price (token1/token0), with 96 binary precision.
* @param sqrtRatioLower The square root price of the lower tick of the liquidity position, with 96 binary precision.
* @param sqrtRatioUpper The square root price of the upper tick of the liquidity position, with 96 binary precision.
* @return targetRatio The ratio of the value of token1 compared to the total value of the position, with 18 decimals precision.
* @dev Function will revert for all pools where the sqrtPrice is bigger than type(uint128).max.
* type(uint128).max is currently more than enough for all supported pools.
* If ever the sqrtPrice of a pool exceeds type(uint128).max, a different contract has to be deployed,
* which does two consecutive mulDivs.
* @dev Derivation of the formula:
* 1) The ratio is defined as:
* R = valueToken1 / [valueToken0 + valueToken1]
* If we express all values in token1 and use the current pool price to denominate token0 in token1:
* R = amount1 / [amount0 * sqrtPrice² + amount1]
* 2) Amount0 for a given liquidity position of a Uniswap V3 pool is given as:
* Amount0 = liquidity * (sqrtRatioUpper - sqrtPrice) / (sqrtRatioUpper * sqrtPrice)
* 3) Amount1 for a given liquidity position of a Uniswap V3 pool is given as:
* Amount1 = liquidity * (sqrtPrice - sqrtRatioLower)
* 4) Combining 1), 2) and 3) and simplifying we get:
* R = [sqrtPrice - sqrtRatioLower] / [2 * sqrtPrice - sqrtRatioLower - sqrtPrice² / sqrtRatioUpper]
*/
function _getTargetRatio(uint256 sqrtPrice, uint256 sqrtRatioLower, uint256 sqrtRatioUpper)
internal
pure
returns (uint256 targetRatio)
{
require(sqrtPrice <= type(uint128).max);
// Unchecked: sqrtPrice is always bigger than sqrtRatioLower.
// Unchecked: sqrtPrice is always smaller than sqrtRatioUpper -> sqrtPrice > sqrtPrice ** 2 / sqrtRatioUpper.
unchecked {
uint256 numerator = sqrtPrice - sqrtRatioLower;
uint256 denominator = 2 * sqrtPrice - sqrtRatioLower - sqrtPrice ** 2 / sqrtRatioUpper;
targetRatio = numerator.mulDivDown(1e18, denominator);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
interface ICLPool {
function fee() external view returns (uint24);
function liquidity() external view returns (uint128 liquidity_);
function slot0()
external
view
returns (
uint160 sqrtPrice,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
bool unlocked
);
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimit,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.0;
interface IStakedSlipstream {
function burn(uint256 id) external returns (uint256 rewards);
function claimReward(uint256 positionId) external returns (uint256 rewards);
function mint(uint256 id) external returns (uint256 id_);
// forge-lint: disable-next-line(mixed-case-function)
function REWARD_TOKEN() external view returns (address rewardToken);
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
library SlipstreamLogic {
/**
* @notice Deterministically computes the pool address.
* @param poolImplementation The contract address of the Slipstream Pool implementation.
* @param factory The contract address of the Slipstream factory.
* @param token0 Contract address of token0.
* @param token1 Contract address of token1.
* @param tickSpacing The tick spacing of the pool.
* @return pool The contract address of the pool.
*/
function computeAddress(
address poolImplementation,
address factory,
address token0,
address token1,
int24 tickSpacing
) internal pure returns (address pool) {
require(token0 < token1);
pool = predictDeterministicAddress({
master: poolImplementation, salt: keccak256(abi.encode(token0, token1, tickSpacing)), deployer: factory
});
}
/**
* @notice Computes the address of a clone deployed.
* @param master The contract address of the master.
* @param salt The salt of the clone.
* @param deployer The deployer of the clone.
* @return predicted The predicted address of the clone.
*/
function predictDeterministicAddress(address master, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
}/**
* https://github.com/Vectorized/solady/blob/main/src/utils/SafeTransferLib.sol
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.0;
import { ERC20 } from "../../lib/accounts-v2/lib/solmate/src/tokens/ERC20.sol";
library SafeApprove {
/**
* @notice Approves an amount of token for a spender.
* @param token The contract address of the token being approved.
* @param to The spender.
* @param amount the amount of token being approved.
* @dev Copied from Solady safeApproveWithRetry (MIT): https://github.com/Vectorized/solady/blob/main/src/utils/SafeTransferLib.sol
* @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
* If the initial attempt to approve fails, attempts to reset the approved amount to zero,
* then retries the approval again (some tokens, e.g. USDT, requires this).
* Reverts upon failure.
*/
function safeApproveWithRetry(ERC20 token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
// Struct with information to pass to and from the actionTarget.
struct ActionData {
// Array of the contract addresses of the assets.
address[] assets;
// Array of the IDs of the assets.
uint256[] assetIds;
// Array with the amounts of the assets.
uint256[] assetAmounts;
// Array with the types of the assets.
uint256[] assetTypes;
}
interface IActionBase {
/**
* @notice Calls an external target contract with arbitrary calldata.
* @param actionTargetData A bytes object containing the encoded input for the actionTarget.
* @return resultData An actionAssetData struct with the final balances of this actionTarget contract.
*/
function executeAction(bytes calldata actionTargetData) external returns (ActionData memory);
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { ActionData } from "../../../lib/accounts-v2/src/interfaces/IActionBase.sol";
import { IPermit2 } from "../../../lib/accounts-v2/src/interfaces/IPermit2.sol";
library ArcadiaLogic {
/**
* @notice Encodes the action data for the flash-action used to manage a Liquidity Position.
* @param positionManager The address of the position manager.
* @param id The id of the Liquidity Position.
* @param token0 The contract address of token0.
* @param token1 The contract address of token1.
* @param amount0 The amount of token0 to transfer.
* @param amount1 The amount of token1 to transfer.
* @param actionTargetData The data to be passed to the action target.
* @return actionData Bytes string with the encoded data.
*/
function _encodeAction(
address positionManager,
uint256 id,
address token0,
address token1,
uint256 amount0,
uint256 amount1,
bytes memory actionTargetData
) internal pure returns (bytes memory actionData) {
// Calculate the number of assets to encode.
uint256 count = 1;
if (amount0 > 0) count++;
if (amount1 > 0) count++;
address[] memory assets = new address[](count);
uint256[] memory ids = new uint256[](count);
uint256[] memory amounts = new uint256[](count);
uint256[] memory types = new uint256[](count);
// Encode liquidity position.
assets[0] = positionManager;
ids[0] = id;
amounts[0] = 1;
types[0] = 2;
// Encode underlying assets of the liquidity position.
uint256 index = 1;
if (amount0 > 0) {
assets[1] = token0;
amounts[1] = amount0;
types[1] = 1;
index = 2;
}
if (amount1 > 0) {
assets[index] = token1;
amounts[index] = amount1;
types[index] = 1;
}
ActionData memory assetData =
ActionData({ assets: assets, assetIds: ids, assetAmounts: amounts, assetTypes: types });
// Empty data objects that have to be encoded when calling flashAction(), but that are not used for this specific flash-action.
bytes memory signature;
ActionData memory transferFromOwner;
IPermit2.PermitBatchTransferFrom memory permit;
// Encode the actionData.
actionData = abi.encode(assetData, transferFromOwner, permit, signature, actionTargetData);
}
/**
* @notice Encodes the deposit data after the flash-action is executed.
* @param positionManager The address of the position manager.
* @param id The id of the Liquidity Position.
* @param tokens The contract addresses of the tokens to deposit.
* @param balances The balances of the tokens to deposit.
* @param count The number of tokens to deposit.
* @return depositData Bytes string with the encoded data.
*/
function _encodeDeposit(
address positionManager,
uint256 id,
address[] memory tokens,
uint256[] memory balances,
uint256 count
) internal pure returns (ActionData memory depositData) {
address[] memory assets = new address[](count);
uint256[] memory ids = new uint256[](count);
uint256[] memory amounts = new uint256[](count);
uint256[] memory types = new uint256[](count);
// Encode liquidity position.
assets[0] = positionManager;
ids[0] = id;
amounts[0] = 1;
types[0] = 2;
// Encode underlying assets of the liquidity position.
if (count > 1) {
uint256 i = 1;
for (uint256 j; j < balances.length; j++) {
if (balances[j] > 0) {
assets[i] = tokens[j];
amounts[i] = balances[j];
types[i] = 1;
i++;
}
}
}
depositData = ActionData({ assets: assets, assetIds: ids, assetAmounts: amounts, assetTypes: types });
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed spender, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE/LOGIC
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
function tokenURI(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC721 BALANCE/OWNER STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) internal _ownerOf;
mapping(address => uint256) internal _balanceOf;
function ownerOf(uint256 id) public view virtual returns (address owner) {
require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
}
function balanceOf(address owner) public view virtual returns (uint256) {
require(owner != address(0), "ZERO_ADDRESS");
return _balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
ERC721 APPROVAL STORAGE
//////////////////////////////////////////////////////////////*/
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
}
/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 id) public virtual {
address owner = _ownerOf[id];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
getApproved[id] = spender;
emit Approval(owner, spender, id);
}
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(
address from,
address to,
uint256 id
) public virtual {
require(from == _ownerOf[id], "WRONG_FROM");
require(to != address(0), "INVALID_RECIPIENT");
require(
msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
"NOT_AUTHORIZED"
);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
unchecked {
_balanceOf[from]--;
_balanceOf[to]++;
}
_ownerOf[id] = to;
delete getApproved[id];
emit Transfer(from, to, id);
}
function safeTransferFrom(
address from,
address to,
uint256 id
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
bytes calldata data
) public virtual {
transferFrom(from, to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(_ownerOf[id] == address(0), "ALREADY_MINTED");
// Counter overflow is incredibly unrealistic.
unchecked {
_balanceOf[to]++;
}
_ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
function _burn(uint256 id) internal virtual {
address owner = _ownerOf[id];
require(owner != address(0), "NOT_MINTED");
// Ownership check above ensures no underflow.
unchecked {
_balanceOf[owner]--;
}
delete _ownerOf[id];
delete getApproved[id];
emit Transfer(owner, address(0), id);
}
/*//////////////////////////////////////////////////////////////
INTERNAL SAFE MINT LOGIC
//////////////////////////////////////////////////////////////*/
function _safeMint(address to, uint256 id) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _safeMint(
address to,
uint256 id,
bytes memory data
) internal virtual {
_mint(to, id);
require(
to.code.length == 0 ||
ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
ERC721TokenReceiver.onERC721Received.selector,
"UNSAFE_RECIPIENT"
);
}
}
/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC721TokenReceiver.onERC721Received.selector;
}
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: BUSL-1.1
*/
pragma solidity ^0.8.0;
import { Owned } from "../../lib/accounts-v2/lib/solmate/src/auth/Owned.sol";
/**
* @title Guardian
* @author Pragma Labs
* @notice Pause guardian for an Asset Manager.
*/
abstract contract Guardian is Owned {
/* //////////////////////////////////////////////////////////////
STORAGE
////////////////////////////////////////////////////////////// */
// Flag indicating if the Asset Manager is paused.
bool public paused;
// Address of the Guardian.
address public guardian;
/* //////////////////////////////////////////////////////////////
ERRORS
////////////////////////////////////////////////////////////// */
error Paused();
error OnlyGuardian();
/* //////////////////////////////////////////////////////////////
EVENTS
////////////////////////////////////////////////////////////// */
event GuardianChanged(address indexed user, address indexed newGuardian);
event PauseFlagsUpdated(bool pauseUpdate);
/* //////////////////////////////////////////////////////////////
MODIFIERS
////////////////////////////////////////////////////////////// */
/**
* @dev Only guardians can call functions with this modifier.
*/
modifier onlyGuardian() {
if (msg.sender != guardian) revert OnlyGuardian();
_;
}
/**
* @dev Throws if the Asset Manager is paused.
*/
modifier whenNotPaused() {
if (paused) revert Paused();
_;
}
/* //////////////////////////////////////////////////////////////
CONSTRUCTOR
////////////////////////////////////////////////////////////// */
/**
* @param owner_ The address of the Owner.
*/
constructor(address owner_) Owned(owner_) { }
/* //////////////////////////////////////////////////////////////
GUARDIAN LOGIC
////////////////////////////////////////////////////////////// */
/**
* @notice Sets a new guardian.
* @param guardian_ The address of the new guardian.
*/
function changeGuardian(address guardian_) external onlyOwner {
emit GuardianChanged(msg.sender, guardian = guardian_);
}
/* //////////////////////////////////////////////////////////////
PAUSING LOGIC
////////////////////////////////////////////////////////////// */
/**
* @notice Pauses the Asset Manager.
*/
function pause() external onlyGuardian whenNotPaused {
emit PauseFlagsUpdated(paused = true);
}
/**
* @notice Sets the pause flag of the Asset Manager.
* @param paused_ Flag indicating if the Asset Manager is paused.
*/
function setPauseFlag(bool paused_) external onlyOwner {
emit PauseFlagsUpdated(paused = paused_);
}
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.0;
interface IAccount {
// forge-lint: disable-next-line(mixed-case-function)
function ACCOUNT_VERSION() external returns (uint256 version);
function flashAction(address actionTarget, bytes calldata actionData) external;
function owner() external returns (address owner_);
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.0;
interface IArcadiaFactory {
/**
* @notice Checks if a contract is an Account.
* @param account The contract address of the Account.
* @return bool indicating if the address is an Account or not.
*/
function isAccount(address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly ("memory-safe") {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly ("memory-safe") {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly ("memory-safe") {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly ("memory-safe") {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly ("memory-safe") {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use 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.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// 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**256. Since the preconditions guarantee
// that the outcome is less than 2**256, 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 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) != 0) {
require(++result > 0);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {BitMath} from "./BitMath.sol";
import {CustomRevert} from "./CustomRevert.sol";
/// @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.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
using CustomRevert for bytes4;
/// @notice Thrown when the tick passed to #getSqrtPriceAtTick is not between MIN_TICK and MAX_TICK
error InvalidTick(int24 tick);
/// @notice Thrown when the price passed to #getTickAtSqrtPrice does not correspond to a price between MIN_TICK and MAX_TICK
error InvalidSqrtPrice(uint160 sqrtPriceX96);
/// @dev The minimum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**-128
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**128
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
int24 internal constant MAX_TICK = 887272;
/// @dev The minimum tick spacing value drawn from the range of type int16 that is greater than 0, i.e. min from the range [1, 32767]
int24 internal constant MIN_TICK_SPACING = 1;
/// @dev The maximum tick spacing value drawn from the range of type int16, i.e. max from the range [1, 32767]
int24 internal constant MAX_TICK_SPACING = type(int16).max;
/// @dev The minimum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_PRICE = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342;
/// @dev A threshold used for optimized bounds check, equals `MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1`
uint160 internal constant MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE =
1461446703485210103287273052203988822378723970342 - 4295128739 - 1;
/// @notice Given a tickSpacing, compute the maximum usable tick
function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
unchecked {
return (MAX_TICK / tickSpacing) * tickSpacing;
}
}
/// @notice Given a tickSpacing, compute the minimum usable tick
function minUsableTick(int24 tickSpacing) internal pure returns (int24) {
unchecked {
return (MIN_TICK / tickSpacing) * tickSpacing;
}
}
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the price of the two assets (currency1/currency0)
/// at the given tick
function getSqrtPriceAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
unchecked {
uint256 absTick;
assembly ("memory-safe") {
tick := signextend(2, tick)
// mask = 0 if tick >= 0 else -1 (all 1s)
let mask := sar(255, tick)
// if tick >= 0, |tick| = tick = 0 ^ tick
// if tick < 0, |tick| = ~~|tick| = ~(-|tick| - 1) = ~(tick - 1) = (-1) ^ (tick - 1)
// either way, |tick| = mask ^ (tick + mask)
absTick := xor(mask, add(mask, tick))
}
if (absTick > uint256(int256(MAX_TICK))) InvalidTick.selector.revertWith(tick);
// The tick is decomposed into bits, and for each bit with index i that is set, the product of 1/sqrt(1.0001^(2^i))
// is calculated (using Q128.128). The constants used for this calculation are rounded to the nearest integer
// Equivalent to:
// price = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
// or price = int(2**128 / sqrt(1.0001)) if (absTick & 0x1) else 1 << 128
uint256 price;
assembly ("memory-safe") {
price := xor(shl(128, 1), mul(xor(shl(128, 1), 0xfffcb933bd6fad37aa2d162d1a594001), and(absTick, 0x1)))
}
if (absTick & 0x2 != 0) price = (price * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) price = (price * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) price = (price * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) price = (price * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) price = (price * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) price = (price * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) price = (price * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) price = (price * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) price = (price * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) price = (price * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) price = (price * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) price = (price * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) price = (price * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) price = (price * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) price = (price * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) price = (price * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) price = (price * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) price = (price * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) price = (price * 0x48a170391f7dc42444e8fa2) >> 128;
assembly ("memory-safe") {
// if (tick > 0) price = type(uint256).max / price;
if sgt(tick, 0) { price := div(not(0), price) }
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtPrice of the output price is always consistent
// `sub(shl(32, 1), 1)` is `type(uint32).max`
// `price + type(uint32).max` will not overflow because `price` fits in 192 bits
sqrtPriceX96 := shr(32, add(price, sub(shl(32, 1), 1)))
}
}
}
/// @notice Calculates the greatest tick value such that getSqrtPriceAtTick(tick) <= sqrtPriceX96
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_PRICE, as MIN_SQRT_PRICE is the lowest value getSqrtPriceAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt price for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the getSqrtPriceAtTick(tick) is less than or equal to the input sqrtPriceX96
function getTickAtSqrtPrice(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
unchecked {
// Equivalent: if (sqrtPriceX96 < MIN_SQRT_PRICE || sqrtPriceX96 >= MAX_SQRT_PRICE) revert InvalidSqrtPrice();
// second inequality must be >= because the price can never reach the price at the max tick
// if sqrtPriceX96 < MIN_SQRT_PRICE, the `sub` underflows and `gt` is true
// if sqrtPriceX96 >= MAX_SQRT_PRICE, sqrtPriceX96 - MIN_SQRT_PRICE > MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1
if ((sqrtPriceX96 - MIN_SQRT_PRICE) > MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE) {
InvalidSqrtPrice.selector.revertWith(sqrtPriceX96);
}
uint256 price = uint256(sqrtPriceX96) << 32;
uint256 r = price;
uint256 msb = BitMath.mostSignificantBit(r);
if (msb >= 128) r = price >> (msb - 127);
else r = price << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly ("memory-safe") {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // Q22.128 number
// Magic number represents the ceiling of the maximum value of the error when approximating log_sqrt10001(x)
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
// Magic number represents the minimum value of the error when approximating log_sqrt10001(x), when
// sqrtPrice is from the range (2^-64, 2^64). This is safe as MIN_SQRT_PRICE is more than 2^-64. If MIN_SQRT_PRICE
// is changed, this may need to be changed too
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtPriceAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}/**
* Created by Pragma Labs
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.8.0;
interface IPermit2 {
/**
* @notice The token and amount details for a transfer signed in the permit transfer signature
*/
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/**
* @notice Used to reconstruct the signed permit message for multiple token transfers
* @dev Do not need to pass in spender address as it is required that it is msg.sender
* @dev Note that a user still signs over a spender address
*/
struct PermitBatchTransferFrom {
// the tokens and corresponding amounts permitted for a transfer
TokenPermissions[] permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/**
* @notice Specifies the recipient address and amount for batched transfers.
* @dev Recipients and amounts correspond to the index of the signed token permissions array.
* @dev Reverts if the requested amount is greater than the permitted signed amount.
*/
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/**
* @notice Transfers multiple tokens using a signed permit message
* @param permit The permit data signed over by the owner
* @param owner The owner of the tokens to transfer
* @param transferDetails Specifies the recipient and requested amount for the token transfer
* @param signature The signature to verify
*/
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event OwnershipTransferred(address indexed user, address indexed newOwner);
/*//////////////////////////////////////////////////////////////
OWNERSHIP STORAGE
//////////////////////////////////////////////////////////////*/
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address _owner) {
owner = _owner;
emit OwnershipTransferred(address(0), _owner);
}
/*//////////////////////////////////////////////////////////////
OWNERSHIP LOGIC
//////////////////////////////////////////////////////////////*/
function transferOwnership(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
/// @author Solady (https://github.com/Vectorized/solady/blob/8200a70e8dc2a77ecb074fc2e99a2a0d36547522/src/utils/LibBit.sol)
library BitMath {
/// @notice Returns the index of the most significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @param x the value for which to compute the most significant bit, must be greater than 0
/// @return r the index of the most significant bit
function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
assembly ("memory-safe") {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020500060203020504000106050205030304010505030400000000))
}
}
/// @notice Returns the index of the least significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @param x the value for which to compute the least significant bit, must be greater than 0
/// @return r the index of the least significant bit
function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
assembly ("memory-safe") {
// Isolate the least significant bit.
x := and(x, sub(0, x))
// For the upper 3 bits of the result, use a De Bruijn-like lookup.
// Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
// forgefmt: disable-next-item
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Library for reverting with custom errors efficiently
/// @notice Contains functions for reverting with custom errors with different argument types efficiently
/// @dev To use this library, declare `using CustomRevert for bytes4;` and replace `revert CustomError()` with
/// `CustomError.selector.revertWith()`
/// @dev The functions may tamper with the free memory pointer but it is fine since the call context is exited immediately
library CustomRevert {
/// @dev ERC-7751 error for wrapping bubbled up reverts
error WrappedError(address target, bytes4 selector, bytes reason, bytes details);
/// @dev Reverts with the selector of a custom error in the scratch space
function revertWith(bytes4 selector) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
revert(0, 0x04)
}
}
/// @dev Reverts with a custom error with an address argument in the scratch space
function revertWith(bytes4 selector, address addr) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, and(addr, 0xffffffffffffffffffffffffffffffffffffffff))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with an int24 argument in the scratch space
function revertWith(bytes4 selector, int24 value) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, signextend(2, value))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with a uint160 argument in the scratch space
function revertWith(bytes4 selector, uint160 value) internal pure {
assembly ("memory-safe") {
mstore(0, selector)
mstore(0x04, and(value, 0xffffffffffffffffffffffffffffffffffffffff))
revert(0, 0x24)
}
}
/// @dev Reverts with a custom error with two int24 arguments
function revertWith(bytes4 selector, int24 value1, int24 value2) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(add(fmp, 0x04), signextend(2, value1))
mstore(add(fmp, 0x24), signextend(2, value2))
revert(fmp, 0x44)
}
}
/// @dev Reverts with a custom error with two uint160 arguments
function revertWith(bytes4 selector, uint160 value1, uint160 value2) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
revert(fmp, 0x44)
}
}
/// @dev Reverts with a custom error with two address arguments
function revertWith(bytes4 selector, address value1, address value2) internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(fmp, selector)
mstore(add(fmp, 0x04), and(value1, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(fmp, 0x24), and(value2, 0xffffffffffffffffffffffffffffffffffffffff))
revert(fmp, 0x44)
}
}
/// @notice bubble up the revert message returned by a call and revert with a wrapped ERC-7751 error
/// @dev this method can be vulnerable to revert data bombs
function bubbleUpAndRevertWith(
address revertingContract,
bytes4 revertingFunctionSelector,
bytes4 additionalContext
) internal pure {
bytes4 wrappedErrorSelector = WrappedError.selector;
assembly ("memory-safe") {
// Ensure the size of the revert data is a multiple of 32 bytes
let encodedDataSize := mul(div(add(returndatasize(), 31), 32), 32)
let fmp := mload(0x40)
// Encode wrapped error selector, address, function selector, offset, additional context, size, revert reason
mstore(fmp, wrappedErrorSelector)
mstore(add(fmp, 0x04), and(revertingContract, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(
add(fmp, 0x24),
and(revertingFunctionSelector, 0xffffffff00000000000000000000000000000000000000000000000000000000)
)
// offset revert reason
mstore(add(fmp, 0x44), 0x80)
// offset additional context
mstore(add(fmp, 0x64), add(0xa0, encodedDataSize))
// size revert reason
mstore(add(fmp, 0x84), returndatasize())
// revert reason
returndatacopy(add(fmp, 0xa4), 0, returndatasize())
// size additional context
mstore(add(fmp, add(0xa4, encodedDataSize)), 0x04)
// additional context
mstore(
add(fmp, add(0xc4, encodedDataSize)),
and(additionalContext, 0xffffffff00000000000000000000000000000000000000000000000000000000)
)
revert(fmp, add(0xe4, encodedDataSize))
}
}
}{
"remappings": [
"@ensdomains/=lib/lending-v2/lib/accounts-v2/lib/slipstream/node_modules/@ensdomains/",
"@nomad-xyz/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/ExcessivelySafeCall/",
"@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/openzeppelin-contracts/",
"@solidity-parser/=lib/lending-v2/lib/accounts-v2/lib/slipstream/node_modules/solhint/node_modules/@solidity-parser/",
"@uniswap/v2-core/contracts/=lib/lending-v2/lib/accounts-v2/./test/utils/fixtures/swap-router-02/",
"@uniswap/v3-core/contracts/=lib/lending-v2/lib/accounts-v2/lib/v3-core/contracts/",
"@uniswap/v3-periphery/contracts/=lib/lending-v2/lib/accounts-v2/lib/v3-periphery/contracts/",
"@uniswap/v4-core/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/v4-core/",
"@utils/=lib/lending-v2/lib/accounts-v2/lib/merkl-contracts/node_modules/utils/src/",
"ExcessivelySafeCall/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/ExcessivelySafeCall/src/",
"accounts-v2/=lib/lending-v2/lib/accounts-v2/src/",
"arcadia-periphery/=lib/arcadia-periphery/src/",
"asset-managers/=lib/arcadia-periphery/lib/asset-managers/src/",
"base64-sol/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/base64/",
"base64/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/base64/",
"contracts/=lib/lending-v2/lib/accounts-v2/lib/slipstream/contracts/",
"ds-test/=lib/lending-v2/lib/accounts-v2/lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/",
"forge-std/=lib/lending-v2/lib/accounts-v2/lib/forge-std/src/",
"hardhat/=lib/lending-v2/lib/accounts-v2/lib/slipstream/node_modules/hardhat/",
"lending-v2/=lib/lending-v2/src/",
"merkl-contracts/=lib/lending-v2/lib/accounts-v2/lib/merkl-contracts/",
"openzeppelin-contracts-upgradeable-v4.9/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-upgradeable-v4.9/",
"openzeppelin-contracts-v3.4/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/contracts/",
"openzeppelin-contracts-v4.9/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/",
"openzeppelin-contracts/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/openzeppelin-contracts/contracts/",
"openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/contracts/",
"oz/=lib/lending-v2/lib/accounts-v2/lib/merkl-contracts/node_modules/@openzeppelin/contracts/",
"permit2/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/permit2/",
"slipstream/=lib/lending-v2/lib/accounts-v2/lib/slipstream/",
"solady/=lib/lending-v2/lib/accounts-v2/lib/solady/src/",
"solidity-lib/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/solidity-lib/contracts/",
"solmate/=lib/lending-v2/lib/accounts-v2/lib/solmate/",
"swap-router-contracts/=lib/lending-v2/lib/accounts-v2/lib/swap-router-contracts/contracts/",
"v3-core/=lib/lending-v2/lib/accounts-v2/lib/v3-core/",
"v3-periphery/=lib/lending-v2/lib/accounts-v2/lib/v3-periphery/contracts/",
"v4-core/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/v4-core/src/",
"v4-periphery/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/",
"lib/accounts-v2/lib/merkl-contracts:@openzeppelin/contracts-upgradeable/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-upgradeable-v4.9/contracts/",
"lib/accounts-v2/lib/merkl-contracts:@openzeppelin/contracts/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/contracts/",
"lib/accounts-v2/lib/openzeppelin-contracts-upgradeable-v4.9:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/",
"lib/accounts-v2/lib/slipstream:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/slipstream/lib/openzeppelin-contracts/",
"lib/accounts-v2/lib/swap-router-contracts:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/",
"lib/accounts-v2/lib/v3-periphery:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/",
"lib/accounts-v2/lib/v4-periphery:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"lib/accounts-v2/lib/v4-periphery/lib/v4-core:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"lib/asset-managers/lib/accounts-v2/lib/slipstream:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/slipstream/lib/openzeppelin-contracts/",
"lib/asset-managers/lib/accounts-v2/lib/swap-router-contracts:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/",
"lib/asset-managers/lib/accounts-v2/lib/v3-periphery:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/",
"lib/asset-managers/lib/accounts-v2/lib/v4-periphery:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"lib/asset-managers/lib/accounts-v2/lib/v4-periphery/lib/v4-core:@openzeppelin/=lib/arcadia-periphery/lib/asset-managers/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"lib/merkl-contracts:@openzeppelin/contracts-upgradeable/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-upgradeable-v4.9/contracts/",
"lib/merkl-contracts:@openzeppelin/contracts/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/contracts/",
"lib/openzeppelin-contracts-upgradeable-v4.9:@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v4.9/",
"lib/slipstream:@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/slipstream/lib/openzeppelin-contracts/",
"lib/v3-periphery:@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/openzeppelin-contracts-v3.4/",
"lib/v4-periphery:@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"lib/v4-periphery/lib/v4-core:@openzeppelin/=lib/lending-v2/lib/accounts-v2/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"arcadiaFactory","type":"address"},{"internalType":"address","name":"positionManager","type":"address"},{"internalType":"address","name":"cLFactory","type":"address"},{"internalType":"address","name":"poolImplementation","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"address","name":"stakedSlipstreamAm","type":"address"},{"internalType":"address","name":"stakedSlipstreamWrapper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidAccountVersion","type":"error"},{"inputs":[],"name":"InvalidInitiator","type":"error"},{"inputs":[],"name":"InvalidPositionManager","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"NotAnAccount","type":"error"},{"inputs":[],"name":"OnlyAccount","type":"error"},{"inputs":[],"name":"OnlyAccountOwner","type":"error"},{"inputs":[],"name":"OnlyGuardian","type":"error"},{"inputs":[],"name":"OnlyPool","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"Reentered","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"initiator","type":"address"}],"name":"AccountInfoSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"positionManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newGuardian","type":"address"}],"name":"GuardianChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"pauseUpdate","type":"bool"}],"name":"PauseFlagsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"YieldClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"YieldTransferred","type":"event"},{"inputs":[],"name":"ARCADIA_FACTORY","outputs":[{"internalType":"contract IArcadiaFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountInfo","outputs":[{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint64","name":"maxClaimFee","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountOwner","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"accountToInitiator","outputs":[{"internalType":"address","name":"initiator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian_","type":"address"}],"name":"changeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"components":[{"internalType":"address","name":"positionManager","type":"address"},{"internalType":"uint96","name":"id","type":"uint96"},{"internalType":"uint64","name":"claimFee","type":"uint64"}],"internalType":"struct YieldClaimer.InitiatorParams","name":"initiatorParams","type":"tuple"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"actionTargetData","type":"bytes"}],"name":"executeAction","outputs":[{"components":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"assetIds","type":"uint256[]"},{"internalType":"uint256[]","name":"assetAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"assetTypes","type":"uint256[]"}],"internalType":"struct ActionData","name":"depositData","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"positionManager","type":"address"}],"name":"isPositionManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"metaData","outputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"accountOwner","type":"address"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onSetAssetManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint256","name":"maxClaimFee","type":"uint256"},{"internalType":"bytes","name":"metaData_","type":"bytes"}],"name":"setAccountInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused_","type":"bool"}],"name":"setPauseFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101603461019957601f612a3638819003918201601f19168301916001600160401b0383118484101761019d578084926101009460405283398101031261019957610049816101b1565b610055602083016101b1565b91610062604082016101b1565b61006e606083016101b1565b61007a608084016101b1565b9061008760a085016101b1565b926100a060e061009960c088016101b1565b96016101b1565b5f80546001600160a01b0319166001600160a01b039098169788178155604051989197907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a36001600160a01b039081166080521660c05260a05260e05261010052610120526101405261287090816101c6823960805181818161078b015281816108b70152610e71015260a0518181816110340152611c9e015260c05181818161110a01528181611b910152611f42015260e0518181816110550152611cbf015261010051818181611e1101528181611e4901528181611e7f015261205e015261012051816110c70152610140518161113a0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101995756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c80630686ddd9146101495780630a73e391146101445780630ede59ba1461013f5780631204f5251461013a578063150b7a02146101355780632fcb4f0414610130578063452a93201461012b5780635c975abb146101265780635f4860df146101215780638456cb591461011c5780638cffa277146101175780638da5cb5b146101125780638da92e711461010d578063a129568d14610108578063a7310b5814610103578063bc25cf77146100fe578063f2fde38b146100f9578063f474e258146100f45763fa461e330361000e57610fb1565b610ddd565b610d69565b610c8b565b610c37565b610a50565b61090d565b6108e6565b6108a2565b610826565b61070e565b6106e0565b6106b8565b610637565b6105dd565b610555565b61033c565b61030b565b610228565b6001600160a01b0381160361015f57565b5f80fd5b90600182811c92168015610191575b602083101461017d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610172565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b038211176101ca57604052565b61019b565b90601f801991011681019081106001600160401b038211176101ca57604052565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9060206102259281815201906101f0565b90565b3461015f57602036600319011261015f576004356102458161014e565b6001600160a01b03165f908152600460205260408082209051815490929161026c82610163565b80855291600181169081156102e457506001146102a4575b6102a084610294818603826101cf565b60405191829182610214565b0390f35b5f90815260208120939250905b8082106102ca5750909150810160200161029482610284565b9192600181602092548385880101520191019092916102b1565b60ff191660208087019190915292151560051b850190920192506102949150839050610284565b3461015f57602036600319011261015f57602061033260043561032d8161014e565b6110c5565b6040519015158152f35b3461015f57608036600319011261015f576004356103598161014e565b606036602319011261015f5760ff5f5460a01c16610546576002546001600160a01b031661053757600280546001600160a01b0319166001600160a01b038316179055604051638da5cb5b60e01b81526001600160a01b038216916020826004815f875af19081156104e5576103f161040692610413945f91610508575b506001600160a01b03165f90815260056020526040902090565b9060018060a01b03165f5260205260405f2090565b546001600160a01b031690565b336001600160a01b03909116036104f95761043661043261032d61118b565b1590565b6104ea5761048061044561118b565b61044d6111a8565b906001600160601b03604051926104798461046b33602083016111b4565b03601f1981018652856101cf565b1690611686565b90803b1561015f5760405162b9252f60e41b8152905f9082908183816104aa883060048401611216565b03925af180156104e5576104cb575b600280546001600160a01b0319169055005b806104d95f6104df936101cf565b806106ae565b806104b9565b611180565b63ed5f09f160e01b5f5260045ffd5b6317fb43e560e31b5f5260045ffd5b61052a915060203d602011610530575b61052281836101cf565b81019061116b565b5f6103d7565b503d610518565b63b5dfd9e560e01b5f5260045ffd5b6313d0ff5960e31b5f5260045ffd5b3461015f57604036600319011261015f5760206004356105748161014e565b602435906105818261014e565b6001600160a01b039081165f908152600584526040808220938316825260209390935282902054915191168152f35b9181601f8401121561015f578235916001600160401b03831161015f576020838186019501011161015f57565b3461015f57608036600319011261015f576105f960043561014e565b61060460243561014e565b6064356001600160401b03811161015f576106239036906004016105b0565b5050604051630a85bd0160e11b8152602090f35b3461015f57602036600319011261015f576004356106548161014e565b61066860018060a01b035f54163314611238565b600180546001600160a01b0319166001600160a01b03929092169182179055337fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e9675f80a3005b5f91031261015f57565b3461015f575f36600319011261015f576001546040516001600160a01b039091168152602090f35b3461015f575f36600319011261015f57602060ff5f5460a01c166040519015158152f35b8015150361015f57565b3461015f57606036600319011261015f5760043561072b8161014e565b610736602435610704565b6044356001600160401b03811161015f576107559036906004016105b0565b6002549192916001600160a01b031661053757604051630972932760e21b81523360048201526020816024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156104e5575f916107f7575b50156107e857826107d1916100189401906112ea565b9390926001600160a01b0392831692169033611859565b630ea8370b60e41b5f5260045ffd5b610819915060203d60201161081f575b61081181836101cf565b810190611273565b5f6107bb565b503d610807565b3461015f575f36600319011261015f576001546001600160a01b03163303610893575f5460ff8160a01c166105465760ff60a01b1916600160a01b175f55604051600181527f549bab54c75a364ce0e438a4fbf09df7e6b096bcc83a6f91065a0fc8e410b29a90602090a1005b636570ecab60e11b5f5260045ffd5b3461015f575f36600319011261015f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461015f575f36600319011261015f575f546040516001600160a01b039091168152602090f35b3461015f57602036600319011261015f577f549bab54c75a364ce0e438a4fbf09df7e6b096bcc83a6f91065a0fc8e410b29a602060043561094d81610704565b5f5490610964336001600160a01b03841614611238565b15159060ff60a01b8260a01b169060ff60a01b1916175f55604051908152a1005b90602080835192838152019201905f5b8181106109a25750505090565b8251845260209384019390920191600101610995565b80516080808452815190840181905260a08401949391602001905f5b818110610a20575050506060610a0f6109fd610225959660208601518582036020870152610985565b60408501518482036040860152610985565b920151906060818403910152610985565b82516001600160a01b03168752602096870196909201916001016109d4565b9060206102259281815201906109b8565b3461015f57602036600319011261015f576004356001600160401b03811161015f57610a809036906004016105b0565b90610a89611345565b50600254610aa7906001600160a01b03165b6001600160a01b031690565b3303610c2857335f908152600360205260409020610ad29190610ac990611379565b928101906113b7565b80519192916001600160a01b0316906040810190610af782516001600160401b031690565b6001600160401b03610b22610b1660208801516001600160401b031690565b6001600160401b031690565b911611610c1957610bb36020610bc26102a097610bd095610b65610b5f610b53868b9901516001600160601b031690565b6001600160601b031690565b87611b62565b95869161012083019a610b798c515161143e565b978891610ba6610b9d610b16610b8f865161143e565b96516001600160401b031690565b87878787611f2f565b516001600160a01b031690565b946001600160a01b031661232c565b92019485519051908561254e565b91516040519081526001600160a01b03919091169033907ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd399268390602090a360405191829182610a3f565b632a9ffab760e21b5f5260045ffd5b63f3f6425d60e01b5f5260045ffd5b3461015f57602036600319011261015f57600435610c548161014e565b6001600160a01b039081165f90815260036020908152604091829020548251938116845260a01c6001600160401b03169083015290f35b3461015f57602036600319011261015f57600435610ca88161014e565b5f5460ff90610cc1336001600160a01b03831614611238565b60a01c16610546576002546001600160a01b0316610537576001600160a01b031680610d0157506100185f80808047335af1610cfb61147f565b906114ae565b6040516370a0823160e01b815230600482015290602082602481845afa9081156104e557610018925f92610d38575b503390612664565b610d5b91925060203d602011610d62575b610d5381836101cf565b810190611470565b905f610d30565b503d610d49565b3461015f57602036600319011261015f57600435610d868161014e565b5f5490610d9d336001600160a01b03841614611238565b60018060a01b031680916001600160601b0360a01b16175f55337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b3461015f5760a036600319011261015f57600435610dfa8161014e565b60243590610e078261014e565b604435610e138161014e565b606435906084356001600160401b03811161015f57610e369036906004016105b0565b6002549195916001600160a01b031661053757604051630972932760e21b81526001600160a01b0386166004820152602081806024810103817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104e5575f91610f92575b50156107e857604051638da5cb5b60e01b8152906001600160a01b0386166020836004815f855af19283156104e5575f93610f71575b506001600160a01b0383163303610f625760205f91600460405180948193635e34633b60e11b83525af180156104e5576003915f91610f43575b5010610f345761001896610f2e9136916112b4565b94611859565b63a93eca7960e01b5f5260045ffd5b610f5c915060203d602011610d6257610d5381836101cf565b5f610f19565b6312272fd360e11b5f5260045ffd5b610f8b91935060203d6020116105305761052281836101cf565b915f610edf565b610fab915060203d60201161081f5761081181836101cf565b5f610ea9565b3461015f57606036600319011261015f576024356004356044356001600160401b03811161015f57610fe960609136906004016105b0565b908092918101031261015f578035926110018461014e565b61107960406020840135936110158561014e565b013594611021866114de565b6001600160a01b039384169593169285847f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006126f4565b336001600160a01b03909116036110b6575f83131561109f575061001892503390612664565b9150505f81136110ab57005b610018913390612664565b634b60273560e01b5f5260045ffd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169116908114908115611138575b8115611108575090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316811491506110fe565b9081602091031261015f57516102258161014e565b6040513d5f823e3d90fd5b6024356102258161014e565b6001600160601b0381160361015f57565b60443561022581611197565b6001600160a01b0390911681526080810191906024356111d38161014e565b6001600160a01b031660208201526001600160601b036044356111f581611197565b166040820152606435906001600160401b03821680920361015f5760600152565b6001600160a01b039091168152604060208201819052610225929101906101f0565b1561123f57565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b9081602091031261015f575161022581610704565b604051906112976080836101cf565b565b6001600160401b0381116101ca57601f01601f191660200190565b9291926112c082611299565b916112ce60405193846101cf565b82948184528183011161015f578281602093845f960137010152565b60808183031261015f5780356112ff8161014e565b92602082013561130e8161014e565b926040830135926060810135906001600160401b03821161015f57019080601f8301121561015f57816020610225933591016112b4565b60405190608082018281106001600160401b038211176101ca57604052606080838181528160208201528160408201520152565b90604051604081018181106001600160401b038211176101ca5760405291546001600160a01b038116835260a01c6001600160401b03166020830152565b80929103916080831261015f57606081356113d18161014e565b93601f19011261015f576060604051916113ea836101af565b60208101356113f88161014e565b8352604081013561140881611197565b602084015201356001600160401b038116810361015f57604082015290565b6001600160401b0381116101ca5760051b60200190565b9061144882611427565b61145560405191826101cf565b8281528092611466601f1991611427565b0190602036910137565b9081602091031261015f575190565b3d156114a9573d9061149082611299565b9161149e60405193846101cf565b82523d5f602084013e565b606090565b156114b65750565b60405162461bcd60e51b8152602060048201529081906114da9060248301906101f0565b0390fd5b8060020b0361015f57565b634e487b7160e01b5f52601160045260245ffd5b5f19811461150b5760010190565b6114e9565b6040516080919061152183826101cf565b6003815291601f1901366020840137565b6040516060919061154383826101cf565b6002815291601f1901366020840137565b634e487b7160e01b5f52603260045260245ffd5b8051156115755760200190565b611554565b8051600110156115755760400190565b8051600210156115755760600190565b80518210156115755760209160051b010190565b604051906115bb826101af565b5f604083606081528260208201520152565b929493916115e66115f49260a0865260a08601906109b8565b9084820360208601526109b8565b828103604084015260608101948051956060835286518091526020608084019701905f5b81811061165b575050509461164d91604080886020610225999a015160208501520151910152838103606085015260606101f0565b9160808184039101526101f0565b825180516001600160a01b03168a52602090810151818b015260409099019890920191600101611618565b9061022591611695600161143e565b916116a0600161143e565b6116aa600161143e565b916116b5600161143e565b936116bf86611568565b6001600160a01b0390911690526116d582611568565b5260016116e183611568565b5260026116ed84611568565b52604051936116fd6080866101cf565b8452602084015260408301526060820152611731611719611345565b936117226115ae565b604051958694602086016115cd565b03601f1981018352826101cf565b601f821161174c57505050565b5f5260205f20906020601f840160051c83019310611784575b601f0160051c01905b818110611779575050565b5f815560010161176e565b9091508190611765565b91909182516001600160401b0381116101ca576117b5816117af8454610163565b8461173f565b6020601f82116001146117f45781906117e59394955f926117e9575b50508160011b915f199060031b1c19161790565b9055565b015190505f806117d1565b601f19821690611807845f5260205f2090565b915f5b81811061184157509583600195969710611829575b505050811b019055565b01515f1960f88460031b161c191690555f808061181f565b9192602060018192868b01518155019401920161180a565b949193926001600160a01b038116156119b057670de0b6b3a76400008411610c195761190d6001600160401b0361197d956119619460018060a01b03165f5260056020526118dd886118be8b60405f209060018060a01b03165f5260205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b6118fc604051946118ef6040876101cf565b6001600160a01b03168552565b166001600160401b03166020830152565b6001600160a01b0386165f9081526003602052604090208151815460209093015167ffffffffffffffff60a01b60a09190911b166001600160e01b03199093166001600160a01b0390911617919091179055565b6001600160a01b0384165f90815260046020526040902061178e565b6001600160a01b0390811691167febc70f7c8d6a67b19e15e968cb908d21719e8ff9a778a71171fba931a618d0525f80a3565b634e46966960e11b5f5260045ffd5b6040519061014082018281106001600160401b038211176101ca576040526060610120835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201520152565b5190611297826114de565b51906001600160801b038216820361015f57565b91908261018091031261015f578151611a5181611197565b916020810151611a608161014e565b916040820151611a6f8161014e565b916060810151611a7e8161014e565b916080820151611a8d816114de565b91611a9a60a08201611a1a565b91611aa760c08301611a1a565b91611ab460e08201611a25565b916101008201519161012081015191610225610160611ad66101408501611a25565b9301611a25565b519061ffff8216820361015f57565b91908260c091031261015f578151611b038161014e565b916020810151611b12816114de565b91611b1f60408301611add565b91611b2c60608201611add565b9160a0611b3b60808401611add565b92015161022581610704565b9081602091031261015f575162ffffff8116810361015f5790565b611bc990929192611b716119bf565b6020810185905260405163133f757160e31b8152600481019590955293917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061018090849081906024820190565b0381845afa9182156104e557611cf093611ce39387935f935f935f905f905f905f96611ea7575b50611c39929160c08a611c29611c3294611c1f6060611c9b9d9e9f019b60e08501906001600160801b03169052565b60020b60a0830152565b019060020b9052565b60020b8452565b6001600160a01b0316148015611e71575b8015611e3b575b15611dfa57611c5e611532565b6101208901525b611c9483611c7f6101208b01611c8e88611c7f8351611568565b6001600160a01b039091169052565b5161157a565b5160020b90565b917f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006126f4565b6001600160a01b03168352565b815160049060c090611d0c90610a9b906001600160a01b031681565b604051633850c7bd60e01b815292839182905afa80156104e5575f915f91611dbf575b5060020b60808401525b6001600160a01b039081166101008401528251600491602091611d5e91610a9b911681565b60405163ddca3f4360e01b815292839182905afa80156104e557611297915f91611d90575b5062ffffff166040840152565b611db2915060203d602011611db8575b611daa81836101cf565b810190611b47565b5f611d83565b503d611da0565b611d399250611de6915060c03d60c011611df3575b611dde81836101cf565b810190611aec565b5050505091909190611d2f565b503d611dd4565b611e36611e05611510565b806101208b0152611c7f7f00000000000000000000000000000000000000000000000000000000000000009161158a565b611c65565b506001600160a01b038381167f000000000000000000000000000000000000000000000000000000000000000090911614611c51565b506001600160a01b038481167f000000000000000000000000000000000000000000000000000000000000000090911614611c4a565b611c299850611c9b9750611c329650611c39935060c09250611ee191506101803d8111611f05575b611ed981836101cf565b810190611a39565b505050509b9650945095929c919c9b909b9c9b95939450509a999850509192611bf0565b503d611ecf565b919082604091031261015f576020825192015190565b9190820180921161150b57565b6001600160a01b039283169491929091907f0000000000000000000000000000000000000000000000000000000000000000168581146121345750602084810151604051630ae169a560e41b8152600481019190915295869060249082905f905af19485156104e5575f9561210f575b50611faa9085612796565b9160038251145f1461203d5790611fea91611fe4611fde611fd488611fce8661158a565b51611f22565b95611fce8461158a565b9161158a565b5261158a565b5261012001516001600160a01b039061200690610ba69061158a565b604051928352169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd79080602081015b0390a3565b90926101200192612051610ba68551611568565b6001600160a01b039081167f0000000000000000000000000000000000000000000000000000000000000000909116036120ca576120b2916120ac6120a661209c88611fce86611568565b95611fce84611568565b91611568565b52611568565b52516001600160a01b039061200690610ba690611568565b6120f7916120f16120eb6120e188611fce8661157a565b95611fce8461157a565b9161157a565b5261157a565b52516001600160a01b039061200690610ba69061157a565b611faa91955061212d9060203d602011610d6257610d5381836101cf565b9490611f9f565b84939295506121b660409160205f97015161214d611288565b90815230602082019081526001600160801b0385830181905260608301818152865163fc6f786560e01b81528451600482015292516001600160a01b03166024840152604090930151811660448301529151909116606482015296879283919082906084820190565b03925af19485156104e5575f945f966122be575b50610a9b93610ba69361223c6120eb61223389968661220c6120eb8e6121f96122899f611fce6101209d611568565b61220285611568565b52611fce8461157a565b5261222361221a828a612796565b611fce87611568565b61222c86611568565b528b612796565b611fce8461157a565b52019060018060a01b03612253610ba68451611568565b604051928352169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd790602090a35161157a565b6040519182529033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd7908060208101612038565b6120eb9650612289955093610ba69361223c6120eb61223361220c9661012096612302610a9b9b60403d604011612318575b6122fa81836101cf565b810190611f0c565b9990999d505096509699505050509350936121ca565b503d6122f0565b9190820391821161150b57565b6020850151949695909490936001600160a01b0316803b1561015f5760405163095ea7b360e01b815233600482015260248101929092525f908290604490829084905af180156104e55761253a575b506001955f5b82518110156125325761239c610ba68261012085015161159a565b6123a6828561159a565b516123b1838761159a565b51101561250c576123d76123c5838661159a565b516123d0848861159a565b519061231f565b986001600160a01b03871633036124e1579061241383928b6123fb6001968961159a565b5261240e8c33878060a01b0386166127be565b6114fd565b995b61241f838861159a565b516124c0575b61242f838861159a565b5160405190815260a085901b859003928316928391908b169033907f1b37fcc57f4b6029ca7b3a70af0104811f67c72fe73e8043575f03a01e05663190602090a4838060a01b0388169033820361248a575b50505001612381565b60405190815233907f9a20584dd4630e0091901c0ae29c3098e8672b1cb8c0dd8e99595536ae6e211f90602090a45f8080612481565b6124dc6124cd848961159a565b518a868060a01b038516612664565b612425565b9860019291906124fb81896001600160a01b038516612664565b5f612506848861159a565b52612415565b906001915f61251b838761159a565b51612526848961159a565b525f612506848861159a565b505050505050565b806104d95f612548936101cf565b5f61237b565b929390919361255b611345565b506125658261143e565b9460016125718461143e565b9361257b8161143e565b956125926125888361143e565b98611c7f8b611568565b61259b86611568565b52816125a687611568565b5260026125b288611568565b52116125d8575b50506125c3611288565b93845260208401526040830152606082015290565b9194909395926001935f5b8651811015612654576125f6818861159a565b51612604575b6001016125e3565b9461264c60019161262561261b610ba68a8a61159a565b611c7f838961159a565b61262f888a61159a565b5161263a828761159a565b5282612646828d61159a565b526114fd565b9590506125fc565b5096945092509390505f806125b9565b60405163a9059cbb60e01b81526001600160a01b03909216600483015260248201929092526020905f9060449082855af19081601f3d1160015f51141615166126e7575b50156126b057565b60405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606490fd5b3b153d171590505f6126a8565b6001600160a01b0393841694939092168481101561015f576055946037946040519160208301938452604083015260020b6060820152606081526127396080826101cf565b5190209060405192733d602d80600a3d3981f3363d3d373d3d3d363d7360601b845260601b60148401526f5af43d82803e903d91602b57fd5bf3ff60801b602884015260601b6038830152604c820152818120606c820152012090565b90805f19048211810215670de0b6b3a7640000021561015f57670de0b6b3a764000091020490565b906014528160345263095ea7b360601b5f5260205f6044601082855af13d1560015f51141716156127f2575b50505f603452565b604460105f80936020958260345263095ea7b360601b83528238868683865af1506034525af13d1560015f511417161561282d575f806127ea565b633e3f8f735f526004601cfdfea264697066735822122039199c359a742e53dcd0297c2bcac9525e49c79595a3f29051a2678c2dce1fa364736f6c634300081e0033000000000000000000000000b4d72b1c91e640e4ed7d7397f3244de4d8acc50b000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e59000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb2470200000000000000000000000004625b046c69577efc40e6c0bb83cdbafab5a55f000000000000000000000000321f7dfb9b2ea9131b8c17691cf6e01e5c149ca80000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a810000000000000000000000001dc7a0f5336f52724b650e39174cfcbbedd67bf1000000000000000000000000d74339e0f10fce96894916b93e5cc7de89c98272
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c80630686ddd9146101495780630a73e391146101445780630ede59ba1461013f5780631204f5251461013a578063150b7a02146101355780632fcb4f0414610130578063452a93201461012b5780635c975abb146101265780635f4860df146101215780638456cb591461011c5780638cffa277146101175780638da5cb5b146101125780638da92e711461010d578063a129568d14610108578063a7310b5814610103578063bc25cf77146100fe578063f2fde38b146100f9578063f474e258146100f45763fa461e330361000e57610fb1565b610ddd565b610d69565b610c8b565b610c37565b610a50565b61090d565b6108e6565b6108a2565b610826565b61070e565b6106e0565b6106b8565b610637565b6105dd565b610555565b61033c565b61030b565b610228565b6001600160a01b0381160361015f57565b5f80fd5b90600182811c92168015610191575b602083101461017d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610172565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b038211176101ca57604052565b61019b565b90601f801991011681019081106001600160401b038211176101ca57604052565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9060206102259281815201906101f0565b90565b3461015f57602036600319011261015f576004356102458161014e565b6001600160a01b03165f908152600460205260408082209051815490929161026c82610163565b80855291600181169081156102e457506001146102a4575b6102a084610294818603826101cf565b60405191829182610214565b0390f35b5f90815260208120939250905b8082106102ca5750909150810160200161029482610284565b9192600181602092548385880101520191019092916102b1565b60ff191660208087019190915292151560051b850190920192506102949150839050610284565b3461015f57602036600319011261015f57602061033260043561032d8161014e565b6110c5565b6040519015158152f35b3461015f57608036600319011261015f576004356103598161014e565b606036602319011261015f5760ff5f5460a01c16610546576002546001600160a01b031661053757600280546001600160a01b0319166001600160a01b038316179055604051638da5cb5b60e01b81526001600160a01b038216916020826004815f875af19081156104e5576103f161040692610413945f91610508575b506001600160a01b03165f90815260056020526040902090565b9060018060a01b03165f5260205260405f2090565b546001600160a01b031690565b336001600160a01b03909116036104f95761043661043261032d61118b565b1590565b6104ea5761048061044561118b565b61044d6111a8565b906001600160601b03604051926104798461046b33602083016111b4565b03601f1981018652856101cf565b1690611686565b90803b1561015f5760405162b9252f60e41b8152905f9082908183816104aa883060048401611216565b03925af180156104e5576104cb575b600280546001600160a01b0319169055005b806104d95f6104df936101cf565b806106ae565b806104b9565b611180565b63ed5f09f160e01b5f5260045ffd5b6317fb43e560e31b5f5260045ffd5b61052a915060203d602011610530575b61052281836101cf565b81019061116b565b5f6103d7565b503d610518565b63b5dfd9e560e01b5f5260045ffd5b6313d0ff5960e31b5f5260045ffd5b3461015f57604036600319011261015f5760206004356105748161014e565b602435906105818261014e565b6001600160a01b039081165f908152600584526040808220938316825260209390935282902054915191168152f35b9181601f8401121561015f578235916001600160401b03831161015f576020838186019501011161015f57565b3461015f57608036600319011261015f576105f960043561014e565b61060460243561014e565b6064356001600160401b03811161015f576106239036906004016105b0565b5050604051630a85bd0160e11b8152602090f35b3461015f57602036600319011261015f576004356106548161014e565b61066860018060a01b035f54163314611238565b600180546001600160a01b0319166001600160a01b03929092169182179055337fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e9675f80a3005b5f91031261015f57565b3461015f575f36600319011261015f576001546040516001600160a01b039091168152602090f35b3461015f575f36600319011261015f57602060ff5f5460a01c166040519015158152f35b8015150361015f57565b3461015f57606036600319011261015f5760043561072b8161014e565b610736602435610704565b6044356001600160401b03811161015f576107559036906004016105b0565b6002549192916001600160a01b031661053757604051630972932760e21b81523360048201526020816024816001600160a01b037f000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e59165afa9081156104e5575f916107f7575b50156107e857826107d1916100189401906112ea565b9390926001600160a01b0392831692169033611859565b630ea8370b60e41b5f5260045ffd5b610819915060203d60201161081f575b61081181836101cf565b810190611273565b5f6107bb565b503d610807565b3461015f575f36600319011261015f576001546001600160a01b03163303610893575f5460ff8160a01c166105465760ff60a01b1916600160a01b175f55604051600181527f549bab54c75a364ce0e438a4fbf09df7e6b096bcc83a6f91065a0fc8e410b29a90602090a1005b636570ecab60e11b5f5260045ffd5b3461015f575f36600319011261015f576040517f000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e596001600160a01b03168152602090f35b3461015f575f36600319011261015f575f546040516001600160a01b039091168152602090f35b3461015f57602036600319011261015f577f549bab54c75a364ce0e438a4fbf09df7e6b096bcc83a6f91065a0fc8e410b29a602060043561094d81610704565b5f5490610964336001600160a01b03841614611238565b15159060ff60a01b8260a01b169060ff60a01b1916175f55604051908152a1005b90602080835192838152019201905f5b8181106109a25750505090565b8251845260209384019390920191600101610995565b80516080808452815190840181905260a08401949391602001905f5b818110610a20575050506060610a0f6109fd610225959660208601518582036020870152610985565b60408501518482036040860152610985565b920151906060818403910152610985565b82516001600160a01b03168752602096870196909201916001016109d4565b9060206102259281815201906109b8565b3461015f57602036600319011261015f576004356001600160401b03811161015f57610a809036906004016105b0565b90610a89611345565b50600254610aa7906001600160a01b03165b6001600160a01b031690565b3303610c2857335f908152600360205260409020610ad29190610ac990611379565b928101906113b7565b80519192916001600160a01b0316906040810190610af782516001600160401b031690565b6001600160401b03610b22610b1660208801516001600160401b031690565b6001600160401b031690565b911611610c1957610bb36020610bc26102a097610bd095610b65610b5f610b53868b9901516001600160601b031690565b6001600160601b031690565b87611b62565b95869161012083019a610b798c515161143e565b978891610ba6610b9d610b16610b8f865161143e565b96516001600160401b031690565b87878787611f2f565b516001600160a01b031690565b946001600160a01b031661232c565b92019485519051908561254e565b91516040519081526001600160a01b03919091169033907ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd399268390602090a360405191829182610a3f565b632a9ffab760e21b5f5260045ffd5b63f3f6425d60e01b5f5260045ffd5b3461015f57602036600319011261015f57600435610c548161014e565b6001600160a01b039081165f90815260036020908152604091829020548251938116845260a01c6001600160401b03169083015290f35b3461015f57602036600319011261015f57600435610ca88161014e565b5f5460ff90610cc1336001600160a01b03831614611238565b60a01c16610546576002546001600160a01b0316610537576001600160a01b031680610d0157506100185f80808047335af1610cfb61147f565b906114ae565b6040516370a0823160e01b815230600482015290602082602481845afa9081156104e557610018925f92610d38575b503390612664565b610d5b91925060203d602011610d62575b610d5381836101cf565b810190611470565b905f610d30565b503d610d49565b3461015f57602036600319011261015f57600435610d868161014e565b5f5490610d9d336001600160a01b03841614611238565b60018060a01b031680916001600160601b0360a01b16175f55337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b3461015f5760a036600319011261015f57600435610dfa8161014e565b60243590610e078261014e565b604435610e138161014e565b606435906084356001600160401b03811161015f57610e369036906004016105b0565b6002549195916001600160a01b031661053757604051630972932760e21b81526001600160a01b0386166004820152602081806024810103817f000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e596001600160a01b03165afa9081156104e5575f91610f92575b50156107e857604051638da5cb5b60e01b8152906001600160a01b0386166020836004815f855af19283156104e5575f93610f71575b506001600160a01b0383163303610f625760205f91600460405180948193635e34633b60e11b83525af180156104e5576003915f91610f43575b5010610f345761001896610f2e9136916112b4565b94611859565b63a93eca7960e01b5f5260045ffd5b610f5c915060203d602011610d6257610d5381836101cf565b5f610f19565b6312272fd360e11b5f5260045ffd5b610f8b91935060203d6020116105305761052281836101cf565b915f610edf565b610fab915060203d60201161081f5761081181836101cf565b5f610ea9565b3461015f57606036600319011261015f576024356004356044356001600160401b03811161015f57610fe960609136906004016105b0565b908092918101031261015f578035926110018461014e565b61107960406020840135936110158561014e565b013594611021866114de565b6001600160a01b039384169593169285847f00000000000000000000000004625b046c69577efc40e6c0bb83cdbafab5a55f7f000000000000000000000000321f7dfb9b2ea9131b8c17691cf6e01e5c149ca86126f4565b336001600160a01b03909116036110b6575f83131561109f575061001892503390612664565b9150505f81136110ab57005b610018913390612664565b634b60273560e01b5f5260045ffd5b7f0000000000000000000000001dc7a0f5336f52724b650e39174cfcbbedd67bf16001600160a01b039081169116908114908115611138575b8115611108575090565b7f000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb247026001600160a01b031614919050565b7f000000000000000000000000d74339e0f10fce96894916b93e5cc7de89c982726001600160a01b0316811491506110fe565b9081602091031261015f57516102258161014e565b6040513d5f823e3d90fd5b6024356102258161014e565b6001600160601b0381160361015f57565b60443561022581611197565b6001600160a01b0390911681526080810191906024356111d38161014e565b6001600160a01b031660208201526001600160601b036044356111f581611197565b166040820152606435906001600160401b03821680920361015f5760600152565b6001600160a01b039091168152604060208201819052610225929101906101f0565b1561123f57565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b9081602091031261015f575161022581610704565b604051906112976080836101cf565b565b6001600160401b0381116101ca57601f01601f191660200190565b9291926112c082611299565b916112ce60405193846101cf565b82948184528183011161015f578281602093845f960137010152565b60808183031261015f5780356112ff8161014e565b92602082013561130e8161014e565b926040830135926060810135906001600160401b03821161015f57019080601f8301121561015f57816020610225933591016112b4565b60405190608082018281106001600160401b038211176101ca57604052606080838181528160208201528160408201520152565b90604051604081018181106001600160401b038211176101ca5760405291546001600160a01b038116835260a01c6001600160401b03166020830152565b80929103916080831261015f57606081356113d18161014e565b93601f19011261015f576060604051916113ea836101af565b60208101356113f88161014e565b8352604081013561140881611197565b602084015201356001600160401b038116810361015f57604082015290565b6001600160401b0381116101ca5760051b60200190565b9061144882611427565b61145560405191826101cf565b8281528092611466601f1991611427565b0190602036910137565b9081602091031261015f575190565b3d156114a9573d9061149082611299565b9161149e60405193846101cf565b82523d5f602084013e565b606090565b156114b65750565b60405162461bcd60e51b8152602060048201529081906114da9060248301906101f0565b0390fd5b8060020b0361015f57565b634e487b7160e01b5f52601160045260245ffd5b5f19811461150b5760010190565b6114e9565b6040516080919061152183826101cf565b6003815291601f1901366020840137565b6040516060919061154383826101cf565b6002815291601f1901366020840137565b634e487b7160e01b5f52603260045260245ffd5b8051156115755760200190565b611554565b8051600110156115755760400190565b8051600210156115755760600190565b80518210156115755760209160051b010190565b604051906115bb826101af565b5f604083606081528260208201520152565b929493916115e66115f49260a0865260a08601906109b8565b9084820360208601526109b8565b828103604084015260608101948051956060835286518091526020608084019701905f5b81811061165b575050509461164d91604080886020610225999a015160208501520151910152838103606085015260606101f0565b9160808184039101526101f0565b825180516001600160a01b03168a52602090810151818b015260409099019890920191600101611618565b9061022591611695600161143e565b916116a0600161143e565b6116aa600161143e565b916116b5600161143e565b936116bf86611568565b6001600160a01b0390911690526116d582611568565b5260016116e183611568565b5260026116ed84611568565b52604051936116fd6080866101cf565b8452602084015260408301526060820152611731611719611345565b936117226115ae565b604051958694602086016115cd565b03601f1981018352826101cf565b601f821161174c57505050565b5f5260205f20906020601f840160051c83019310611784575b601f0160051c01905b818110611779575050565b5f815560010161176e565b9091508190611765565b91909182516001600160401b0381116101ca576117b5816117af8454610163565b8461173f565b6020601f82116001146117f45781906117e59394955f926117e9575b50508160011b915f199060031b1c19161790565b9055565b015190505f806117d1565b601f19821690611807845f5260205f2090565b915f5b81811061184157509583600195969710611829575b505050811b019055565b01515f1960f88460031b161c191690555f808061181f565b9192602060018192868b01518155019401920161180a565b949193926001600160a01b038116156119b057670de0b6b3a76400008411610c195761190d6001600160401b0361197d956119619460018060a01b03165f5260056020526118dd886118be8b60405f209060018060a01b03165f5260205260405f2090565b80546001600160a01b0319166001600160a01b03909216919091179055565b6118fc604051946118ef6040876101cf565b6001600160a01b03168552565b166001600160401b03166020830152565b6001600160a01b0386165f9081526003602052604090208151815460209093015167ffffffffffffffff60a01b60a09190911b166001600160e01b03199093166001600160a01b0390911617919091179055565b6001600160a01b0384165f90815260046020526040902061178e565b6001600160a01b0390811691167febc70f7c8d6a67b19e15e968cb908d21719e8ff9a778a71171fba931a618d0525f80a3565b634e46966960e11b5f5260045ffd5b6040519061014082018281106001600160401b038211176101ca576040526060610120835f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201520152565b5190611297826114de565b51906001600160801b038216820361015f57565b91908261018091031261015f578151611a5181611197565b916020810151611a608161014e565b916040820151611a6f8161014e565b916060810151611a7e8161014e565b916080820151611a8d816114de565b91611a9a60a08201611a1a565b91611aa760c08301611a1a565b91611ab460e08201611a25565b916101008201519161012081015191610225610160611ad66101408501611a25565b9301611a25565b519061ffff8216820361015f57565b91908260c091031261015f578151611b038161014e565b916020810151611b12816114de565b91611b1f60408301611add565b91611b2c60608201611add565b9160a0611b3b60808401611add565b92015161022581610704565b9081602091031261015f575162ffffff8116810361015f5790565b611bc990929192611b716119bf565b6020810185905260405163133f757160e31b8152600481019590955293917f000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb247026001600160a01b03169061018090849081906024820190565b0381845afa9182156104e557611cf093611ce39387935f935f935f905f905f905f96611ea7575b50611c39929160c08a611c29611c3294611c1f6060611c9b9d9e9f019b60e08501906001600160801b03169052565b60020b60a0830152565b019060020b9052565b60020b8452565b6001600160a01b0316148015611e71575b8015611e3b575b15611dfa57611c5e611532565b6101208901525b611c9483611c7f6101208b01611c8e88611c7f8351611568565b6001600160a01b039091169052565b5161157a565b5160020b90565b917f00000000000000000000000004625b046c69577efc40e6c0bb83cdbafab5a55f7f000000000000000000000000321f7dfb9b2ea9131b8c17691cf6e01e5c149ca86126f4565b6001600160a01b03168352565b815160049060c090611d0c90610a9b906001600160a01b031681565b604051633850c7bd60e01b815292839182905afa80156104e5575f915f91611dbf575b5060020b60808401525b6001600160a01b039081166101008401528251600491602091611d5e91610a9b911681565b60405163ddca3f4360e01b815292839182905afa80156104e557611297915f91611d90575b5062ffffff166040840152565b611db2915060203d602011611db8575b611daa81836101cf565b810190611b47565b5f611d83565b503d611da0565b611d399250611de6915060c03d60c011611df3575b611dde81836101cf565b810190611aec565b5050505091909190611d2f565b503d611dd4565b611e36611e05611510565b806101208b0152611c7f7f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a819161158a565b611c65565b506001600160a01b038381167f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8190911614611c51565b506001600160a01b038481167f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a8190911614611c4a565b611c299850611c9b9750611c329650611c39935060c09250611ee191506101803d8111611f05575b611ed981836101cf565b810190611a39565b505050509b9650945095929c919c9b909b9c9b95939450509a999850509192611bf0565b503d611ecf565b919082604091031261015f576020825192015190565b9190820180921161150b57565b6001600160a01b039283169491929091907f000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb24702168581146121345750602084810151604051630ae169a560e41b8152600481019190915295869060249082905f905af19485156104e5575f9561210f575b50611faa9085612796565b9160038251145f1461203d5790611fea91611fe4611fde611fd488611fce8661158a565b51611f22565b95611fce8461158a565b9161158a565b5261158a565b5261012001516001600160a01b039061200690610ba69061158a565b604051928352169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd79080602081015b0390a3565b90926101200192612051610ba68551611568565b6001600160a01b039081167f0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a81909116036120ca576120b2916120ac6120a661209c88611fce86611568565b95611fce84611568565b91611568565b52611568565b52516001600160a01b039061200690610ba690611568565b6120f7916120f16120eb6120e188611fce8661157a565b95611fce8461157a565b9161157a565b5261157a565b52516001600160a01b039061200690610ba69061157a565b611faa91955061212d9060203d602011610d6257610d5381836101cf565b9490611f9f565b84939295506121b660409160205f97015161214d611288565b90815230602082019081526001600160801b0385830181905260608301818152865163fc6f786560e01b81528451600482015292516001600160a01b03166024840152604090930151811660448301529151909116606482015296879283919082906084820190565b03925af19485156104e5575f945f966122be575b50610a9b93610ba69361223c6120eb61223389968661220c6120eb8e6121f96122899f611fce6101209d611568565b61220285611568565b52611fce8461157a565b5261222361221a828a612796565b611fce87611568565b61222c86611568565b528b612796565b611fce8461157a565b52019060018060a01b03612253610ba68451611568565b604051928352169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd790602090a35161157a565b6040519182529033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd7908060208101612038565b6120eb9650612289955093610ba69361223c6120eb61223361220c9661012096612302610a9b9b60403d604011612318575b6122fa81836101cf565b810190611f0c565b9990999d505096509699505050509350936121ca565b503d6122f0565b9190820391821161150b57565b6020850151949695909490936001600160a01b0316803b1561015f5760405163095ea7b360e01b815233600482015260248101929092525f908290604490829084905af180156104e55761253a575b506001955f5b82518110156125325761239c610ba68261012085015161159a565b6123a6828561159a565b516123b1838761159a565b51101561250c576123d76123c5838661159a565b516123d0848861159a565b519061231f565b986001600160a01b03871633036124e1579061241383928b6123fb6001968961159a565b5261240e8c33878060a01b0386166127be565b6114fd565b995b61241f838861159a565b516124c0575b61242f838861159a565b5160405190815260a085901b859003928316928391908b169033907f1b37fcc57f4b6029ca7b3a70af0104811f67c72fe73e8043575f03a01e05663190602090a4838060a01b0388169033820361248a575b50505001612381565b60405190815233907f9a20584dd4630e0091901c0ae29c3098e8672b1cb8c0dd8e99595536ae6e211f90602090a45f8080612481565b6124dc6124cd848961159a565b518a868060a01b038516612664565b612425565b9860019291906124fb81896001600160a01b038516612664565b5f612506848861159a565b52612415565b906001915f61251b838761159a565b51612526848961159a565b525f612506848861159a565b505050505050565b806104d95f612548936101cf565b5f61237b565b929390919361255b611345565b506125658261143e565b9460016125718461143e565b9361257b8161143e565b956125926125888361143e565b98611c7f8b611568565b61259b86611568565b52816125a687611568565b5260026125b288611568565b52116125d8575b50506125c3611288565b93845260208401526040830152606082015290565b9194909395926001935f5b8651811015612654576125f6818861159a565b51612604575b6001016125e3565b9461264c60019161262561261b610ba68a8a61159a565b611c7f838961159a565b61262f888a61159a565b5161263a828761159a565b5282612646828d61159a565b526114fd565b9590506125fc565b5096945092509390505f806125b9565b60405163a9059cbb60e01b81526001600160a01b03909216600483015260248201929092526020905f9060449082855af19081601f3d1160015f51141615166126e7575b50156126b057565b60405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606490fd5b3b153d171590505f6126a8565b6001600160a01b0393841694939092168481101561015f576055946037946040519160208301938452604083015260020b6060820152606081526127396080826101cf565b5190209060405192733d602d80600a3d3981f3363d3d373d3d3d363d7360601b845260601b60148401526f5af43d82803e903d91602b57fd5bf3ff60801b602884015260601b6038830152604c820152818120606c820152012090565b90805f19048211810215670de0b6b3a7640000021561015f57670de0b6b3a764000091020490565b906014528160345263095ea7b360601b5f5260205f6044601082855af13d1560015f51141716156127f2575b50505f603452565b604460105f80936020958260345263095ea7b360601b83528238868683865af1506034525af13d1560015f511417161561282d575f806127ea565b633e3f8f735f526004601cfdfea264697066735822122039199c359a742e53dcd0297c2bcac9525e49c79595a3f29051a2678c2dce1fa364736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b4d72b1c91e640e4ed7d7397f3244de4d8acc50b000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e59000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb2470200000000000000000000000004625b046c69577efc40e6c0bb83cdbafab5a55f000000000000000000000000321f7dfb9b2ea9131b8c17691cf6e01e5c149ca80000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a810000000000000000000000001dc7a0f5336f52724b650e39174cfcbbedd67bf1000000000000000000000000d74339e0f10fce96894916b93e5cc7de89c98272
-----Decoded View---------------
Arg [0] : owner_ (address): 0xb4d72B1c91e640e4ED7d7397F3244De4D8ACc50B
Arg [1] : arcadiaFactory (address): 0xDa14Fdd72345c4d2511357214c5B89A919768e59
Arg [2] : positionManager (address): 0x991d5546C4B442B4c5fdc4c8B8b8d131DEB24702
Arg [3] : cLFactory (address): 0x04625B046C69577EfC40e6c0Bb83CDBAfab5a55F
Arg [4] : poolImplementation (address): 0x321f7Dfb9B2eA9131B8C17691CF6e01E5c149cA8
Arg [5] : rewardToken (address): 0x7f9AdFbd38b669F03d1d11000Bc76b9AaEA28A81
Arg [6] : stakedSlipstreamAm (address): 0x1Dc7A0f5336F52724B650E39174cfcbbEdD67bF1
Arg [7] : stakedSlipstreamWrapper (address): 0xD74339e0F10fcE96894916B93E5Cc7dE89C98272
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000b4d72b1c91e640e4ed7d7397f3244de4d8acc50b
Arg [1] : 000000000000000000000000da14fdd72345c4d2511357214c5b89a919768e59
Arg [2] : 000000000000000000000000991d5546c4b442b4c5fdc4c8b8b8d131deb24702
Arg [3] : 00000000000000000000000004625b046c69577efc40e6c0bb83cdbafab5a55f
Arg [4] : 000000000000000000000000321f7dfb9b2ea9131b8c17691cf6e01e5c149ca8
Arg [5] : 0000000000000000000000007f9adfbd38b669f03d1d11000bc76b9aaea28a81
Arg [6] : 0000000000000000000000001dc7a0f5336f52724b650e39174cfcbbedd67bf1
Arg [7] : 000000000000000000000000d74339e0f10fce96894916b93e5cc7de89c98272
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.