ETH Price: $2,054.71 (+0.27%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Method Block
From
To
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
V3FactoryOwner

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion, GNU AGPLv3 license
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.23;

import {IUniswapV3PoolOwnerActions} from "src/interfaces/IUniswapV3PoolOwnerActions.sol";
import {IUniswapV3FactoryOwnerActions} from "src/interfaces/IUniswapV3FactoryOwnerActions.sol";
import {INotifiableRewardReceiver} from "src/interfaces/INotifiableRewardReceiver.sol";
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin/token/ERC20/utils/SafeERC20.sol";

/// @title V3FactoryOwner
/// @author ScopeLift
/// @notice A contract that can serve as the owner of the Uniswap v3 factory. This contract itself
/// has an admin. That admin retains the exclusive right to call privileged methods on the v3
/// factory, and on pools which it has deployed, via passthrough methods. This includes the ability
/// to enable fee amounts on the factory, and set protocol fees on individual pools. The admin can
/// also set a new admin.
///
/// One privileged function that is _not_ reserved exclusively for the admin is the ability to
/// collect protocol fees from a pool. This method is instead exposed publicly by this contract's
/// `claimFees` method. That method collects fees from the protocol as long as the caller pays for
/// them with a transfer of a designated amount of a designated token. That payout is forwarded
/// to a reward receiver.
///
/// In the context of the broader system, it is expected that this contract's REWARD_RECEIVER is
/// a deployment of the `UniStaker` contract. It is expected the admin of this contract will be the
/// Uniswap Governance timelock. It is expected governance will transfer
/// ownership of the factory to an instance of this contract, and turn on protocol fees for select
/// pools. It is also expected a competitive market of seekers will emerge racing to "buy" the fees
/// for an arbitrage opportunity.
contract V3FactoryOwner {
  using SafeERC20 for IERC20;

  /// @notice Emitted when a user pays the payout and claims the fees from a given v3 pool.
  /// @param pool The v3 pool from which protocol fees were claimed.
  /// @param caller The address which executes the call to claim the fees.
  /// @param recipient The address to which the claimed pool fees are sent.
  /// @param amount0 The raw amount of token0 fees claimed from the pool.
  /// @param amount1 The raw amount token1 fees claimed from the pool.
  event FeesClaimed(
    address indexed pool,
    address indexed caller,
    address indexed recipient,
    uint256 amount0,
    uint256 amount1
  );

  /// @notice Emitted when the existing admin designates a new address as the admin.
  event AdminSet(address indexed oldAmin, address indexed newAdmin);

  /// @notice Emitted when the admin updates the payout amount.
  event PayoutAmountSet(uint256 indexed oldPayoutAmount, uint256 indexed newPayoutAmount);

  /// @notice Thrown when an unauthorized account calls a privileged function.
  error V3FactoryOwner__Unauthorized();

  /// @notice Thrown if the proposed admin is the zero address.
  error V3FactoryOwner__InvalidAddress();

  /// @notice Thrown if the proposed payout amount is zero.
  error V3FactoryOwner__InvalidPayoutAmount();

  /// @notice Thrown when the fees collected from a pool are less than the caller expects.
  error V3FactoryOwner__InsufficientFeesCollected();

  /// @notice The instance of the Uniswap v3 factory contract which this contract will own.
  IUniswapV3FactoryOwnerActions public immutable FACTORY;

  /// @notice The ERC-20 token which must be used to pay for fees when claiming pool fees.
  IERC20 public immutable PAYOUT_TOKEN;

  /// @notice The raw amount of the payout token which is paid by a user when claiming pool fees.
  uint256 public payoutAmount;

  /// @notice The contract that receives the payout and is notified via method call, when pool fees
  /// are claimed.
  INotifiableRewardReceiver public immutable REWARD_RECEIVER;

  /// @notice The address that can call privileged methods, including passthrough owner functions
  /// to the factory itself.
  address public admin;

  /// @param _admin The initial admin address for this deployment. Cannot be zero address.
  /// @param _factory The v3 factory instance for which this deployment will serve as owner.
  /// @param _payoutToken The ERC-20 token in which payouts will be denominated.
  /// @param _payoutAmount The initial raw amount of the payout token required to claim fees from
  /// a pool.
  /// @param _rewardReceiver The contract that will receive the payout when fees are claimed.
  constructor(
    address _admin,
    IUniswapV3FactoryOwnerActions _factory,
    IERC20 _payoutToken,
    uint256 _payoutAmount,
    INotifiableRewardReceiver _rewardReceiver
  ) {
    if (_admin == address(0)) revert V3FactoryOwner__InvalidAddress();
    if (_payoutAmount == 0) revert V3FactoryOwner__InvalidPayoutAmount();

    admin = _admin;
    FACTORY = _factory;
    PAYOUT_TOKEN = _payoutToken;
    payoutAmount = _payoutAmount;
    REWARD_RECEIVER = _rewardReceiver;

    emit AdminSet(address(0), _admin);
    emit PayoutAmountSet(0, _payoutAmount);
  }

  /// @notice Pass the admin role to a new address. Must be called by the existing admin.
  /// @param _newAdmin The address that will be the admin after this call completes.
  function setAdmin(address _newAdmin) external {
    _revertIfNotAdmin();
    if (_newAdmin == address(0)) revert V3FactoryOwner__InvalidAddress();
    emit AdminSet(admin, _newAdmin);
    admin = _newAdmin;
  }

  /// @notice Update the payout amount to a new value. Must be called by admin.
  /// @param _newPayoutAmount The value that will be the new payout amount.
  function setPayoutAmount(uint256 _newPayoutAmount) external {
    _revertIfNotAdmin();
    if (_newPayoutAmount == 0) revert V3FactoryOwner__InvalidPayoutAmount();
    emit PayoutAmountSet(payoutAmount, _newPayoutAmount);
    payoutAmount = _newPayoutAmount;
  }

  /// @notice Passthrough method that enables a fee amount on the factory. Must be called by the
  /// admin.
  /// @param _fee The fee param to forward to the factory.
  /// @param _tickSpacing The tick spacing param to forward to the factory.
  /// @dev See docs on IUniswapV3FactoryOwnerActions for more information on forwarded params.
  function enableFeeAmount(uint24 _fee, int24 _tickSpacing) external {
    _revertIfNotAdmin();
    FACTORY.enableFeeAmount(_fee, _tickSpacing);
  }

  /// @notice Passthrough method that sets the protocol fee on a v3 pool. Must be called by the
  /// admin.
  /// @param _pool The Uniswap v3 pool on which the protocol fee is being set.
  /// @param _feeProtocol0 The fee protocol 0 param to forward to the pool.
  /// @param _feeProtocol1 The fee protocol 1 parm to forward to the pool.
  /// @dev See docs on IUniswapV3PoolOwnerActions for more information on forwarded params.
  function setFeeProtocol(
    IUniswapV3PoolOwnerActions _pool,
    uint8 _feeProtocol0,
    uint8 _feeProtocol1
  ) external {
    _revertIfNotAdmin();
    _pool.setFeeProtocol(_feeProtocol0, _feeProtocol1);
  }

  /// @notice Public method that allows any caller to claim the protocol fees accrued by a given
  /// Uniswap v3 pool contract. Caller must pre-approve this factory owner contract on the payout
  /// token contract for at least the payout amount, which is transferred from the caller to the
  /// reward receiver. The reward receiver is "notified" of the payout via a method call. The
  /// protocol fees collected are sent to a receiver of the caller's specification.
  ///
  /// A quick example can help illustrate why an external party, such as an MEV searcher, would be
  /// incentivized to call this method. Imagine, purely for the sake of example, that protocol fees
  /// have been activated for the USDC/USDT stablecoin v3 pool. Imagine also the payout token and
  /// payout amount are WETH and 10e18 respectively. Finally, assume the spot USD price of ETH is
  /// $2,500, and both stablecoins are trading at their $1 peg. As regular users trade against the
  /// USDC/USDT pool, protocol fees amass in the pool contract in both stablecoins. Once the fees
  /// in the pool total more than 25,000 in stablecoins, it becomes profitable for an external
  /// party to arbitrage the fees by calling this method, paying 10 WETH (worth $25K) and getting
  /// more than $25K worth of stablecoins. (This ignores other details, which real searchers would
  /// take into consideration, such as the gas/builder fee they would pay to call the method).
  ///
  /// The same mechanic applies regardless of what the pool currencies, payout token, or payout
  /// amount are. Effectively, as each pool accrues fees, it eventually becomes possible to "buy"
  /// the pool fees for less than they are valued by "paying" the the payout amount of the payout
  /// token.
  /// `payoutAmount` may be changed by the admin (governance). Any proposal that changes this amount
  /// is expected to be subject to the governance process, including a timelocked execution, and so
  /// it's unlikely that a caller would be surprised by a change in this value. Still, callers
  /// should be aware of the edge case where:
  /// 1. The caller grants a higher-than-necessary payout token approval to this factory.
  /// 2. caller's claimFee transaction is in the mempool.
  /// 3. the payoutAmount is changed.
  /// 4. the claimFee transaction is now included in a block.
  /// @param _pool The Uniswap v3 pool contract from which protocol fees are being collected.
  /// @param _recipient The address to which collected protocol fees will be transferred.
  /// @param _amount0Requested The amount0Requested param to forward to the pool's collectProtocol
  /// method. Its maximum value will be `protocolFees.token0 - 1`.
  /// @param _amount1Requested The amount1Requested param to forward to the pool's collectProtocol
  /// method. Its maximum value will be `protocolFees.token1 - 1`.
  /// @return _amount0 The amount0 fees collected, returned by the pool's collectProtocol method.
  /// @return _amount1 The amount1 fees collected, returned by the pool's collectProtocol method.
  /// @dev The `UniswapV3Pool contract allows claiming a maximum of the total accrued fees minus 1.
  /// We highly recommend checking the source code of the `UniswapV3Pool` contract in order to
  /// better understand the potential constraints of the forwarded params.
  function claimFees(
    IUniswapV3PoolOwnerActions _pool,
    address _recipient,
    uint128 _amount0Requested,
    uint128 _amount1Requested
  ) external returns (uint128, uint128) {
    PAYOUT_TOKEN.safeTransferFrom(msg.sender, address(REWARD_RECEIVER), payoutAmount);
    REWARD_RECEIVER.notifyRewardAmount(payoutAmount);
    (uint128 _amount0, uint128 _amount1) =
      _pool.collectProtocol(_recipient, _amount0Requested, _amount1Requested);

    // Protect the caller from receiving less than requested. See `collectProtocol` for context.
    if (_amount0 < _amount0Requested || _amount1 < _amount1Requested) {
      revert V3FactoryOwner__InsufficientFeesCollected();
    }
    emit FeesClaimed(address(_pool), msg.sender, _recipient, _amount0, _amount1);
    return (_amount0, _amount1);
  }

  /// @notice Ensures the msg.sender is the contract admin and reverts otherwise.
  /// @dev Place inside external methods to make them admin-only.
  function _revertIfNotAdmin() internal view {
    if (msg.sender != admin) revert V3FactoryOwner__Unauthorized();
  }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.23;

/// @title Permissioned pool actions
/// @notice Contains pool methods that may only be called by the factory owner
/// @dev Vendored from
/// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol
interface IUniswapV3PoolOwnerActions {
  /// @notice Set the denominator of the protocol's % share of the fees
  /// @param feeProtocol0 new protocol fee for token0 of the pool
  /// @param feeProtocol1 new protocol fee for token1 of the pool
  function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;

  /// @notice Collect the protocol fee accrued to the pool
  /// @param recipient The address to which collected protocol fees should be sent
  /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only
  /// token1
  /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only
  /// token0
  /// @return amount0 The protocol fee collected in token0
  /// @return amount1 The protocol fee collected in token1
  function collectProtocol(address recipient, uint128 amount0Requested, uint128 amount1Requested)
    external
    returns (uint128 amount0, uint128 amount1);
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.23;

/// @title The interface for the Uniswap V3 Factory
/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the
/// protocol fees
/// @dev Stripped down and renamed from:
/// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/interfaces/IUniswapV3Factory.sol
interface IUniswapV3FactoryOwnerActions {
  /// @notice Returns the current owner of the factory
  /// @dev Can be changed by the current owner via setOwner
  /// @return The address of the factory owner
  function owner() external view returns (address);

  /// @notice Updates the owner of the factory
  /// @dev Must be called by the current owner
  /// @param _owner The new owner of the factory
  function setOwner(address _owner) external;

  /// @notice Enables a fee amount with the given tickSpacing
  /// @dev Fee amounts may never be removed once enabled
  /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)
  /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the
  /// given fee amount
  function enableFeeAmount(uint24 fee, int24 tickSpacing) external;

  /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled
  /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the
  /// calling context
  /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled
  /// fee
  /// @return The tick spacing
  function feeAmountTickSpacing(uint24 fee) external view returns (int24);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;

/// @title INotifiableRewardReceiver
/// @author ScopeLift
/// @notice The communication interface between the V3FactoryOwner contract and the UniStaker
/// contract. In particular, the V3FactoryOwner only needs to know the latter implements the
/// specified method in order to forward payouts to the UniStaker contract. The UniStaker contract
/// receives the rewards and abstracts the distribution mechanics
interface INotifiableRewardReceiver {
  /// @notice Method called to notify a reward receiver it has received a reward.
  /// @param _amount The amount of reward.
  function notifyRewardAmount(uint256 _amount) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

Settings
{
  "remappings": [
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "uniswap-periphery/=lib/v3-periphery/contracts/",
    "@uniswap/v3-core/=lib/v3-core/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "v3-core/=lib/v3-core/",
    "v3-periphery/=lib/v3-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"contract IUniswapV3FactoryOwnerActions","name":"_factory","type":"address"},{"internalType":"contract IERC20","name":"_payoutToken","type":"address"},{"internalType":"uint256","name":"_payoutAmount","type":"uint256"},{"internalType":"contract INotifiableRewardReceiver","name":"_rewardReceiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"V3FactoryOwner__InsufficientFeesCollected","type":"error"},{"inputs":[],"name":"V3FactoryOwner__InvalidAddress","type":"error"},{"inputs":[],"name":"V3FactoryOwner__InvalidPayoutAmount","type":"error"},{"inputs":[],"name":"V3FactoryOwner__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"FeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldPayoutAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newPayoutAmount","type":"uint256"}],"name":"PayoutAmountSet","type":"event"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"contract IUniswapV3FactoryOwnerActions","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYOUT_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_RECEIVER","outputs":[{"internalType":"contract INotifiableRewardReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IUniswapV3PoolOwnerActions","name":"_pool","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint128","name":"_amount0Requested","type":"uint128"},{"internalType":"uint128","name":"_amount1Requested","type":"uint128"}],"name":"claimFees","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_fee","type":"uint24"},{"internalType":"int24","name":"_tickSpacing","type":"int24"}],"name":"enableFeeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"payoutAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IUniswapV3PoolOwnerActions","name":"_pool","type":"address"},{"internalType":"uint8","name":"_feeProtocol0","type":"uint8"},{"internalType":"uint8","name":"_feeProtocol1","type":"uint8"}],"name":"setFeeProtocol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPayoutAmount","type":"uint256"}],"name":"setPayoutAmount","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e060405234801561001057600080fd5b50604051610edf380380610edf83398101604081905261002f91610127565b6001600160a01b0385166100565760405163a553972760e01b815260040160405180910390fd5b816000036100775760405163b4230b9d60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0387811691821790925585821660805284821660a052600084815591831660c0526040519091907fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff97908290a360405182906000907f8f6c5c01f9385e42ed275713f18de607d67ea7f6673e431418c8b286057a2207908290a35050505050610192565b6001600160a01b038116811461012457600080fd5b50565b600080600080600060a0868803121561013f57600080fd5b855161014a8161010f565b602087015190955061015b8161010f565b604087015190945061016c8161010f565b6060870151608088015191945092506101848161010f565b809150509295509295909350565b60805160a05160c051610d036101dc6000396000818161017e015281816104d3015261056f0152600081816101e101526104f701526000818160c801526104550152610d036000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80638a7c195f11610076578063bf2d5f1b1161005b578063bf2d5f1b146101a0578063e2f6f511146101dc578063f851a4401461020357600080fd5b80638a7c195f14610166578063a508ff6c1461017957600080fd5b80636b46c8c3116100a75780636b46c8c314610129578063704b6c02146101405780637f4d39451461015357600080fd5b80632dd31000146100c357806336077b3c14610114575b600080fd5b6100ea7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610127610122366004610b10565b610223565b005b61013260005481565b60405190815260200161010b565b61012761014e366004610b55565b6102ba565b610127610161366004610b72565b61039d565b610127610174366004610b8b565b610410565b6100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6101b36101ae366004610bf1565b6104ca565b604080516fffffffffffffffffffffffffffffffff93841681529290911660208301520161010b565b6100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6001546100ea9073ffffffffffffffffffffffffffffffffffffffff1681565b61022b61079e565b6040517f8206a4d100000000000000000000000000000000000000000000000000000000815260ff80841660048301528216602482015273ffffffffffffffffffffffffffffffffffffffff841690638206a4d190604401600060405180830381600087803b15801561029d57600080fd5b505af11580156102b1573d6000803e3d6000fd5b50505050505050565b6102c261079e565b73ffffffffffffffffffffffffffffffffffffffff811661030f576040517fa553972700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015460405173ffffffffffffffffffffffffffffffffffffffff8084169216907fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff9790600090a3600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6103a561079e565b806000036103df576040517fb4230b9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405183927f8f6c5c01f9385e42ed275713f18de607d67ea7f6673e431418c8b286057a220791a3600055565b61041861079e565b6040517f8a7c195f00000000000000000000000000000000000000000000000000000000815262ffffff83166004820152600282900b60248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638a7c195f90604401600060405180830381600087803b1580156104ae57600080fd5b505af11580156104c2573d6000803e3d6000fd5b505050505050565b60008061053c337f00000000000000000000000000000000000000000000000000000000000000006000547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166107f1909392919063ffffffff16565b6000546040517f3c6b16ab00000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690633c6b16ab90602401600060405180830381600087803b1580156105c857600080fd5b505af11580156105dc573d6000803e3d6000fd5b50506040517f85b6672900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526fffffffffffffffffffffffffffffffff808916602484015287166044830152600093508392508916906385b667299060640160408051808303816000875af1158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190610c4d565b91509150856fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff1610806106ef5750846fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16105b15610726576040517f0790df8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516fffffffffffffffffffffffffffffffff80851682528316602082015273ffffffffffffffffffffffffffffffffffffffff808a16923392918c16917fd377f58cbc83f844989775f0d4bfa247dbee70bf3d851b8c5f0e0fe51d3b6ef9910160405180910390a49097909650945050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107ef576040517fd064e4bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261088690859061088c565b50505050565b60006108ae73ffffffffffffffffffffffffffffffffffffffff84168361092c565b905080516000141580156108d35750808060200190518101906108d19190610c7c565b155b15610927576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024015b60405180910390fd5b505050565b606061093a83836000610941565b9392505050565b60608147101561097f576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161091e565b6000808573ffffffffffffffffffffffffffffffffffffffff1684866040516109a89190610c9e565b60006040518083038185875af1925050503d80600081146109e5576040519150601f19603f3d011682016040523d82523d6000602084013e6109ea565b606091505b50915091506109fa868383610a04565b9695505050505050565b606082610a1957610a1482610a93565b61093a565b8151158015610a3d575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610a8c576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161091e565b508061093a565b805115610aa35780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b73ffffffffffffffffffffffffffffffffffffffff81168114610ad557600080fd5b803560ff81168114610b0b57600080fd5b919050565b600080600060608486031215610b2557600080fd5b8335610b3081610ad8565b9250610b3e60208501610afa565b9150610b4c60408501610afa565b90509250925092565b600060208284031215610b6757600080fd5b813561093a81610ad8565b600060208284031215610b8457600080fd5b5035919050565b60008060408385031215610b9e57600080fd5b823562ffffff81168114610bb157600080fd5b91506020830135600281900b8114610bc857600080fd5b809150509250929050565b6fffffffffffffffffffffffffffffffff81168114610ad557600080fd5b60008060008060808587031215610c0757600080fd5b8435610c1281610ad8565b93506020850135610c2281610ad8565b92506040850135610c3281610bd3565b91506060850135610c4281610bd3565b939692955090935050565b60008060408385031215610c6057600080fd5b8251610c6b81610bd3565b6020840151909250610bc881610bd3565b600060208284031215610c8e57600080fd5b8151801515811461093a57600080fd5b6000825160005b81811015610cbf5760208186018101518583015201610ca5565b50600092019182525091905056fea264697066735822122008a6b35575393a510061efd1eae133068932958d79f59515eea9f79583b84b1f64736f6c634300081700330000000000000000000000001a9c8182c09f50c8318d769245bea52c32be35bc0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc8

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100be5760003560e01c80638a7c195f11610076578063bf2d5f1b1161005b578063bf2d5f1b146101a0578063e2f6f511146101dc578063f851a4401461020357600080fd5b80638a7c195f14610166578063a508ff6c1461017957600080fd5b80636b46c8c3116100a75780636b46c8c314610129578063704b6c02146101405780637f4d39451461015357600080fd5b80632dd31000146100c357806336077b3c14610114575b600080fd5b6100ea7f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98481565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610127610122366004610b10565b610223565b005b61013260005481565b60405190815260200161010b565b61012761014e366004610b55565b6102ba565b610127610161366004610b72565b61039d565b610127610174366004610b8b565b610410565b6100ea7f000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc881565b6101b36101ae366004610bf1565b6104ca565b604080516fffffffffffffffffffffffffffffffff93841681529290911660208301520161010b565b6100ea7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6001546100ea9073ffffffffffffffffffffffffffffffffffffffff1681565b61022b61079e565b6040517f8206a4d100000000000000000000000000000000000000000000000000000000815260ff80841660048301528216602482015273ffffffffffffffffffffffffffffffffffffffff841690638206a4d190604401600060405180830381600087803b15801561029d57600080fd5b505af11580156102b1573d6000803e3d6000fd5b50505050505050565b6102c261079e565b73ffffffffffffffffffffffffffffffffffffffff811661030f576040517fa553972700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015460405173ffffffffffffffffffffffffffffffffffffffff8084169216907fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff9790600090a3600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6103a561079e565b806000036103df576040517fb4230b9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405183927f8f6c5c01f9385e42ed275713f18de607d67ea7f6673e431418c8b286057a220791a3600055565b61041861079e565b6040517f8a7c195f00000000000000000000000000000000000000000000000000000000815262ffffff83166004820152600282900b60248201527f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98473ffffffffffffffffffffffffffffffffffffffff1690638a7c195f90604401600060405180830381600087803b1580156104ae57600080fd5b505af11580156104c2573d6000803e3d6000fd5b505050505050565b60008061053c337f000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc86000547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff166107f1909392919063ffffffff16565b6000546040517f3c6b16ab00000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc873ffffffffffffffffffffffffffffffffffffffff1690633c6b16ab90602401600060405180830381600087803b1580156105c857600080fd5b505af11580156105dc573d6000803e3d6000fd5b50506040517f85b6672900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526fffffffffffffffffffffffffffffffff808916602484015287166044830152600093508392508916906385b667299060640160408051808303816000875af1158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190610c4d565b91509150856fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff1610806106ef5750846fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16105b15610726576040517f0790df8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516fffffffffffffffffffffffffffffffff80851682528316602082015273ffffffffffffffffffffffffffffffffffffffff808a16923392918c16917fd377f58cbc83f844989775f0d4bfa247dbee70bf3d851b8c5f0e0fe51d3b6ef9910160405180910390a49097909650945050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107ef576040517fd064e4bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261088690859061088c565b50505050565b60006108ae73ffffffffffffffffffffffffffffffffffffffff84168361092c565b905080516000141580156108d35750808060200190518101906108d19190610c7c565b155b15610927576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024015b60405180910390fd5b505050565b606061093a83836000610941565b9392505050565b60608147101561097f576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161091e565b6000808573ffffffffffffffffffffffffffffffffffffffff1684866040516109a89190610c9e565b60006040518083038185875af1925050503d80600081146109e5576040519150601f19603f3d011682016040523d82523d6000602084013e6109ea565b606091505b50915091506109fa868383610a04565b9695505050505050565b606082610a1957610a1482610a93565b61093a565b8151158015610a3d575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610a8c576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161091e565b508061093a565b805115610aa35780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b73ffffffffffffffffffffffffffffffffffffffff81168114610ad557600080fd5b803560ff81168114610b0b57600080fd5b919050565b600080600060608486031215610b2557600080fd5b8335610b3081610ad8565b9250610b3e60208501610afa565b9150610b4c60408501610afa565b90509250925092565b600060208284031215610b6757600080fd5b813561093a81610ad8565b600060208284031215610b8457600080fd5b5035919050565b60008060408385031215610b9e57600080fd5b823562ffffff81168114610bb157600080fd5b91506020830135600281900b8114610bc857600080fd5b809150509250929050565b6fffffffffffffffffffffffffffffffff81168114610ad557600080fd5b60008060008060808587031215610c0757600080fd5b8435610c1281610ad8565b93506020850135610c2281610ad8565b92506040850135610c3281610bd3565b91506060850135610c4281610bd3565b939692955090935050565b60008060408385031215610c6057600080fd5b8251610c6b81610bd3565b6020840151909250610bc881610bd3565b600060208284031215610c8e57600080fd5b8151801515811461093a57600080fd5b6000825160005b81811015610cbf5760208186018101518583015201610ca5565b50600092019182525091905056fea264697066735822122008a6b35575393a510061efd1eae133068932958d79f59515eea9f79583b84b1f64736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001a9c8182c09f50c8318d769245bea52c32be35bc0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc8

-----Decoded View---------------
Arg [0] : _admin (address): 0x1a9C8182C09F50C8318d769245beA52c32BE35BC
Arg [1] : _factory (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [2] : _payoutToken (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [3] : _payoutAmount (uint256): 10000000000000000000
Arg [4] : _rewardReceiver (address): 0xE3071e87a7E6dD19A911Dbf1127BA9dD67Aa6fc8

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000001a9c8182c09f50c8318d769245bea52c32be35bc
Arg [1] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [3] : 0000000000000000000000000000000000000000000000008ac7230489e80000
Arg [4] : 000000000000000000000000e3071e87a7e6dd19a911dbf1127ba9dd67aa6fc8


Deployed Bytecode Sourcemap

1865:9601:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3417:54;;;;;;;;228:42:8;216:55;;;198:74;;186:2;171:18;3417:54:4;;;;;;;;6843:211;;;;;;:::i;:::-;;:::i;:::-;;3706:27;;;;;;;;;1232:25:8;;;1220:2;1205:18;3706:27:4;1086:177:8;5286:210:4;;;;;;:::i;:::-;;:::i;5656:262::-;;;;;;:::i;:::-;;:::i;6262:146::-;;;;;;:::i;:::-;;:::i;3857:58::-;;;;;10396:800;;;;;;:::i;:::-;;:::i;:::-;;;;3547:34:8;3608:15;;;3590:34;;3660:15;;;;3655:2;3640:18;;3633:43;3510:18;10396:800:4;3363:319:8;3567:36:4;;;;;4047:20;;;;;;;;;6843:211;6974:19;:17;:19::i;:::-;6999:50;;;;;4358:4:8;4346:17;;;6999:50:4;;;4328:36:8;4400:17;;4380:18;;;4373:45;6999:20:4;;;;;;4301:18:8;;6999:50:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6843:211;;;:::o;5286:210::-;5338:19;:17;:19::i;:::-;5367:23;;;5363:68;;5399:32;;;;;;;;;;;;;;5363:68;5451:5;;5442:26;;;;;;;5451:5;;5442:26;;5451:5;;5442:26;5474:5;:17;;;;;;;;;;;;;;;5286:210::o;5656:262::-;5722:19;:17;:19::i;:::-;5751:16;5771:1;5751:21;5747:71;;5781:37;;;;;;;;;;;;;;5747:71;5845:12;;;5829:47;;5859:16;;5829:47;;;5882:12;:31;5656:262::o;6262:146::-;6335:19;:17;:19::i;:::-;6360:43;;;;;4627:8:8;4615:21;;6360:43:4;;;4597:40:8;4684:1;4673:21;;;4653:18;;;4646:49;6360:7:4;:23;;;;;4570:18:8;;6360:43:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6262:146;;:::o;10396:800::-;10561:7;10570;10585:81;10615:10;10635:15;10653:12;;10585;:29;;;;:81;;;;;;:::i;:::-;10707:12;;10672:48;;;;;;;;1232:25:8;;;;10672:15:4;:34;;;;;1205:18:8;;10672:48:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;10771:71:4;;;;;:21;4926:55:8;;;10771:71:4;;;4908:74:8;5001:34;5071:15;;;5051:18;;;5044:43;5123:15;;5103:18;;;5096:43;10727:16:4;;-1:-1:-1;10727:16:4;;-1:-1:-1;10771:21:4;;;;;4881:18:8;;10771:71:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10726:116;;;;10961:17;10950:28;;:8;:28;;;:60;;;;10993:17;10982:28;;:8;:28;;;10950:60;10946:131;;;11027:43;;;;;;;;;;;;;;10946:131;11087:71;;;3547:34:8;3608:15;;;3590:34;;3660:15;;3655:2;3640:18;;3633:43;11087:71:4;;;;;11115:10;;11087:71;;;;;;3510:18:8;11087:71:4;;;;;;;11172:8;;;;-1:-1:-1;10396:800:4;-1:-1:-1;;;;;10396:800:4:o;11348:116::-;11415:5;;;;11401:10;:19;11397:62;;11429:30;;;;;;;;;;;;;;11397:62;11348:116::o;1702:188:2:-;1829:53;;;1844:18;6145:15:8;;;1829:53:2;;;6127:34:8;6197:15;;6177:18;;;6170:43;6229:18;;;;6222:34;;;1829:53:2;;;;;;;;;;6039:18:8;;;;1829:53:2;;;;;;;;;;;;;;1802:81;;1822:5;;1802:19;:81::i;:::-;1702:188;;;;:::o;4059:629::-;4478:23;4504:33;:27;;;4532:4;4504:27;:33::i;:::-;4478:59;;4551:10;:17;4572:1;4551:22;;:57;;;;;4589:10;4578:30;;;;;;;;;;;;:::i;:::-;4577:31;4551:57;4547:135;;;4631:40;;;;;228:42:8;216:55;;4631:40:2;;;198:74:8;171:18;;4631:40:2;;;;;;;;4547:135;4129:559;4059:629;;:::o;2705:151:3:-;2780:12;2811:38;2833:6;2841:4;2847:1;2811:21;:38::i;:::-;2804:45;2705:151;-1:-1:-1;;;2705:151:3:o;3180:392::-;3279:12;3331:5;3307:21;:29;3303:108;;;3359:41;;;;;3394:4;3359:41;;;198:74:8;171:18;;3359:41:3;14:264:8;3303:108:3;3421:12;3435:23;3462:6;:11;;3481:5;3488:4;3462:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3420:73;;;;3510:55;3537:6;3545:7;3554:10;3510:26;:55::i;:::-;3503:62;3180:392;-1:-1:-1;;;;;;3180:392:3:o;4625:582::-;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;5071:18:3;;;;:23;5045:49;5041:119;;;5121:24;;;;;228:42:8;216:55;;5121:24:3;;;198:74:8;171:18;;5121:24:3;14:264:8;5041:119:3;-1:-1:-1;5180:10:3;5173:17;;5743:516;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;;;;;;;;;;;;;5870:383;5743:516;:::o;283:182:8:-;397:42;390:5;386:54;379:5;376:65;366:93;;455:1;452;445:12;470:156;536:20;;596:4;585:16;;575:27;;565:55;;616:1;613;606:12;565:55;470:156;;;:::o;631:450::-;739:6;747;755;808:2;796:9;787:7;783:23;779:32;776:52;;;824:1;821;814:12;776:52;863:9;850:23;882:59;935:5;882:59;:::i;:::-;960:5;-1:-1:-1;984:36:8;1016:2;1001:18;;984:36;:::i;:::-;974:46;;1039:36;1071:2;1060:9;1056:18;1039:36;:::i;:::-;1029:46;;631:450;;;;;:::o;1268:275::-;1327:6;1380:2;1368:9;1359:7;1355:23;1351:32;1348:52;;;1396:1;1393;1386:12;1348:52;1435:9;1422:23;1454:59;1507:5;1454:59;:::i;1548:180::-;1607:6;1660:2;1648:9;1639:7;1635:23;1631:32;1628:52;;;1676:1;1673;1666:12;1628:52;-1:-1:-1;1699:23:8;;1548:180;-1:-1:-1;1548:180:8:o;1733:443::-;1798:6;1806;1859:2;1847:9;1838:7;1834:23;1830:32;1827:52;;;1875:1;1872;1865:12;1827:52;1914:9;1901:23;1964:8;1957:5;1953:20;1946:5;1943:31;1933:59;;1988:1;1985;1978:12;1933:59;2011:5;-1:-1:-1;2068:2:8;2053:18;;2040:32;2114:1;2103:22;;;2091:35;;2081:63;;2140:1;2137;2130:12;2081:63;2163:7;2153:17;;;1733:443;;;;;:::o;2445:146::-;2531:34;2524:5;2520:46;2513:5;2510:57;2500:85;;2581:1;2578;2571:12;2596:762;2717:6;2725;2733;2741;2794:3;2782:9;2773:7;2769:23;2765:33;2762:53;;;2811:1;2808;2801:12;2762:53;2850:9;2837:23;2869:59;2922:5;2869:59;:::i;:::-;2947:5;-1:-1:-1;3004:2:8;2989:18;;2976:32;3017:61;2976:32;3017:61;:::i;:::-;3097:7;-1:-1:-1;3156:2:8;3141:18;;3128:32;3169:33;3128:32;3169:33;:::i;:::-;3221:7;-1:-1:-1;3280:2:8;3265:18;;3252:32;3293:33;3252:32;3293:33;:::i;:::-;2596:762;;;;-1:-1:-1;2596:762:8;;-1:-1:-1;;2596:762:8:o;5150:385::-;5229:6;5237;5290:2;5278:9;5269:7;5265:23;5261:32;5258:52;;;5306:1;5303;5296:12;5258:52;5338:9;5332:16;5357:31;5382:5;5357:31;:::i;:::-;5457:2;5442:18;;5436:25;5407:5;;-1:-1:-1;5470:33:8;5436:25;5470:33;:::i;6267:277::-;6334:6;6387:2;6375:9;6366:7;6362:23;6358:32;6355:52;;;6403:1;6400;6393:12;6355:52;6435:9;6429:16;6488:5;6481:13;6474:21;6467:5;6464:32;6454:60;;6510:1;6507;6500:12;6549:412;6678:3;6716:6;6710:13;6741:1;6751:129;6765:6;6762:1;6759:13;6751:129;;;6863:4;6847:14;;;6843:25;;6837:32;6824:11;;;6817:53;6780:12;6751:129;;;-1:-1:-1;6935:1:8;6899:16;;6924:13;;;-1:-1:-1;6899:16:8;6549:412;-1:-1:-1;6549:412:8:o

Swarm Source

ipfs://08a6b35575393a510061efd1eae133068932958d79f59515eea9f79583b84b1f

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.