Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
ShadowV3Connector
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IShadowNonfungiblePositionManager } from "contracts/interfaces/external/shadow/IShadowNonfungiblePositionManager.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UniswapV3Connector } from "contracts/connectors/velodrome/SlipstreamNftConnector.sol"; import { NftAddLiquidity, NftRemoveLiquidity } from "contracts/interfaces/INftLiquidityConnector.sol"; import { INftFarmConnector, Farm, NftPosition } from "contracts/interfaces/INftFarmConnector.sol"; import { INonfungiblePositionManager } from "contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol"; struct ShadowAddLiquidityExtraData { int24 tickSpacing; } interface IXShadow { function exit( uint256 amount ) external returns (uint256 exitedAmount); } interface IX33 { function deposit( uint256 assets, address receiver ) external returns (uint256 shares); } contract ShadowV3Connector is UniswapV3Connector { address constant SHADOW = 0x3333b97138D4b086720b5aE8A7844b1345a33333; address constant X_SHADOW = 0x5050bc082FF4A74Fb6B0B04385dEfdDB114b2424; address constant X33 = 0x3333111A391cC08fa51353E9195526A70b333333; // Shadow rewards are in xShadow, which is not transferable. // When claiming, there are two options: // 1. Exit to Shadow (50% penalty) // 2. Deposit into X33 (no penalty) // This function supports both options. If one of the reward tokens is // X33, we deposit the xShadow into X33. Otherwise, we exit to Shadow. function claim( NftPosition calldata position, address[] memory rewardTokens, uint128 amount0Max, uint128 amount1Max, bytes calldata // extraData ) external payable override { bool isX33 = false; address[] memory claimTokens = new address[](rewardTokens.length); for (uint256 i = 0; i < rewardTokens.length; i++) { if (rewardTokens[i] == SHADOW || rewardTokens[i] == X33) { claimTokens[i] = X_SHADOW; if (rewardTokens[i] == X33) { isX33 = true; } } else { claimTokens[i] = rewardTokens[i]; } } try IShadowNonfungiblePositionManager(address(position.nft)).getReward( position.tokenId, claimTokens ) { uint256 rewards = IERC20(X_SHADOW).balanceOf(address(this)); IERC20(X_SHADOW).approve(X33, rewards); if (rewards > 0) { if (isX33) { IX33(X33).deposit(rewards, address(this)); } else { IXShadow(X_SHADOW).exit(rewards); } } } catch { } // Avoid revert for non-gauge pools if (amount0Max != 0 || amount1Max != 0) { IShadowNonfungiblePositionManager.CollectParams memory params = IShadowNonfungiblePositionManager.CollectParams({ tokenId: position.tokenId, recipient: address(this), amount0Max: amount0Max, amount1Max: amount1Max }); IShadowNonfungiblePositionManager(address(position.nft)).collect( params ); } } function ticks( address nftManager, uint256 tokenId ) external view override returns (int24 tickLower, int24 tickUpper) { (,,, tickLower, tickUpper,,,,,) = IShadowNonfungiblePositionManager(nftManager).positions(tokenId); } function _mint( NftAddLiquidity memory addLiquidityParams ) internal override { ShadowAddLiquidityExtraData memory extra = abi.decode( addLiquidityParams.extraData, (ShadowAddLiquidityExtraData) ); IShadowNonfungiblePositionManager.MintParams memory params = IShadowNonfungiblePositionManager.MintParams({ token0: addLiquidityParams.pool.token0, token1: addLiquidityParams.pool.token1, tickSpacing: extra.tickSpacing, tickLower: addLiquidityParams.tickLower, tickUpper: addLiquidityParams.tickUpper, amount0Desired: addLiquidityParams.amount0Desired, amount1Desired: addLiquidityParams.amount1Desired, amount0Min: addLiquidityParams.amount0Min, amount1Min: addLiquidityParams.amount1Min, recipient: address(this), deadline: block.timestamp + 1 }); IShadowNonfungiblePositionManager(address(addLiquidityParams.nft)).mint( params ); } function _get_current_liquidity( NftRemoveLiquidity memory removeLiquidityParams ) internal view override returns (uint128 currentLiquidity) { (,,,,, currentLiquidity,,,,) = IShadowNonfungiblePositionManager( address(removeLiquidityParams.nft) ).positions(removeLiquidityParams.tokenId); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; /// @title Non-fungible token for positions /// @notice Wraps Uniswap V3 positions in a non-fungible token interface which /// allows for them to be transferred /// and authorized. interface IShadowNonfungiblePositionManager { /// @notice Emitted when liquidity is increased for a position NFT /// @dev Also emitted when a token is minted /// @param tokenId The ID of the token for which liquidity was increased /// @param liquidity The amount by which liquidity for the NFT position was /// increased /// @param amount0 The amount of token0 that was paid for the increase in /// liquidity /// @param amount1 The amount of token1 that was paid for the increase in /// liquidity event IncreaseLiquidity( uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); /// @notice Emitted when liquidity is decreased for a position NFT /// @param tokenId The ID of the token for which liquidity was decreased /// @param liquidity The amount by which liquidity for the NFT position was /// decreased /// @param amount0 The amount of token0 that was accounted for the decrease /// in liquidity /// @param amount1 The amount of token1 that was accounted for the decrease /// in liquidity event DecreaseLiquidity( uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); /// @notice Emitted when tokens are collected for a position NFT /// @dev The amounts reported may not be exactly equivalent to the amounts /// transferred, due to rounding behavior /// @param tokenId The ID of the token for which underlying tokens were /// collected /// @param recipient The address of the account that received the collected /// tokens /// @param amount0 The amount of token0 owed to the position that was /// collected /// @param amount1 The amount of token1 owed to the position that was /// collected event Collect( uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1 ); /// @notice Returns the position information associated with a given token /// ID. /// @dev Throws if the token ID is not valid. /// @param tokenId The ID of the token that represents the position /// @return token0 The address of the token0 for a specific pool /// @return token1 The address of the token1 for a specific pool /// @return tickSpacing The tickSpacing the pool /// @return tickLower The lower end of the tick range for the position /// @return tickUpper The higher end of the tick range for the position /// @return liquidity The liquidity of the position /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last /// action on the individual position /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last /// action on the individual position /// @return tokensOwed0 The uncollected amount of token0 owed to the /// position as of the last computation /// @return tokensOwed1 The uncollected amount of token1 owed to the /// position as of the last computation function positions( uint256 tokenId ) external view returns ( address token0, address token1, int24 tickSpacing, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); struct MintParams { address token0; address token1; int24 tickSpacing; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } /// @notice Creates a new position wrapped in a NFT /// @dev Call this when the pool does exist and is initialized. Note that if /// the pool is created but not initialized /// a method does not exist, i.e. the pool is assumed to be initialized. /// @param params The params necessary to mint a position, encoded as /// `MintParams` in calldata /// @return tokenId The ID of the token that represents the minted position /// @return liquidity The amount of liquidity for this position /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function mint( MintParams calldata params ) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Increases the amount of liquidity in a position, with tokens /// paid by the `msg.sender` /// @param params tokenId The ID of the token for which liquidity is being /// increased, /// amount0Desired The desired amount of token0 to be spent, /// amount1Desired The desired amount of token1 to be spent, /// amount0Min The minimum amount of token0 to spend, which serves as a /// slippage check, /// amount1Min The minimum amount of token1 to spend, which serves as a /// slippage check, /// deadline The time by which the transaction must be included to effect /// the change /// @return liquidity The new liquidity amount as a result of the increase /// @return amount0 The amount of token0 to acheive resulting liquidity /// @return amount1 The amount of token1 to acheive resulting liquidity function increaseLiquidity( IncreaseLiquidityParams calldata params ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1); struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Decreases the amount of liquidity in a position and accounts it /// to the position /// @param params tokenId The ID of the token for which liquidity is being /// decreased, /// amount The amount by which liquidity will be decreased, /// amount0Min The minimum amount of token0 that should be accounted for the /// burned liquidity, /// amount1Min The minimum amount of token1 that should be accounted for the /// burned liquidity, /// deadline The time by which the transaction must be included to effect /// the change /// @return amount0 The amount of token0 accounted to the position's tokens /// owed /// @return amount1 The amount of token1 accounted to the position's tokens /// owed function decreaseLiquidity( DecreaseLiquidityParams calldata params ) external payable returns (uint256 amount0, uint256 amount1); struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } /// @notice Collects up to a maximum amount of fees owed to a specific /// position to the recipient /// @param params tokenId The ID of the NFT for which tokens are being /// collected, /// recipient The account that should receive the tokens, /// amount0Max The maximum amount of token0 to collect, /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect( CollectParams calldata params ) external payable returns (uint256 amount0, uint256 amount1); /// @notice Burns a token ID, which deletes it from the NFT contract. The /// token must have 0 liquidity and all tokens /// must be collected first. /// @param tokenId The ID of the token that is being burned function burn( uint256 tokenId ) external payable; /// @notice Claims gauge rewards from liquidity incentives for a specific /// tokenId /// @param tokenId The ID of the token to claim rewards from /// @param tokens an array of reward tokens to claim function getReward(uint256 tokenId, address[] calldata tokens) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { INftLiquidityConnector, NftAddLiquidity, NftRemoveLiquidity, SwapParams } from "contracts/interfaces/INftLiquidityConnector.sol"; import "contracts/interfaces/external/aerodrome/ISlipstreamNonfungiblePositionManager.sol"; import { UniswapV3Connector } from "contracts/connectors/UniswapV3Connector.sol"; import { IUniswapV3Pool } from "contracts/interfaces/external/uniswap/IUniswapV3Pool.sol"; import { IPool } from "contracts/interfaces/external/aerodrome/IPool.sol"; struct SlipstreamAddLiquidityExtraData { int24 tickSpacing; } contract SlipstreamNftConnector is UniswapV3Connector { error Unsupported(); function swapExactTokensForTokens( SwapParams memory ) external payable override { revert Unsupported(); } function _mint( NftAddLiquidity memory addLiquidityParams ) internal override { SlipstreamAddLiquidityExtraData memory extra = abi.decode( addLiquidityParams.extraData, (SlipstreamAddLiquidityExtraData) ); ISlipstreamNonfungiblePositionManager.MintParams memory params = ISlipstreamNonfungiblePositionManager.MintParams({ token0: addLiquidityParams.pool.token0, token1: addLiquidityParams.pool.token1, tickSpacing: extra.tickSpacing, tickLower: addLiquidityParams.tickLower, tickUpper: addLiquidityParams.tickUpper, amount0Desired: addLiquidityParams.amount0Desired, amount1Desired: addLiquidityParams.amount1Desired, amount0Min: addLiquidityParams.amount0Min, amount1Min: addLiquidityParams.amount1Min, recipient: address(this), deadline: block.timestamp + 1, sqrtPriceX96: 0 }); ISlipstreamNonfungiblePositionManager(address(addLiquidityParams.nft)) .mint(params); } function tick( address pool ) external view virtual override returns (int24 result) { (, result,,,,) = IPool(pool).slot0(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; import { NftAddLiquidity, NftRemoveLiquidity } from "contracts/structs/NftLiquidityStructs.sol"; interface INftLiquidityConnector { function addLiquidity( NftAddLiquidity memory addLiquidityParams ) external payable; function removeLiquidity( NftRemoveLiquidity memory removeLiquidityParams ) external; function swapExactTokensForTokens( SwapParams memory swap ) external payable; function fee( address pool ) external view returns (uint24); function tickSpacing( address pool ) external view returns (uint24); function tick( address pool ) external view returns (int24); function ticks( address nftManager, uint256 tokenId ) external view returns (int24 tickLower, int24 tickUpper); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { INonfungiblePositionManager } from "contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol"; import { Farm } from "contracts/structs/FarmStrategyStructs.sol"; import { NftPosition } from "contracts/structs/NftFarmStrategyStructs.sol"; interface INftFarmConnector { function depositExistingNft( NftPosition calldata position, bytes calldata extraData ) external payable; function withdrawNft( NftPosition calldata position, bytes calldata extraData ) external payable; // Payable in case an NFT is withdrawn to be increased with ETH function claim( NftPosition calldata position, address[] memory rewardTokens, uint128 maxAmount0, // For collecting uint128 maxAmount1, bytes calldata extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC721Enumerable } from "openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol"; interface INonfungiblePositionManager is IERC721Enumerable { struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } function increaseLiquidity(IncreaseLiquidityParams memory params) external payable returns (uint256 amount0, uint256 amount1, uint256 liquidity); function decreaseLiquidity(DecreaseLiquidityParams calldata params) external payable returns (uint256 amount0, uint256 amount1); function mint(MintParams memory params) external payable returns (uint256 tokenId, uint256 amount0, uint256 amount1); function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); function burn(uint256 tokenId) external payable; function positions(uint256 tokenId) external view returns ( uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import { IERC721Metadata } from "@openzeppelin/contracts/interfaces/IERC721Metadata.sol"; import { IERC721Enumerable } from "@openzeppelin/contracts/interfaces/IERC721Enumerable.sol"; /// @title Non-fungible token for positions /// @notice Wraps CL positions in a non-fungible token interface which allows /// for them to be transferred /// and authorized. interface ISlipstreamNonfungiblePositionManager is IERC721Metadata, IERC721Enumerable { /// @notice Emitted when liquidity is increased for a position NFT /// @dev Also emitted when a token is minted /// @param tokenId The ID of the token for which liquidity was increased /// @param liquidity The amount by which liquidity for the NFT position was /// increased /// @param amount0 The amount of token0 that was paid for the increase in /// liquidity /// @param amount1 The amount of token1 that was paid for the increase in /// liquidity event IncreaseLiquidity( uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); /// @notice Emitted when liquidity is decreased for a position NFT /// @param tokenId The ID of the token for which liquidity was decreased /// @param liquidity The amount by which liquidity for the NFT position was /// decreased /// @param amount0 The amount of token0 that was accounted for the decrease /// in liquidity /// @param amount1 The amount of token1 that was accounted for the decrease /// in liquidity event DecreaseLiquidity( uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); /// @notice Emitted when tokens are collected for a position NFT /// @dev The amounts reported may not be exactly equivalent to the amounts /// transferred, due to rounding behavior /// @param tokenId The ID of the token for which underlying tokens were /// collected /// @param recipient The address of the account that received the collected /// tokens /// @param amount0 The amount of token0 owed to the position that was /// collected /// @param amount1 The amount of token1 owed to the position that was /// collected event Collect( uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1 ); /// @notice Emitted when a new Token Descriptor is set /// @param tokenDescriptor Address of the new Token Descriptor event TokenDescriptorChanged(address indexed tokenDescriptor); /// @notice Emitted when a new Owner is set /// @param owner Address of the new Owner event TransferOwnership(address indexed owner); /// @notice Returns the position information associated with a given token /// ID. /// @dev Throws if the token ID is not valid. /// @param tokenId The ID of the token that represents the position /// @return nonce The nonce for permits /// @return operator The address that is approved for spending /// @return token0 The address of the token0 for a specific pool /// @return token1 The address of the token1 for a specific pool /// @return tickSpacing The tick spacing associated with the pool /// @return tickLower The lower end of the tick range for the position /// @return tickUpper The higher end of the tick range for the position /// @return liquidity The liquidity of the position /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last /// action on the individual position /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last /// action on the individual position /// @return tokensOwed0 The uncollected amount of token0 owed to the /// position as of the last computation /// @return tokensOwed1 The uncollected amount of token1 owed to the /// position as of the last computation 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 ); /// @notice Returns the address of the Token Descriptor, that handles /// generating token URIs for Positions function tokenDescriptor() external view returns (address); /// @notice Returns the address of the Owner, that is allowed to set a new /// TokenDescriptor function owner() external view returns (address); 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 sqrtPriceX96; } /// @notice Creates a new position wrapped in a NFT /// @dev Call this when the pool does exist and is initialized. Note that if /// the pool is created but not initialized /// a method does not exist, i.e. the pool is assumed to be initialized. /// @param params The params necessary to mint a position, encoded as /// `MintParams` in calldata /// @return tokenId The ID of the token that represents the minted position /// @return liquidity The amount of liquidity for this position /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function mint(MintParams calldata params) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Increases the amount of liquidity in a position, with tokens /// paid by the `msg.sender` /// @param params tokenId The ID of the token for which liquidity is being /// increased, /// amount0Desired The desired amount of token0 to be spent, /// amount1Desired The desired amount of token1 to be spent, /// amount0Min The minimum amount of token0 to spend, which serves as a /// slippage check, /// amount1Min The minimum amount of token1 to spend, which serves as a /// slippage check, /// deadline The time by which the transaction must be included to effect /// the change /// @return liquidity The new liquidity amount as a result of the increase /// @return amount0 The amount of token0 to acheive resulting liquidity /// @return amount1 The amount of token1 to acheive resulting liquidity function increaseLiquidity(IncreaseLiquidityParams calldata params) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1); struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } /// @notice Decreases the amount of liquidity in a position and accounts it /// to the position /// @param params tokenId The ID of the token for which liquidity is being /// decreased, /// amount The amount by which liquidity will be decreased, /// amount0Min The minimum amount of token0 that should be accounted for the /// burned liquidity, /// amount1Min The minimum amount of token1 that should be accounted for the /// burned liquidity, /// deadline The time by which the transaction must be included to effect /// the change /// @return amount0 The amount of token0 accounted to the position's tokens /// owed /// @return amount1 The amount of token1 accounted to the position's tokens /// owed /// @dev The use of this function can cause a loss to users of the /// NonfungiblePositionManager /// @dev for tokens that have very high decimals. /// @dev The amount of tokens necessary for the loss is: 3.4028237e+38. /// @dev This is equivalent to 1e20 value with 18 decimals. function decreaseLiquidity(DecreaseLiquidityParams calldata params) external payable returns (uint256 amount0, uint256 amount1); struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } /// @notice Collects up to a maximum amount of fees owed to a specific /// position to the recipient /// @notice Used to update staked positions before deposit and withdraw /// @param params tokenId The ID of the NFT for which tokens are being /// collected, /// recipient The account that should receive the tokens, /// amount0Max The maximum amount of token0 to collect, /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); /// @notice Burns a token ID, which deletes it from the NFT contract. The /// token must have 0 liquidity and all tokens /// must be collected first. /// @param tokenId The ID of the token that is being burned function burn(uint256 tokenId) external payable; /// @notice Sets a new Token Descriptor /// @param _tokenDescriptor Address of the new Token Descriptor to be chosen function setTokenDescriptor(address _tokenDescriptor) external; /// @notice Sets a new Owner address /// @param _owner Address of the new Owner to be chosen function setOwner(address _owner) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { INonfungiblePositionManager } from "contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol"; import { ISwapRouter } from "contracts/interfaces/external/uniswap/ISwapRouter.sol"; import { IUniswapV3Pool, IUniswapV3PoolState } from "contracts/interfaces/external/uniswap/IUniswapV3Pool.sol"; import { INftFarmConnector } from "contracts/interfaces/INftFarmConnector.sol"; import { INftLiquidityConnector } from "contracts/interfaces/INftLiquidityConnector.sol"; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; import { NftAddLiquidity, NftRemoveLiquidity, Pool } from "contracts/structs/NftLiquidityStructs.sol"; import { Farm } from "contracts/structs/FarmStrategyStructs.sol"; import { NftPosition } from "contracts/structs/NftFarmStrategyStructs.sol"; struct UniswapV3SwapExtraData { address pool; bytes path; } contract UniswapV3Connector is INftLiquidityConnector, INftFarmConnector { error InvalidParameters(); function addLiquidity( NftAddLiquidity memory addLiquidityParams ) external payable override { if (addLiquidityParams.tokenId == 0) { _mint(addLiquidityParams); } else { _increase_liquidity(addLiquidityParams); } } function _get_current_liquidity( NftRemoveLiquidity memory removeLiquidityParams ) internal view virtual returns (uint128 currentLiquidity) { (,,,,,,, currentLiquidity,,,,) = removeLiquidityParams.nft.positions(removeLiquidityParams.tokenId); } function removeLiquidity( NftRemoveLiquidity memory removeLiquidityParams ) external override { uint128 currentLiquidity; if (removeLiquidityParams.liquidity == type(uint128).max) { currentLiquidity = _get_current_liquidity(removeLiquidityParams); removeLiquidityParams.liquidity = currentLiquidity; } if (removeLiquidityParams.liquidity == 0) { revert InvalidParameters(); } _decrease_liquidity(removeLiquidityParams); _collect(removeLiquidityParams); currentLiquidity = _get_current_liquidity(removeLiquidityParams); if (currentLiquidity == 0) { removeLiquidityParams.nft.burn(removeLiquidityParams.tokenId); } } function swapExactTokensForTokens( SwapParams memory swap ) external payable virtual override { UniswapV3SwapExtraData memory extraData = abi.decode(swap.extraData, (UniswapV3SwapExtraData)); IERC20(swap.tokenIn).approve(address(extraData.pool), swap.amountIn); ISwapRouter(swap.router).exactInput( ISwapRouter.ExactInputParams({ path: extraData.path, recipient: address(this), deadline: block.timestamp + 1, amountIn: swap.amountIn, amountOutMinimum: swap.minAmountOut }) ); } function depositExistingNft( NftPosition calldata, // position, bytes calldata // extraData ) external payable virtual override { } function withdrawNft( NftPosition calldata, // position, bytes calldata // extraData ) external payable virtual override { } function claim( NftPosition calldata position, address[] memory, // rewardTokens uint128 amount0Max, uint128 amount1Max, bytes calldata // extraData ) external payable virtual override { _claim_fees(position, amount0Max, amount1Max); } function fee( address pool ) external view virtual override returns (uint24) { return IUniswapV3Pool(pool).fee(); } function tickSpacing( address pool ) external view virtual override returns (uint24) { return uint24(IUniswapV3Pool(pool).tickSpacing()); } // Tick is the 2nd field in slot0, the rest can vary function tick( address pool ) external view virtual override returns (int24 result) { (, result,,,,,) = IUniswapV3Pool(pool).slot0(); } function ticks( address nftManager, uint256 tokenId ) external view virtual override returns (int24 tickLower, int24 tickUpper) { (,,,,, tickLower, tickUpper,,,,,) = INonfungiblePositionManager(nftManager).positions(tokenId); } function _claim_fees( NftPosition calldata position, uint128 amount0Max, uint128 amount1Max ) internal virtual { if (amount0Max > 0 || amount1Max > 0) { INonfungiblePositionManager.CollectParams memory params = INonfungiblePositionManager.CollectParams({ tokenId: position.tokenId, recipient: address(this), amount0Max: amount0Max, amount1Max: amount1Max }); INonfungiblePositionManager(address(position.nft)).collect(params); } } function _mint( NftAddLiquidity memory addLiquidityParams ) internal virtual { addLiquidityParams.nft.mint( INonfungiblePositionManager.MintParams({ token0: addLiquidityParams.pool.token0, token1: addLiquidityParams.pool.token1, fee: addLiquidityParams.pool.fee, tickLower: addLiquidityParams.tickLower, tickUpper: addLiquidityParams.tickUpper, amount0Desired: addLiquidityParams.amount0Desired, amount1Desired: addLiquidityParams.amount1Desired, amount0Min: addLiquidityParams.amount0Min, amount1Min: addLiquidityParams.amount1Min, recipient: address(this), deadline: block.timestamp + 1 }) ); } function _increase_liquidity( NftAddLiquidity memory addLiquidityParams ) internal { addLiquidityParams.nft.increaseLiquidity( INonfungiblePositionManager.IncreaseLiquidityParams({ tokenId: addLiquidityParams.tokenId, amount0Desired: addLiquidityParams.amount0Desired, amount1Desired: addLiquidityParams.amount1Desired, amount0Min: addLiquidityParams.amount0Min, amount1Min: addLiquidityParams.amount1Min, deadline: block.timestamp + 1 }) ); } function _decrease_liquidity( NftRemoveLiquidity memory removeLiquidityParams ) internal { removeLiquidityParams.nft.decreaseLiquidity( INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: removeLiquidityParams.tokenId, liquidity: removeLiquidityParams.liquidity, amount0Min: removeLiquidityParams.amount0Min, amount1Min: removeLiquidityParams.amount1Min, deadline: block.timestamp + 1 }) ); } function _collect( NftRemoveLiquidity memory removeLiquidityParams ) internal { removeLiquidityParams.nft.collect( INonfungiblePositionManager.CollectParams({ tokenId: removeLiquidityParams.tokenId, recipient: address(this), amount0Max: removeLiquidityParams.amount0Max, amount1Max: removeLiquidityParams.amount1Max }) ); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods /// will always return the same values interface IUniswapV3PoolImmutables { /// @notice The contract that deployed the pool, which must adhere to the /// IUniswapV3Factory interface /// @return The contract address function factory() external view returns (address); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (address); /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The fee function fee() external view returns (uint24); /// @notice The pool tick spacing /// @dev Ticks can only be used at multiples of this value, minimum of 1 and /// always positive /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, /// i.e., ..., -6, -3, 0, 3, 6, ... /// This value is an int24 to avoid casting even though it is always /// positive. /// @return The tick spacing function tickSpacing() external view returns (int24); /// @notice The maximum amount of position liquidity that can use any tick /// in the range /// @dev This parameter is enforced per tick to prevent liquidity from /// overflowing a uint128 at any point, and /// also prevents out-of-range liquidity from being used to prevent adding /// in-range liquidity to a pool /// @return The max amount of liquidity per tick function maxLiquidityPerTick() external view returns (uint128); } /// @title Pool state that can change /// @notice These methods compose the pool's state, and can change with any /// frequency including multiple times /// per transaction interface IUniswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is /// exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a /// sqrt(token1/token0) Q64.96 value /// @return tick The current tick of the pool, i.e. according to the last /// tick transition that was run. /// This value may not always be equal to /// SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// @return observationIndex The index of the last oracle observation that /// was written, /// @return observationCardinality The current maximum number of /// observations stored in the pool, /// @return observationCardinalityNext The next maximum number of /// observations, to be updated when the observation. /// @return feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted /// 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap /// fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked ); /// @notice The fee growth as a Q128.128 fees of token0 collected per unit /// of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal0X128() external view returns (uint256); /// @notice The fee growth as a Q128.128 fees of token1 collected per unit /// of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); /// @notice The amounts of token0 and token1 that are owed to the protocol /// @dev Protocol fees will never exceed uint128 max in either token function protocolFees() external view returns (uint128 token0, uint128 token1); /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all /// ticks /// @return The liquidity at the current price of the pool function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses /// the pool either as tick lower or /// tick upper /// @return liquidityNet how much liquidity changes when the pool price /// crosses the tick, /// @return feeGrowthOutside0X128 the fee growth on the other side of the /// tick from the current tick in token0, /// @return feeGrowthOutside1X128 the fee growth on the other side of the /// tick from the current tick in token1, /// @return tickCumulativeOutside the cumulative tick value on the other /// side of the tick from the current tick /// @return secondsPerLiquidityOutsideX128 the seconds spent per liquidity /// on the other side of the tick from the current tick, /// @return secondsOutside the seconds spent on the other side of the tick /// from the current tick, /// @return initialized Set to true if the tick is initialized, i.e. /// liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if /// liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in /// comparison to previous snapshots for /// a specific position. function ticks(int24 tick) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); /// @notice Returns 256 packed tick initialized boolean values. See /// TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the /// owner, tickLower and tickUpper /// @return liquidity The amount of liquidity in the position, /// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick /// range as of the last mint/burn/poke, /// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick /// range as of the last mint/burn/poke, /// @return tokensOwed0 the computed amount of token0 owed to the position /// as of the last mint/burn/poke, /// @return tokensOwed1 the computed amount of token1 owed to the position /// as of the last mint/burn/poke function positions(bytes32 key) external view returns ( uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Returns data about a specific observation index /// @param index The element of the observations array to fetch /// @dev You most likely want to use #observe() instead of this method to /// get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, /// @return tickCumulative the tick multiplied by seconds elapsed for the /// life of the pool as of the observation timestamp, /// @return secondsPerLiquidityCumulativeX128 the seconds per in range /// liquidity for the life of the pool as of the observation timestamp, /// @return initialized whether the observation has been initialized and the /// values are safe to use function observations(uint256 index) external view returns ( uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized ); } interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState { function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IPool { error DepositsNotEqual(); error BelowMinimumK(); error FactoryAlreadySet(); error InsufficientLiquidity(); error InsufficientLiquidityMinted(); error InsufficientLiquidityBurned(); error InsufficientOutputAmount(); error InsufficientInputAmount(); error IsPaused(); error InvalidTo(); error K(); error NotEmergencyCouncil(); event Fees(address indexed sender, uint256 amount0, uint256 amount1); event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn( address indexed sender, address indexed to, uint256 amount0, uint256 amount1 ); event Swap( address indexed sender, address indexed to, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out ); event Sync(uint256 reserve0, uint256 reserve1); event Claim( address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1 ); // Struct to capture time period obervations every 30 minutes, used for // local oracles struct Observation { uint256 timestamp; uint256 reserve0Cumulative; uint256 reserve1Cumulative; } /// @notice The 0th storage slot in the pool stores many values, and is /// exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a /// sqrt(token1/token0) Q64.96 value /// @return tick The current tick of the pool, i.e. according to the last /// tick transition that was run. /// This value may not always be equal to /// SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// @return observationIndex The index of the last oracle observation that /// was written, /// @return observationCardinality The current maximum number of /// observations stored in the pool, /// @return observationCardinalityNext The next maximum number of /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted /// 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap /// fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, bool unlocked ); /// @notice Returns the decimal (dec), reserves (r), stable (st), and tokens /// (t) of token0 and token1 function metadata() external view returns ( uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1 ); /// @notice Claim accumulated but unclaimed fees (claimable0 and claimable1) function claimFees() external returns (uint256, uint256); /// @notice Returns [token0, token1] function tokens() external view returns (address, address); /// @notice Address of token in the pool with the lower address value function token0() external view returns (address); /// @notice Address of token in the poool with the higher address value function token1() external view returns (address); /// @notice Address of linked PoolFees.sol function poolFees() external view returns (address); /// @notice Address of PoolFactory that created this contract function factory() external view returns (address); /// @notice Capture oracle reading every 30 minutes (1800 seconds) function periodSize() external view returns (uint256); /// @notice Amount of token0 in pool function reserve0() external view returns (uint256); /// @notice Amount of token1 in pool function reserve1() external view returns (uint256); /// @notice Timestamp of last update to pool function blockTimestampLast() external view returns (uint256); /// @notice Cumulative of reserve0 factoring in time elapsed function reserve0CumulativeLast() external view returns (uint256); /// @notice Cumulative of reserve1 factoring in time elapsed function reserve1CumulativeLast() external view returns (uint256); /// @notice Accumulated fees of token0 (global) function index0() external view returns (uint256); /// @notice Accumulated fees of token1 (global) function index1() external view returns (uint256); /// @notice Get an LP's relative index0 to index0 function supplyIndex0( address ) external view returns (uint256); /// @notice Get an LP's relative index1 to index1 function supplyIndex1( address ) external view returns (uint256); /// @notice Amount of unclaimed, but claimable tokens from fees of token0 /// for an LP function claimable0( address ) external view returns (uint256); /// @notice Amount of unclaimed, but claimable tokens from fees of token1 /// for an LP function claimable1( address ) external view returns (uint256); /// @notice Returns the value of K in the Pool, based on its reserves. function getK() external returns (uint256); /// @notice Set pool name /// Only callable by Voter.emergencyCouncil() /// @param __name String of new name function setName( string calldata __name ) external; /// @notice Set pool symbol /// Only callable by Voter.emergencyCouncil() /// @param __symbol String of new symbol function setSymbol( string calldata __symbol ) external; /// @notice Get the number of observations recorded function observationLength() external view returns (uint256); /// @notice Get the value of the most recent observation function lastObservation() external view returns (Observation memory); /// @notice True if pool is stable, false if volatile function stable() external view returns (bool); /// @notice Produces the cumulative price using counterfactuals to save gas /// and avoid a call to sync. function currentCumulativePrices() external view returns ( uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp ); /// @notice Provides twap price with user configured granularity, up to the /// full window size /// @param tokenIn . /// @param amountIn . /// @param granularity . /// @return amountOut . function quote( address tokenIn, uint256 amountIn, uint256 granularity ) external view returns (uint256 amountOut); /// @notice Returns a memory set of TWAP prices /// Same as calling sample(tokenIn, amountIn, points, 1) /// @param tokenIn . /// @param amountIn . /// @param points Number of points to return /// @return Array of TWAP prices function prices( address tokenIn, uint256 amountIn, uint256 points ) external view returns (uint256[] memory); /// @notice Same as prices with with an additional window argument. /// Window = 2 means 2 * 30min (or 1 hr) between observations /// @param tokenIn . /// @param amountIn . /// @param points . /// @param window . /// @return Array of TWAP prices function sample( address tokenIn, uint256 amountIn, uint256 points, uint256 window ) external view returns (uint256[] memory); /// @notice This low-level function should be called from a contract which /// performs important safety checks /// @param amount0Out Amount of token0 to send to `to` /// @param amount1Out Amount of token1 to send to `to` /// @param to Address to recieve the swapped output /// @param data Additional calldata for flashloans function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; /// @notice This low-level function should be called from a contract which /// performs important safety checks /// standard uniswap v2 implementation /// @param to Address to receive token0 and token1 from burning the pool /// token /// @return amount0 Amount of token0 returned /// @return amount1 Amount of token1 returned function burn( address to ) external returns (uint256 amount0, uint256 amount1); /// @notice This low-level function should be called by addLiquidity /// functions in Router.sol, which performs important safety checks /// standard uniswap v2 implementation /// @param to Address to receive the minted LP token /// @return liquidity Amount of LP token minted function mint( address to ) external returns (uint256 liquidity); /// @notice Update reserves and, on the first call per block, price /// accumulators /// @return _reserve0 . /// @return _reserve1 . /// @return _blockTimestampLast . function getReserves() external view returns ( uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast ); /// @notice Get the amount of tokenOut given the amount of tokenIn /// @param amountIn Amount of token in /// @param tokenIn Address of token /// @return Amount out function getAmountOut( uint256 amountIn, address tokenIn ) external view returns (uint256); /// @notice Force balances to match reserves /// @param to Address to receive any skimmed rewards function skim( address to ) external; /// @notice Force reserves to match balances function sync() external; /// @notice Called on pool creation by PoolFactory /// @param _token0 Address of token0 /// @param _token1 Address of token1 /// @param _stable True if stable, false if volatile function initialize( address _token0, address _token1, bool _stable ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct AddLiquidityParams { address router; address lpToken; address[] tokens; uint256[] desiredAmounts; uint256[] minAmounts; bytes extraData; } struct RemoveLiquidityParams { address router; address lpToken; address[] tokens; uint256 lpAmountIn; uint256[] minAmountsOut; bytes extraData; } struct SwapParams { address router; uint256 amountIn; uint256 minAmountOut; address tokenIn; bytes extraData; } struct GetAmountOutParams { address router; address lpToken; address tokenIn; address tokenOut; uint256 amountIn; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { INonfungiblePositionManager } from "contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol"; struct Pool { address token0; address token1; uint24 fee; } struct NftAddLiquidity { INonfungiblePositionManager nft; uint256 tokenId; Pool pool; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; bytes extraData; } struct NftRemoveLiquidity { INonfungiblePositionManager nft; uint256 tokenId; uint128 liquidity; uint256 amount0Min; // For decreasing uint256 amount1Min; uint128 amount0Max; // For collecting uint128 amount1Max; bytes extraData; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { ZapIn, ZapOut } from "contracts/libraries/ZapLib.sol"; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; struct Farm { address stakingContract; uint256 poolIndex; } struct DepositParams { Farm farm; address[] tokensIn; uint256[] amountsIn; ZapIn zap; bytes extraData; } struct WithdrawParams { bytes extraData; ZapOut zap; address[] tokensOut; } struct HarvestParams { SwapParams[] swaps; bytes extraData; address[] tokensOut; } struct CompoundParams { Farm claimFarm; bytes claimExtraData; address[] rewardTokens; ZapIn zap; Farm depositFarm; bytes depositExtraData; } struct SimpleDepositParams { Farm farm; address lpToken; uint256 amountIn; bytes extraData; } struct SimpleHarvestParams { address[] rewardTokens; bytes extraData; } struct SimpleWithdrawParams { address lpToken; uint256 amountOut; bytes extraData; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { IUniswapV3Pool } from "contracts/interfaces/external/uniswap/IUniswapV3Pool.sol"; import { INonfungiblePositionManager } from "contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol"; import { NftZapIn, NftZapOut } from "contracts/structs/NftZapStructs.sol"; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; import { Farm } from "contracts/structs/FarmStrategyStructs.sol"; struct NftPosition { Farm farm; INonfungiblePositionManager nft; uint256 tokenId; } struct NftIncrease { address[] tokensIn; uint256[] amountsIn; NftZapIn zap; bytes extraData; } struct NftDeposit { Farm farm; INonfungiblePositionManager nft; NftIncrease increase; } struct NftWithdraw { NftZapOut zap; address[] tokensOut; bytes extraData; } struct SimpleNftHarvest { address[] rewardTokens; uint128 amount0Max; uint128 amount1Max; bytes extraData; } struct NftHarvest { SimpleNftHarvest harvest; SwapParams[] swaps; address[] outputTokens; address[] sweepTokens; } struct NftCompound { SimpleNftHarvest harvest; NftZapIn zap; } struct NftRebalance { IUniswapV3Pool pool; NftPosition position; NftHarvest harvest; NftWithdraw withdraw; NftIncrease increase; } struct NftMove { IUniswapV3Pool pool; NftPosition position; NftHarvest harvest; NftWithdraw withdraw; NftDeposit deposit; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721Enumerable.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721Metadata.sol";
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another /// token /// @param params The parameters necessary for the swap, encoded as /// `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another /// along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded /// as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of /// another token /// @param params The parameters necessary for the swap, encoded as /// `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of /// another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded /// as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { SwapParams, AddLiquidityParams } from "contracts/structs/LiquidityStructs.sol"; import { ILiquidityConnector } from "contracts/interfaces/ILiquidityConnector.sol"; import { ConnectorRegistry } from "contracts/ConnectorRegistry.sol"; import { DelegateModule } from "contracts/modules/DelegateModule.sol"; import { ZapIn, ZapOut } from "contracts/structs/ZapStructs.sol"; import { IZapLib } from "contracts/interfaces/libraries/IZapLib.sol"; import { ISwapLib } from "contracts/interfaces/libraries/ISwapLib.sol"; contract ZapLib is DelegateModule, IZapLib { error LiquidityAmountError(); // 0x4d0ab6b4 ISwapLib public immutable swapLib; ConnectorRegistry public immutable connectorRegistry; constructor(ConnectorRegistry connectorRegistry_, ISwapLib swapLib_) { connectorRegistry = connectorRegistry_; swapLib = swapLib_; } function zapIn( ZapIn memory zap ) external payable { uint256 swapDataLength = zap.swaps.length; for (uint256 i; i < swapDataLength;) { _delegateTo( address(swapLib), abi.encodeCall(ISwapLib.swap, (zap.swaps[i])) ); unchecked { i++; } } if (zap.addLiquidityParams.lpToken == address(0)) { return; } bool atLeastOneNonZero = false; AddLiquidityParams memory addLiquidityParams = zap.addLiquidityParams; uint256 addLiquidityParamsTokensLength = addLiquidityParams.tokens.length; for (uint256 i; i < addLiquidityParamsTokensLength; i++) { if (addLiquidityParams.tokens[i] == address(0)) { continue; } if (addLiquidityParams.desiredAmounts[i] == 0) { addLiquidityParams.desiredAmounts[i] = IERC20( addLiquidityParams.tokens[i] ).balanceOf(address(this)); } if (addLiquidityParams.desiredAmounts[i] > 0) { atLeastOneNonZero = true; // In case there is USDT or similar dust approval, revoke it SafeTransferLib.safeApprove( addLiquidityParams.tokens[i], addLiquidityParams.router, 0 ); SafeTransferLib.safeApprove( addLiquidityParams.tokens[i], addLiquidityParams.router, addLiquidityParams.desiredAmounts[i] ); } } if (!atLeastOneNonZero) { revert LiquidityAmountError(); } address routerConnector = connectorRegistry.connectorOf(addLiquidityParams.router); _delegateTo( routerConnector, abi.encodeCall( ILiquidityConnector.addLiquidity, (addLiquidityParams) ) ); for (uint256 i; i < addLiquidityParamsTokensLength;) { if (addLiquidityParams.tokens[i] != address(0)) { // Revoke any dust approval in case the amount was estimated SafeTransferLib.safeApprove( addLiquidityParams.tokens[i], addLiquidityParams.router, 0 ); } unchecked { i++; } } } function zapOut( ZapOut memory zap ) external { if (zap.removeLiquidityParams.lpToken != address(0)) { if (zap.removeLiquidityParams.lpAmountIn > 0) { SafeTransferLib.safeApprove( zap.removeLiquidityParams.lpToken, zap.removeLiquidityParams.router, zap.removeLiquidityParams.lpAmountIn ); } address routerConnector = connectorRegistry.connectorOf(zap.removeLiquidityParams.router); _delegateTo( address(routerConnector), abi.encodeCall( ILiquidityConnector.removeLiquidity, zap.removeLiquidityParams ) ); } uint256 swapDataLength = zap.swaps.length; for (uint256 i; i < swapDataLength;) { _delegateTo( address(swapLib), abi.encodeCall(ISwapLib.swap, (zap.swaps[i])) ); unchecked { i++; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; import { NftAddLiquidity, NftRemoveLiquidity } from "contracts/structs/NftLiquidityStructs.sol"; struct NftZapIn { SwapParams[] swaps; NftAddLiquidity addLiquidityParams; } struct NftZapOut { NftRemoveLiquidity removeLiquidityParams; SwapParams[] swaps; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// 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. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error ETHTransferFailed(); error TransferFromFailed(); error TransferFailed(); error ApproveFailed(); /*////////////////////////////////////////////////////////////// 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) } if (!success) revert ETHTransferFailed(); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( address 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), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // 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. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // 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. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } if (!success) revert TransferFromFailed(); } function safeTransfer( address 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), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // 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. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // 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. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } if (!success) revert TransferFailed(); } function safeApprove( address 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), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // 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. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // 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. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } if (!success) revert ApproveFailed(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { AddLiquidityParams, RemoveLiquidityParams, SwapParams, GetAmountOutParams } from "contracts/structs/LiquidityStructs.sol"; interface ILiquidityConnector { function addLiquidity( AddLiquidityParams memory addLiquidityParams ) external payable; function removeLiquidity( RemoveLiquidityParams memory removeLiquidityParams ) external; function swapExactTokensForTokens( SwapParams memory swap ) external payable; function getAmountOut( GetAmountOutParams memory getAmountOutParams ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { Admin } from "contracts/base/Admin.sol"; import { TimelockAdmin } from "contracts/base/TimelockAdmin.sol"; error ConnectorNotRegistered(address target); interface ICustomConnectorRegistry { function connectorOf(address target) external view returns (address); } contract ConnectorRegistry is Admin, TimelockAdmin { event ConnectorChanged(address target, address connector); event CustomRegistryAdded(address registry); event CustomRegistryRemoved(address registry); error ConnectorAlreadySet(address target); error ConnectorNotSet(address target); ICustomConnectorRegistry[] public customRegistries; mapping(ICustomConnectorRegistry => bool) public isCustomRegistry; mapping(address target => address connector) private connectors_; constructor( address admin_, address timelockAdmin_ ) Admin(admin_) TimelockAdmin(timelockAdmin_) { } /// @notice Update connector addresses for a batch of targets. /// @dev Controls which connector contracts are used for the specified /// targets. /// @custom:access Restricted to protocol admin. function setConnectors( address[] calldata targets, address[] calldata connectors ) external onlyAdmin { for (uint256 i; i != targets.length;) { if (connectors_[targets[i]] != address(0)) { revert ConnectorAlreadySet(targets[i]); } connectors_[targets[i]] = connectors[i]; emit ConnectorChanged(targets[i], connectors[i]); unchecked { ++i; } } } function updateConnectors( address[] calldata targets, address[] calldata connectors ) external onlyTimelockAdmin { for (uint256 i; i != targets.length;) { if (connectors_[targets[i]] == address(0)) { revert ConnectorNotSet(targets[i]); } connectors_[targets[i]] = connectors[i]; emit ConnectorChanged(targets[i], connectors[i]); unchecked { ++i; } } } /// @notice Append an address to the custom registries list. /// @custom:access Restricted to protocol admin. function addCustomRegistry(ICustomConnectorRegistry registry) external onlyAdmin { customRegistries.push(registry); isCustomRegistry[registry] = true; emit CustomRegistryAdded(address(registry)); } /// @notice Replace an address in the custom registries list. /// @custom:access Restricted to protocol admin. function updateCustomRegistry( uint256 index, ICustomConnectorRegistry newRegistry ) external onlyTimelockAdmin { address oldRegistry = address(customRegistries[index]); isCustomRegistry[customRegistries[index]] = false; emit CustomRegistryRemoved(oldRegistry); customRegistries[index] = newRegistry; isCustomRegistry[newRegistry] = true; if (address(newRegistry) != address(0)) { emit CustomRegistryAdded(address(newRegistry)); } } function connectorOf(address target) external view returns (address) { address connector = connectors_[target]; if (connector != address(0)) { return connector; } uint256 length = customRegistries.length; for (uint256 i; i != length;) { if (address(customRegistries[i]) != address(0)) { try customRegistries[i].connectorOf(target) returns ( address _connector ) { if (_connector != address(0)) { return _connector; } } catch { // Ignore } } unchecked { ++i; } } revert ConnectorNotRegistered(target); } function hasConnector(address target) external view returns (bool) { if (connectors_[target] != address(0)) { return true; } uint256 length = customRegistries.length; for (uint256 i; i != length;) { if (address(customRegistries[i]) != address(0)) { try customRegistries[i].connectorOf(target) returns ( address _connector ) { if (_connector != address(0)) { return true; } } catch { // Ignore } unchecked { ++i; } } } return false; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; contract DelegateModule { function _delegateTo( address to, bytes memory data ) internal returns (bytes memory) { (bool success, bytes memory result) = to.delegatecall(data); if (!success) { if (result.length == 0) revert(); assembly { revert(add(32, result), mload(result)) } } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SwapParams, AddLiquidityParams, RemoveLiquidityParams } from "contracts/structs/LiquidityStructs.sol"; struct ZapIn { SwapParams[] swaps; AddLiquidityParams addLiquidityParams; } struct ZapOut { RemoveLiquidityParams removeLiquidityParams; SwapParams[] swaps; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { ZapIn, ZapOut } from "contracts/structs/ZapStructs.sol"; interface IZapLib { function zapIn( ZapIn memory zap ) external payable; function zapOut( ZapOut memory zap ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SwapParams } from "contracts/structs/LiquidityStructs.sol"; interface ISwapLib { function swap( SwapParams memory swap ) external payable; function swapMultiple( SwapParams[] memory swaps ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// 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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /// @title Admin contract /// @author vfat.tools /// @notice Provides an administration mechanism allowing restricted functions abstract contract Admin { /// ERRORS /// /// @notice Thrown when the caller is not the admin error NotAdminError(); //0xb5c42b3b /// EVENTS /// /// @notice Emitted when a new admin is set /// @param oldAdmin Address of the old admin /// @param newAdmin Address of the new admin event AdminSet(address oldAdmin, address newAdmin); /// STORAGE /// /// @notice Address of the current admin address public admin; /// MODIFIERS /// /// @dev Restricts a function to the admin modifier onlyAdmin() { if (msg.sender != admin) revert NotAdminError(); _; } /// WRITE FUNCTIONS /// /// @param admin_ Address of the admin constructor(address admin_) { emit AdminSet(admin, admin_); admin = admin_; } /// @notice Sets a new admin /// @param newAdmin Address of the new admin /// @custom:access Restricted to protocol admin. function setAdmin(address newAdmin) external onlyAdmin { emit AdminSet(admin, newAdmin); admin = newAdmin; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /// @title TimelockAdmin contract /// @author vfat.tools /// @notice Provides an timelockAdministration mechanism allowing restricted /// functions abstract contract TimelockAdmin { /// ERRORS /// /// @notice Thrown when the caller is not the timelockAdmin error NotTimelockAdminError(); /// EVENTS /// /// @notice Emitted when a new timelockAdmin is set /// @param oldTimelockAdmin Address of the old timelockAdmin /// @param newTimelockAdmin Address of the new timelockAdmin event TimelockAdminSet(address oldTimelockAdmin, address newTimelockAdmin); /// STORAGE /// /// @notice Address of the current timelockAdmin address public timelockAdmin; /// MODIFIERS /// /// @dev Restricts a function to the timelockAdmin modifier onlyTimelockAdmin() { if (msg.sender != timelockAdmin) revert NotTimelockAdminError(); _; } /// WRITE FUNCTIONS /// /// @param timelockAdmin_ Address of the timelockAdmin constructor(address timelockAdmin_) { emit TimelockAdminSet(timelockAdmin, timelockAdmin_); timelockAdmin = timelockAdmin_; } /// @notice Sets a new timelockAdmin /// @dev Can only be called by the current timelockAdmin /// @param newTimelockAdmin Address of the new timelockAdmin function setTimelockAdmin(address newTimelockAdmin) external onlyTimelockAdmin { emit TimelockAdminSet(timelockAdmin, newTimelockAdmin); timelockAdmin = newTimelockAdmin; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "solmate/=lib/solmate/src/", "@openzeppelin/=lib/openzeppelin-contracts/", "@uniswap/v3-periphery/=lib/v3-periphery/", "@uniswap/v3-core/=lib/v3-core/", "@morpho-blue/=lib/morpho-blue/src/", "ds-test/=lib/solmate/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "morpho-blue/=lib/morpho-blue/", "openzeppelin-contracts/=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": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"InvalidParameters","type":"error"},{"inputs":[{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"internalType":"struct Pool","name":"pool","type":"tuple"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftAddLiquidity","name":"addLiquidityParams","type":"tuple"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition","name":"position","type":"tuple"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"depositExistingNft","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"fee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftRemoveLiquidity","name":"removeLiquidityParams","type":"tuple"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams","name":"swap","type":"tuple"}],"name":"swapExactTokensForTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"tick","outputs":[{"internalType":"int24","name":"result","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"tickSpacing","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftManager","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ticks","outputs":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"withdrawNft","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50611bf8806100206000396000f3fe6080604052600436106100915760003560e01c806380cc71f21161005957806380cc71f21461013d578063cce9480114610177578063d7dd162e14610197578063ff781feb146101b7578063ff7b9266146100ab57600080fd5b806304caab47146100965780632847ccf2146100ab5780636f4621e3146100be5780636fcca69b146100d1578063803347361461010a575b600080fd5b6100a96100a4366004611163565b6101ca565b005b6100a96100b93660046112ad565b505050565b6100a96100cc366004611320565b6101eb565b3480156100dd57600080fd5b506100f16100ec366004611432565b610727565b60405162ffffff90911681526020015b60405180910390f35b34801561011657600080fd5b5061012a610125366004611432565b610791565b60405160029190910b8152602001610101565b34801561014957600080fd5b5061015d610158366004611456565b610802565b60408051600293840b81529190920b602082015201610101565b34801561018357600080fd5b506100a9610192366004611482565b610885565b3480156101a357600080fd5b506100f16101b2366004611432565b610988565b6100a96101c5366004611551565b6109ec565b80602001516000036101e2576101df81610b37565b50565b6101df81610c7a565b60008086516001600160401b0381111561020757610207610f4b565b604051908082528060200260200182016040528015610230578160200160208202803683370190505b50905060005b87518110156103c557733333b97138d4b086720b5ae8a7844b1345a333336001600160a01b031688828151811061026f5761026f6115f9565b60200260200101516001600160a01b031614806102ca5750733333111a391cc08fa51353e9195526a70b3333336001600160a01b03168882815181106102b7576102b76115f9565b60200260200101516001600160a01b0316145b1561036657735050bc082ff4a74fb6b0b04385defddb114b24248282815181106102f6576102f66115f9565b60200260200101906001600160a01b031690816001600160a01b031681525050733333111a391cc08fa51353e9195526a70b3333336001600160a01b0316888281518110610346576103466115f9565b60200260200101516001600160a01b03160361036157600192505b6103b3565b878181518110610378576103786115f9565b6020026020010151828281518110610392576103926115f9565b60200260200101906001600160a01b031690816001600160a01b0316815250505b806103bd81611625565b915050610236565b506103d66060890160408a01611432565b6001600160a01b031663f5f8d3658960600135836040518363ffffffff1660e01b815260040161040792919061163e565b600060405180830381600087803b15801561042157600080fd5b505af1925050508015610432575060015b15610649576040516370a0823160e01b8152306004820152600090735050bc082ff4a74fb6b0b04385defddb114b2424906370a0823190602401602060405180830381865afa158015610489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ad9190611695565b60405163095ea7b360e01b8152733333111a391cc08fa51353e9195526a70b333333600482015260248101829052909150735050bc082ff4a74fb6b0b04385defddb114b24249063095ea7b3906044016020604051808303816000875af115801561051c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054091906116be565b5080156106475782156105cf57604051636e553f6560e01b815260048101829052306024820152733333111a391cc08fa51353e9195526a70b33333390636e553f65906044016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c99190611695565b50610647565b604051637f8661a160e01b815260048101829052735050bc082ff4a74fb6b0b04385defddb114b242490637f8661a1906024016020604051808303816000875af1158015610621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106459190611695565b505b505b6001600160801b03861615158061066857506001600160801b03851615155b1561071d57604080516080810182526060808b01803583523060208401526001600160801b03808b168486015289169183019190915290916106ac91908b01611432565b6001600160a01b031663fc6f7865826040518263ffffffff1660e01b81526004016106d791906116d9565b60408051808303816000875af11580156106f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610719919061171d565b5050505b5050505050505050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078b9190611741565b92915050565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156107d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f59190611770565b5093979650505050505050565b60405163133f757160e31b81526004810182905260009081906001600160a01b038516906399fbab889060240161014060405180830381865afa15801561084d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108719190611803565b50949c939b50929950505050505050505050565b60006001600160801b03801682604001516001600160801b0316036108bf576108ad82610d74565b6001600160801b038116604084015290505b81604001516001600160801b03166000036108ed57604051630e52390960e41b815260040160405180910390fd5b6108f682610df8565b6108ff82610ee9565b61090882610d74565b9050806001600160801b03166000036109845781516020830151604051630852cd8d60e31b81526001600160a01b03909216916342966c68916109519160040190815260200190565b600060405180830381600087803b15801561096b57600080fd5b505af115801561097f573d6000803e3d6000fd5b505050505b5050565b6000816001600160a01b031663d0c93a7c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078b91906118c9565b60008160800151806020019051810190610a06919061190a565b60608301518151602085015160405163095ea7b360e01b81526001600160a01b0392831660048201526024810191909152929350169063095ea7b3906044016020604051808303816000875af1158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8891906116be565b5081516040805160a081018252602080850151825230908201526001600160a01b039092169163c04b8d59918101610ac14260016119c7565b81526020018560200151815260200185604001518152506040518263ffffffff1660e01b8152600401610af491906119da565b6020604051808303816000875af1158015610b13573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b99190611695565b6000816101200151806020019051810190610b529190611a49565b905060006040518061016001604052808460400151600001516001600160a01b031681526020018460400151602001516001600160a01b03168152602001836000015160020b8152602001846060015160020b8152602001846080015160020b81526020018460a0015181526020018460c0015181526020018460e0015181526020018461010001518152602001306001600160a01b03168152602001426001610bfc91906119c7565b90528351604051636d70c41560e01b81529192506001600160a01b031690636d70c41590610c2e908490600401611a94565b6080604051808303816000875af1158015610c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c719190611b56565b50505050505050565b80600001516001600160a01b031663219f5d176040518060c00160405280846020015181526020018460a0015181526020018460c0015181526020018460e0015181526020018461010001518152602001426001610cd891906119c7565b9052604080516001600160e01b031960e085901b1681528251600482015260208301516024820152908201516044820152606082015160648201526080820151608482015260a09091015160a482015260c4016060604051808303816000875af1158015610d4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6e9190611b94565b50505050565b8051602082015160405163133f757160e31b815260048101919091526000916001600160a01b0316906399fbab889060240161014060405180830381865afa158015610dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de89190611803565b50929a9950505050505050505050565b80600001516001600160a01b0316630c49ccbe6040518060a001604052808460200151815260200184604001516001600160801b031681526020018460600151815260200184608001518152602001426001610e5491906119c7565b9052604080516001600160e01b031960e085901b1681528251600482015260208301516001600160801b0316602482015290820151604482015260608201516064820152608090910151608482015260a4015b60408051808303816000875af1158015610ec5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b9919061171d565b8051604080516080810182526020808501518252309082015260a08401516001600160801b039081168284015260c0850151166060820152905163fc6f786560e01b81526001600160a01b039092169163fc6f786591610ea7916004016116d9565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715610f8457610f84610f4b565b60405290565b60405161010081016001600160401b0381118282101715610f8457610f84610f4b565b60405160a081016001600160401b0381118282101715610f8457610f84610f4b565b604080519081016001600160401b0381118282101715610f8457610f84610f4b565b604051601f8201601f191681016001600160401b038111828210171561101957611019610f4b565b604052919050565b6001600160a01b03811681146101df57600080fd5b803561104181611021565b919050565b62ffffff811681146101df57600080fd5b60006060828403121561106957600080fd5b604051606081018181106001600160401b038211171561108b5761108b610f4b565b604052905080823561109c81611021565b815260208301356110ac81611021565b602082015260408301356110bf81611046565b6040919091015292915050565b8060020b81146101df57600080fd5b8035611041816110cc565b60006001600160401b038211156110ff576110ff610f4b565b50601f01601f191660200190565b600082601f83011261111e57600080fd5b813561113161112c826110e6565b610ff1565b81815284602083860101111561114657600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561117557600080fd5b81356001600160401b038082111561118c57600080fd5b9083019061018082860312156111a157600080fd5b6111a9610f61565b6111b283611036565b8152602083013560208201526111cb8660408501611057565b60408201526111dc60a084016110db565b60608201526111ed60c084016110db565b608082015260e083013560a08201526101008084013560c08301526101208085013560e08401526101408501358284015261016085013591508382111561123357600080fd5b61123f8883870161110d565b908301525095945050505050565b60006080828403121561125f57600080fd5b50919050565b60008083601f84011261127757600080fd5b5081356001600160401b0381111561128e57600080fd5b6020830191508360208285010111156112a657600080fd5b9250929050565b600080600060a084860312156112c257600080fd5b6112cc858561124d565b925060808401356001600160401b038111156112e757600080fd5b6112f386828701611265565b9497909650939450505050565b6001600160801b03811681146101df57600080fd5b803561104181611300565b600080600080600080610100878903121561133a57600080fd5b611344888861124d565b955060808701356001600160401b038082111561136057600080fd5b818901915089601f83011261137457600080fd5b813560208282111561138857611388610f4b565b8160051b611397828201610ff1565b928352848101820192828101908e8511156113b157600080fd5b958301955b848710156113db57863592506113cb83611021565b82825295830195908301906113b6565b809b5050505050506113ef60a08a01611315565b95506113fd60c08a01611315565b945060e089013591508082111561141357600080fd5b5061142089828a01611265565b979a9699509497509295939492505050565b60006020828403121561144457600080fd5b813561144f81611021565b9392505050565b6000806040838503121561146957600080fd5b823561147481611021565b946020939093013593505050565b60006020828403121561149457600080fd5b81356001600160401b03808211156114ab57600080fd5b9083019061010082860312156114c057600080fd5b6114c8610f8a565b6114d183611036565b8152602083013560208201526114e960408401611315565b6040820152606083013560608201526080830135608082015261150e60a08401611315565b60a082015261151f60c08401611315565b60c082015260e08301358281111561153657600080fd5b6115428782860161110d565b60e08301525095945050505050565b60006020828403121561156357600080fd5b81356001600160401b038082111561157a57600080fd5b9083019060a0828603121561158e57600080fd5b611596610fad565b82356115a181611021565b80825250602083013560208201526040830135604082015260608301356115c781611021565b60608201526080830135828111156115de57600080fd5b6115ea8782860161110d565b60808301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016116375761163761160f565b5060010190565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156116885784516001600160a01b031683529383019391830191600101611663565b5090979650505050505050565b6000602082840312156116a757600080fd5b5051919050565b8051801515811461104157600080fd5b6000602082840312156116d057600080fd5b61144f826116ae565b6080810161078b8284805182526020808201516001600160a01b0316908301526040808201516001600160801b039081169184019190915260609182015116910152565b6000806040838503121561173057600080fd5b505080516020909101519092909150565b60006020828403121561175357600080fd5b815161144f81611046565b805161ffff8116811461104157600080fd5b600080600080600080600060e0888a03121561178b57600080fd5b875161179681611021565b60208901519097506117a7816110cc565b95506117b56040890161175e565b94506117c36060890161175e565b93506117d16080890161175e565b925060a088015160ff811681146117e757600080fd5b91506117f560c089016116ae565b905092959891949750929550565b6000806000806000806000806000806101408b8d03121561182357600080fd5b8a5161182e81611021565b60208c0151909a5061183f81611021565b60408c0151909950611850816110cc565b60608c0151909850611861816110cc565b60808c0151909750611872816110cc565b60a08c015190965061188381611300565b8095505060c08b0151935060e08b015192506101008b01516118a481611300565b6101208c01519092506118b681611300565b809150509295989b9194979a5092959850565b6000602082840312156118db57600080fd5b815161144f816110cc565b60005b838110156119015781810151838201526020016118e9565b50506000910152565b6000602080838503121561191d57600080fd5b82516001600160401b038082111561193457600080fd5b908401906040828703121561194857600080fd5b611950610fcf565b825161195b81611021565b8152828401518281111561196e57600080fd5b80840193505086601f84011261198357600080fd5b8251915061199361112c836110e6565b82815287858486010111156119a757600080fd5b6119b6838683018787016118e6565b938101939093525090949350505050565b8082018082111561078b5761078b61160f565b602081526000825160a0602084015280518060c0850152611a028160e08601602085016118e6565b60018060a01b0360208601511660408501526040850151606085015260608501516080850152608085015160a085015260e0601f19601f8301168501019250505092915050565b600060208284031215611a5b57600080fd5b604051602081018181106001600160401b0382111715611a7d57611a7d610f4b565b6040528251611a8b816110cc565b81529392505050565b81516001600160a01b0316815261016081016020830151611ac060208401826001600160a01b03169052565b506040830151611ad5604084018260020b9052565b506060830151611aea606084018260020b9052565b506080830151611aff608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b45828501826001600160a01b03169052565b505061014092830151919092015290565b60008060008060808587031215611b6c57600080fd5b845193506020850151611b7e81611300565b6040860151606090960151949790965092505050565b600080600060608486031215611ba957600080fd5b835192506020840151915060408401519050925092509256fea2646970667358221220d9ae5d355f6ef521fdba25d29d9c747e525456ac67ed0180c1dd3cbcd989624864736f6c63430008130033
Deployed Bytecode
0x6080604052600436106100915760003560e01c806380cc71f21161005957806380cc71f21461013d578063cce9480114610177578063d7dd162e14610197578063ff781feb146101b7578063ff7b9266146100ab57600080fd5b806304caab47146100965780632847ccf2146100ab5780636f4621e3146100be5780636fcca69b146100d1578063803347361461010a575b600080fd5b6100a96100a4366004611163565b6101ca565b005b6100a96100b93660046112ad565b505050565b6100a96100cc366004611320565b6101eb565b3480156100dd57600080fd5b506100f16100ec366004611432565b610727565b60405162ffffff90911681526020015b60405180910390f35b34801561011657600080fd5b5061012a610125366004611432565b610791565b60405160029190910b8152602001610101565b34801561014957600080fd5b5061015d610158366004611456565b610802565b60408051600293840b81529190920b602082015201610101565b34801561018357600080fd5b506100a9610192366004611482565b610885565b3480156101a357600080fd5b506100f16101b2366004611432565b610988565b6100a96101c5366004611551565b6109ec565b80602001516000036101e2576101df81610b37565b50565b6101df81610c7a565b60008086516001600160401b0381111561020757610207610f4b565b604051908082528060200260200182016040528015610230578160200160208202803683370190505b50905060005b87518110156103c557733333b97138d4b086720b5ae8a7844b1345a333336001600160a01b031688828151811061026f5761026f6115f9565b60200260200101516001600160a01b031614806102ca5750733333111a391cc08fa51353e9195526a70b3333336001600160a01b03168882815181106102b7576102b76115f9565b60200260200101516001600160a01b0316145b1561036657735050bc082ff4a74fb6b0b04385defddb114b24248282815181106102f6576102f66115f9565b60200260200101906001600160a01b031690816001600160a01b031681525050733333111a391cc08fa51353e9195526a70b3333336001600160a01b0316888281518110610346576103466115f9565b60200260200101516001600160a01b03160361036157600192505b6103b3565b878181518110610378576103786115f9565b6020026020010151828281518110610392576103926115f9565b60200260200101906001600160a01b031690816001600160a01b0316815250505b806103bd81611625565b915050610236565b506103d66060890160408a01611432565b6001600160a01b031663f5f8d3658960600135836040518363ffffffff1660e01b815260040161040792919061163e565b600060405180830381600087803b15801561042157600080fd5b505af1925050508015610432575060015b15610649576040516370a0823160e01b8152306004820152600090735050bc082ff4a74fb6b0b04385defddb114b2424906370a0823190602401602060405180830381865afa158015610489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ad9190611695565b60405163095ea7b360e01b8152733333111a391cc08fa51353e9195526a70b333333600482015260248101829052909150735050bc082ff4a74fb6b0b04385defddb114b24249063095ea7b3906044016020604051808303816000875af115801561051c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054091906116be565b5080156106475782156105cf57604051636e553f6560e01b815260048101829052306024820152733333111a391cc08fa51353e9195526a70b33333390636e553f65906044016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c99190611695565b50610647565b604051637f8661a160e01b815260048101829052735050bc082ff4a74fb6b0b04385defddb114b242490637f8661a1906024016020604051808303816000875af1158015610621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106459190611695565b505b505b6001600160801b03861615158061066857506001600160801b03851615155b1561071d57604080516080810182526060808b01803583523060208401526001600160801b03808b168486015289169183019190915290916106ac91908b01611432565b6001600160a01b031663fc6f7865826040518263ffffffff1660e01b81526004016106d791906116d9565b60408051808303816000875af11580156106f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610719919061171d565b5050505b5050505050505050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078b9190611741565b92915050565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156107d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f59190611770565b5093979650505050505050565b60405163133f757160e31b81526004810182905260009081906001600160a01b038516906399fbab889060240161014060405180830381865afa15801561084d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108719190611803565b50949c939b50929950505050505050505050565b60006001600160801b03801682604001516001600160801b0316036108bf576108ad82610d74565b6001600160801b038116604084015290505b81604001516001600160801b03166000036108ed57604051630e52390960e41b815260040160405180910390fd5b6108f682610df8565b6108ff82610ee9565b61090882610d74565b9050806001600160801b03166000036109845781516020830151604051630852cd8d60e31b81526001600160a01b03909216916342966c68916109519160040190815260200190565b600060405180830381600087803b15801561096b57600080fd5b505af115801561097f573d6000803e3d6000fd5b505050505b5050565b6000816001600160a01b031663d0c93a7c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078b91906118c9565b60008160800151806020019051810190610a06919061190a565b60608301518151602085015160405163095ea7b360e01b81526001600160a01b0392831660048201526024810191909152929350169063095ea7b3906044016020604051808303816000875af1158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8891906116be565b5081516040805160a081018252602080850151825230908201526001600160a01b039092169163c04b8d59918101610ac14260016119c7565b81526020018560200151815260200185604001518152506040518263ffffffff1660e01b8152600401610af491906119da565b6020604051808303816000875af1158015610b13573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b99190611695565b6000816101200151806020019051810190610b529190611a49565b905060006040518061016001604052808460400151600001516001600160a01b031681526020018460400151602001516001600160a01b03168152602001836000015160020b8152602001846060015160020b8152602001846080015160020b81526020018460a0015181526020018460c0015181526020018460e0015181526020018461010001518152602001306001600160a01b03168152602001426001610bfc91906119c7565b90528351604051636d70c41560e01b81529192506001600160a01b031690636d70c41590610c2e908490600401611a94565b6080604051808303816000875af1158015610c4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c719190611b56565b50505050505050565b80600001516001600160a01b031663219f5d176040518060c00160405280846020015181526020018460a0015181526020018460c0015181526020018460e0015181526020018461010001518152602001426001610cd891906119c7565b9052604080516001600160e01b031960e085901b1681528251600482015260208301516024820152908201516044820152606082015160648201526080820151608482015260a09091015160a482015260c4016060604051808303816000875af1158015610d4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6e9190611b94565b50505050565b8051602082015160405163133f757160e31b815260048101919091526000916001600160a01b0316906399fbab889060240161014060405180830381865afa158015610dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de89190611803565b50929a9950505050505050505050565b80600001516001600160a01b0316630c49ccbe6040518060a001604052808460200151815260200184604001516001600160801b031681526020018460600151815260200184608001518152602001426001610e5491906119c7565b9052604080516001600160e01b031960e085901b1681528251600482015260208301516001600160801b0316602482015290820151604482015260608201516064820152608090910151608482015260a4015b60408051808303816000875af1158015610ec5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b9919061171d565b8051604080516080810182526020808501518252309082015260a08401516001600160801b039081168284015260c0850151166060820152905163fc6f786560e01b81526001600160a01b039092169163fc6f786591610ea7916004016116d9565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715610f8457610f84610f4b565b60405290565b60405161010081016001600160401b0381118282101715610f8457610f84610f4b565b60405160a081016001600160401b0381118282101715610f8457610f84610f4b565b604080519081016001600160401b0381118282101715610f8457610f84610f4b565b604051601f8201601f191681016001600160401b038111828210171561101957611019610f4b565b604052919050565b6001600160a01b03811681146101df57600080fd5b803561104181611021565b919050565b62ffffff811681146101df57600080fd5b60006060828403121561106957600080fd5b604051606081018181106001600160401b038211171561108b5761108b610f4b565b604052905080823561109c81611021565b815260208301356110ac81611021565b602082015260408301356110bf81611046565b6040919091015292915050565b8060020b81146101df57600080fd5b8035611041816110cc565b60006001600160401b038211156110ff576110ff610f4b565b50601f01601f191660200190565b600082601f83011261111e57600080fd5b813561113161112c826110e6565b610ff1565b81815284602083860101111561114657600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561117557600080fd5b81356001600160401b038082111561118c57600080fd5b9083019061018082860312156111a157600080fd5b6111a9610f61565b6111b283611036565b8152602083013560208201526111cb8660408501611057565b60408201526111dc60a084016110db565b60608201526111ed60c084016110db565b608082015260e083013560a08201526101008084013560c08301526101208085013560e08401526101408501358284015261016085013591508382111561123357600080fd5b61123f8883870161110d565b908301525095945050505050565b60006080828403121561125f57600080fd5b50919050565b60008083601f84011261127757600080fd5b5081356001600160401b0381111561128e57600080fd5b6020830191508360208285010111156112a657600080fd5b9250929050565b600080600060a084860312156112c257600080fd5b6112cc858561124d565b925060808401356001600160401b038111156112e757600080fd5b6112f386828701611265565b9497909650939450505050565b6001600160801b03811681146101df57600080fd5b803561104181611300565b600080600080600080610100878903121561133a57600080fd5b611344888861124d565b955060808701356001600160401b038082111561136057600080fd5b818901915089601f83011261137457600080fd5b813560208282111561138857611388610f4b565b8160051b611397828201610ff1565b928352848101820192828101908e8511156113b157600080fd5b958301955b848710156113db57863592506113cb83611021565b82825295830195908301906113b6565b809b5050505050506113ef60a08a01611315565b95506113fd60c08a01611315565b945060e089013591508082111561141357600080fd5b5061142089828a01611265565b979a9699509497509295939492505050565b60006020828403121561144457600080fd5b813561144f81611021565b9392505050565b6000806040838503121561146957600080fd5b823561147481611021565b946020939093013593505050565b60006020828403121561149457600080fd5b81356001600160401b03808211156114ab57600080fd5b9083019061010082860312156114c057600080fd5b6114c8610f8a565b6114d183611036565b8152602083013560208201526114e960408401611315565b6040820152606083013560608201526080830135608082015261150e60a08401611315565b60a082015261151f60c08401611315565b60c082015260e08301358281111561153657600080fd5b6115428782860161110d565b60e08301525095945050505050565b60006020828403121561156357600080fd5b81356001600160401b038082111561157a57600080fd5b9083019060a0828603121561158e57600080fd5b611596610fad565b82356115a181611021565b80825250602083013560208201526040830135604082015260608301356115c781611021565b60608201526080830135828111156115de57600080fd5b6115ea8782860161110d565b60808301525095945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016116375761163761160f565b5060010190565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156116885784516001600160a01b031683529383019391830191600101611663565b5090979650505050505050565b6000602082840312156116a757600080fd5b5051919050565b8051801515811461104157600080fd5b6000602082840312156116d057600080fd5b61144f826116ae565b6080810161078b8284805182526020808201516001600160a01b0316908301526040808201516001600160801b039081169184019190915260609182015116910152565b6000806040838503121561173057600080fd5b505080516020909101519092909150565b60006020828403121561175357600080fd5b815161144f81611046565b805161ffff8116811461104157600080fd5b600080600080600080600060e0888a03121561178b57600080fd5b875161179681611021565b60208901519097506117a7816110cc565b95506117b56040890161175e565b94506117c36060890161175e565b93506117d16080890161175e565b925060a088015160ff811681146117e757600080fd5b91506117f560c089016116ae565b905092959891949750929550565b6000806000806000806000806000806101408b8d03121561182357600080fd5b8a5161182e81611021565b60208c0151909a5061183f81611021565b60408c0151909950611850816110cc565b60608c0151909850611861816110cc565b60808c0151909750611872816110cc565b60a08c015190965061188381611300565b8095505060c08b0151935060e08b015192506101008b01516118a481611300565b6101208c01519092506118b681611300565b809150509295989b9194979a5092959850565b6000602082840312156118db57600080fd5b815161144f816110cc565b60005b838110156119015781810151838201526020016118e9565b50506000910152565b6000602080838503121561191d57600080fd5b82516001600160401b038082111561193457600080fd5b908401906040828703121561194857600080fd5b611950610fcf565b825161195b81611021565b8152828401518281111561196e57600080fd5b80840193505086601f84011261198357600080fd5b8251915061199361112c836110e6565b82815287858486010111156119a757600080fd5b6119b6838683018787016118e6565b938101939093525090949350505050565b8082018082111561078b5761078b61160f565b602081526000825160a0602084015280518060c0850152611a028160e08601602085016118e6565b60018060a01b0360208601511660408501526040850151606085015260608501516080850152608085015160a085015260e0601f19601f8301168501019250505092915050565b600060208284031215611a5b57600080fd5b604051602081018181106001600160401b0382111715611a7d57611a7d610f4b565b6040528251611a8b816110cc565b81529392505050565b81516001600160a01b0316815261016081016020830151611ac060208401826001600160a01b03169052565b506040830151611ad5604084018260020b9052565b506060830151611aea606084018260020b9052565b506080830151611aff608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151611b45828501826001600160a01b03169052565b505061014092830151919092015290565b60008060008060808587031215611b6c57600080fd5b845193506020850151611b7e81611300565b6040860151606090960151949790965092505050565b600080600060608486031215611ba957600080fd5b835192506020840151915060408401519050925092509256fea2646970667358221220d9ae5d355f6ef521fdba25d29d9c747e525456ac67ed0180c1dd3cbcd989624864736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.