Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
ShadowGaugeRegistry
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.17; import { ICustomConnectorRegistry } from "contracts/ConnectorRegistry.sol"; import { IGaugeRegistryVoter } from "contracts/connectors/GaugeRegistry.sol"; import { ShadowGaugeConnector } from "contracts/connectors/shadow/ShadowGaugeConnector.sol"; import { ShadowV3Connector } from "contracts/connectors/shadow/ShadowV3Connector.sol"; interface IShadowPairFactory { function isPair( address pair ) external view returns (bool); } contract ShadowGaugeRegistry is ICustomConnectorRegistry { IGaugeRegistryVoter public immutable voter; ShadowGaugeConnector public immutable shadowGaugeConnector; ShadowV3Connector public immutable shadowV3Connector; IShadowPairFactory public immutable shadowPairFactory; constructor( IGaugeRegistryVoter voter_, ShadowGaugeConnector shadowGaugeConnector_, ShadowV3Connector shadowV3Connector_, IShadowPairFactory shadowPairFactory_ ) { voter = voter_; shadowGaugeConnector = shadowGaugeConnector_; shadowV3Connector = shadowV3Connector_; shadowPairFactory = shadowPairFactory_; } function connectorOf( address target ) external view override returns (address) { if (voter.isGauge(target)) { if (shadowPairFactory.isPair(voter.poolForGauge(target))) { return address(shadowGaugeConnector); } if (voter.isClGauge(target)) { return address(shadowV3Connector); } } return address(0); } }
// 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; import { ICustomConnectorRegistry } from "contracts/ConnectorRegistry.sol"; interface IGaugeRegistryVoter { function isGauge( address target ) external view returns (bool); function isClGauge( address target ) external view returns (bool); function poolForGauge( address gauge ) external view returns (address); } contract GaugeRegistry is ICustomConnectorRegistry { IGaugeRegistryVoter public immutable voter; address public immutable connector; constructor(IGaugeRegistryVoter voter_, address connector_) { voter = voter_; connector = connector_; } function connectorOf( address target ) external view override returns (address) { if (voter.isGauge(target)) { return connector; } return address(0); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IFarmConnector, Farm } from "contracts/interfaces/IFarmConnector.sol"; import { IGauge } from "contracts/interfaces/external/aerodrome/IGauge.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { IRamsesGauge } from "contracts/interfaces/external/ramses/IRamsesGauge.sol"; import { RamsesGaugeConnector } from "contracts/connectors/ramses/RamsesGaugeConnector.sol"; struct ShadowClaimExtraData { address[] rewardTokens; } contract ShadowGaugeConnector is IFarmConnector { function deposit( Farm calldata farm, address token, bytes memory // _extraData ) external payable override { uint256 amount = IERC20(token).balanceOf(address(this)); SafeTransferLib.safeApprove(token, farm.stakingContract, amount); IGauge(farm.stakingContract).deposit(amount); } function withdraw( Farm calldata farm, uint256 amount, bytes memory // _extraData ) external override { IRamsesGauge(farm.stakingContract).withdraw(amount); } function claim( Farm calldata farm, bytes memory _extraData ) external override { ShadowClaimExtraData memory extraData = abi.decode(_extraData, (ShadowClaimExtraData)); IRamsesGauge(farm.stakingContract).getReward( address(this), extraData.rewardTokens ); } }
// 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: 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 pragma solidity ^0.8.0; import { Farm } from "contracts/structs/FarmStrategyStructs.sol"; interface IFarmConnector { function deposit( Farm calldata farm, address token, bytes memory extraData ) external payable; function withdraw( Farm calldata farm, uint256 amount, bytes memory extraData ) external; function claim(Farm calldata farm, bytes memory extraData) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IGauge { error NotAlive(); error NotAuthorized(); error NotVoter(); error NotTeam(); error RewardRateTooHigh(); error ZeroAmount(); error ZeroRewardRate(); event Deposit(address indexed from, address indexed to, uint256 amount); event Withdraw(address indexed from, uint256 amount); event NotifyReward(address indexed from, uint256 amount); event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1); event ClaimRewards(address indexed from, uint256 amount); /// @notice Address of the pool LP token which is deposited (staked) for rewards function stakingToken() external view returns (address); /// @notice Address of the token (AERO) rewarded to stakers function rewardToken() external view returns (address); /// @notice Address of the FeesVotingReward contract linked to the gauge function feesVotingReward() external view returns (address); /// @notice Address of Protocol Voter function voter() external view returns (address); /// @notice Address of Protocol Voting Escrow function ve() external view returns (address); /// @notice Returns if gauge is linked to a legitimate Protocol pool function isPool() external view returns (bool); /// @notice Timestamp end of current rewards period function periodFinish() external view returns (uint256); /// @notice Current reward rate of rewardToken to distribute per second function rewardRate() external view returns (uint256); /// @notice Most recent timestamp contract has updated state function lastUpdateTime() external view returns (uint256); /// @notice Most recent stored value of rewardPerToken function rewardPerTokenStored() external view returns (uint256); /// @notice Amount of stakingToken deposited for rewards function totalSupply() external view returns (uint256); /// @notice Get the amount of stakingToken deposited by an account function balanceOf(address) external view returns (uint256); /// @notice Cached rewardPerTokenStored for an account based on their most recent action function userRewardPerTokenPaid(address) external view returns (uint256); /// @notice Cached amount of rewardToken earned for an account function rewards(address) external view returns (uint256); /// @notice View to see the rewardRate given the timestamp of the start of the epoch function rewardRateByEpoch(uint256) external view returns (uint256); /// @notice Cached amount of fees generated from the Pool linked to the Gauge of token0 function fees0() external view returns (uint256); /// @notice Cached amount of fees generated from the Pool linked to the Gauge of token1 function fees1() external view returns (uint256); /// @notice Get the current reward rate per unit of stakingToken deposited function rewardPerToken() external view returns (uint256 _rewardPerToken); /// @notice Returns the last time the reward was modified or periodFinish if the reward has ended function lastTimeRewardApplicable() external view returns (uint256 _time); /// @notice Returns accrued balance to date from last claim / first deposit. function earned(address _account) external view returns (uint256 _earned); /// @notice Total amount of rewardToken to distribute for the current rewards period function left() external view returns (uint256 _left); /// @notice Retrieve rewards for an address. /// @dev Throws if not called by same address or voter. /// @param _account . function getReward(address _account) external; /// @notice Deposit LP tokens into gauge for msg.sender /// @param _amount . function deposit(uint256 _amount) external; /// @notice Deposit LP tokens into gauge for any user /// @param _amount . /// @param _recipient Recipient to give balance to function deposit(uint256 _amount, address _recipient) external; /// @notice Withdraw LP tokens for user /// @param _amount . function withdraw(uint256 _amount) external; /// @dev Notifies gauge of gauge rewards. Assumes gauge reward tokens is 18 decimals. /// If not 18 decimals, rewardRate may have rounding issues. function notifyRewardAmount(uint256 amount) external; /// @dev Notifies gauge of gauge rewards without distributing its fees. /// Assumes gauge reward tokens is 18 decimals. /// If not 18 decimals, rewardRate may have rounding issues. function notifyRewardWithoutClaim(uint256 amount) 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: 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.13; interface IRamsesGauge { function notifyRewardAmount(address token, uint256 amount) external; function getReward(address account, address[] memory tokens) external; function claimFees() external returns (uint256 claimed0, uint256 claimed1); function left(address token) external view returns (uint256); function isForPair() external view returns (bool); function whitelistNotifiedRewards(address token) external; function removeRewardWhitelist(address token) external; function rewardsListLength() external view returns (uint256); function rewards(uint256 index) external view returns (address); function earned( address token, address account ) external view returns (uint256); function balanceOf(address) external view returns (uint256); function derivedBalances(address) external view returns (uint256); function rewardRate(address) external view returns (uint256); function deposit(uint256 amount, uint256 tokenId) external; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IFarmConnector, Farm } from "contracts/interfaces/IFarmConnector.sol"; import { IRamsesGauge } from "contracts/interfaces/external/ramses/IRamsesGauge.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; struct RamsesClaimExtraData { address[] rewardTokens; } contract RamsesGaugeConnector is IFarmConnector { function deposit( Farm calldata farm, address token, bytes memory // _extraData ) external payable override { uint256 amount = IERC20(token).balanceOf(address(this)); SafeTransferLib.safeApprove(token, farm.stakingContract, amount); IRamsesGauge(farm.stakingContract).deposit(amount, 0); } function withdraw( Farm calldata farm, uint256 amount, bytes memory // _extraData ) external override { IRamsesGauge(farm.stakingContract).withdraw(amount); } function claim( Farm calldata farm, bytes memory _extraData ) external override { RamsesClaimExtraData memory extraData = abi.decode(_extraData, (RamsesClaimExtraData)); IRamsesGauge(farm.stakingContract).claimFees(); IRamsesGauge(farm.stakingContract).getReward( address(this), extraData.rewardTokens ); } }
// 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 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: 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: 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: 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 { 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 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 // 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 { 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 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; 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 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: 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: 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":[{"internalType":"contract IGaugeRegistryVoter","name":"voter_","type":"address"},{"internalType":"contract ShadowGaugeConnector","name":"shadowGaugeConnector_","type":"address"},{"internalType":"contract ShadowV3Connector","name":"shadowV3Connector_","type":"address"},{"internalType":"contract IShadowPairFactory","name":"shadowPairFactory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"connectorOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shadowGaugeConnector","outputs":[{"internalType":"contract ShadowGaugeConnector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shadowPairFactory","outputs":[{"internalType":"contract IShadowPairFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shadowV3Connector","outputs":[{"internalType":"contract ShadowV3Connector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"contract IGaugeRegistryVoter","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61010060405234801561001157600080fd5b506040516105953803806105958339810160408190526100309161006a565b6001600160a01b0393841660805291831660a052821660c0521660e0526100c9565b6001600160a01b038116811461006757600080fd5b50565b6000806000806080858703121561008057600080fd5b845161008b81610052565b602086015190945061009c81610052565b60408601519093506100ad81610052565b60608601519092506100be81610052565b939692955090935050565b60805160a05160c05160e05161046d6101286000396000818160a401526101d50152600081816061015261039001526000818160f201526102da01526000818160cb01528181610144015281816101ff015261031d015261046d6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806308454c231461005c578063258bba141461009f57806346c96aac146100c65780634da98ab7146100ed578063c79aeaae14610114575b600080fd5b6100837f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b6100837f000000000000000000000000000000000000000000000000000000000000000081565b6100837f000000000000000000000000000000000000000000000000000000000000000081565b6100837f000000000000000000000000000000000000000000000000000000000000000081565b6100836101223660046103d4565b60405163aa79979b60e01b81526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa79979b90602401602060405180830381865afa15801561018d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b191906103f8565b156103b45760405163036b50d960e11b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000081169163e5e31b13917f000000000000000000000000000000000000000000000000000000000000000016906306d6a1b290602401602060405180830381865afa158015610246573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026a919061041a565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156102ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d291906103f8565b156102fe57507f0000000000000000000000000000000000000000000000000000000000000000919050565b60405163060ce5a560e01b81526001600160a01b0383811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063060ce5a590602401602060405180830381865afa158015610364573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038891906103f8565b156103b457507f0000000000000000000000000000000000000000000000000000000000000000919050565b506000919050565b6001600160a01b03811681146103d157600080fd5b50565b6000602082840312156103e657600080fd5b81356103f1816103bc565b9392505050565b60006020828403121561040a57600080fd5b815180151581146103f157600080fd5b60006020828403121561042c57600080fd5b81516103f1816103bc56fea2646970667358221220d4fa2d9cbb04d6e4a5b0ef0381132a9e2cb54ec5f9f2f9850e1843c3a938e9d664736f6c634300081300330000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f000000000000000000000000de3f584116e31b14aeaf67d4a667935c3a23165d000000000000000000000000ac371d6e651b6450ea8c4ce346ddd44b62d851b50000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c8
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100575760003560e01c806308454c231461005c578063258bba141461009f57806346c96aac146100c65780634da98ab7146100ed578063c79aeaae14610114575b600080fd5b6100837f000000000000000000000000ac371d6e651b6450ea8c4ce346ddd44b62d851b581565b6040516001600160a01b03909116815260200160405180910390f35b6100837f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c881565b6100837f0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f81565b6100837f000000000000000000000000de3f584116e31b14aeaf67d4a667935c3a23165d81565b6100836101223660046103d4565b60405163aa79979b60e01b81526001600160a01b0382811660048301526000917f0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f9091169063aa79979b90602401602060405180830381865afa15801561018d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b191906103f8565b156103b45760405163036b50d960e11b81526001600160a01b0383811660048301527f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c881169163e5e31b13917f0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f16906306d6a1b290602401602060405180830381865afa158015610246573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026a919061041a565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156102ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d291906103f8565b156102fe57507f000000000000000000000000de3f584116e31b14aeaf67d4a667935c3a23165d919050565b60405163060ce5a560e01b81526001600160a01b0383811660048301527f0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f169063060ce5a590602401602060405180830381865afa158015610364573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038891906103f8565b156103b457507f000000000000000000000000ac371d6e651b6450ea8c4ce346ddd44b62d851b5919050565b506000919050565b6001600160a01b03811681146103d157600080fd5b50565b6000602082840312156103e657600080fd5b81356103f1816103bc565b9392505050565b60006020828403121561040a57600080fd5b815180151581146103f157600080fd5b60006020828403121561042c57600080fd5b81516103f1816103bc56fea2646970667358221220d4fa2d9cbb04d6e4a5b0ef0381132a9e2cb54ec5f9f2f9850e1843c3a938e9d664736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f000000000000000000000000de3f584116e31b14aeaf67d4a667935c3a23165d000000000000000000000000ac371d6e651b6450ea8c4ce346ddd44b62d851b50000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c8
-----Decoded View---------------
Arg [0] : voter_ (address): 0x3aF1dD7A2755201F8e2D6dCDA1a61d9f54838f4f
Arg [1] : shadowGaugeConnector_ (address): 0xde3f584116e31B14aEAf67d4a667935C3a23165D
Arg [2] : shadowV3Connector_ (address): 0xAc371D6E651b6450ea8c4cE346Ddd44B62d851B5
Arg [3] : shadowPairFactory_ (address): 0x2dA25E7446A70D7be65fd4c053948BEcAA6374c8
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003af1dd7a2755201f8e2d6dcda1a61d9f54838f4f
Arg [1] : 000000000000000000000000de3f584116e31b14aeaf67d4a667935c3a23165d
Arg [2] : 000000000000000000000000ac371d6e651b6450ea8c4ce346ddd44b62d851b5
Arg [3] : 0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c8
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.