ETH Price: $3,443.76 (+1.54%)
Gas: 4 Gwei

Contract

0x0ac850A303169bD762a06567cAad02a8e680E7B3
 
Transaction Hash
Method
Block
From
To
Value
0x862e65a3c466e3402cda96387af4e486a3bc983761d488603b8bd454dafb2149 Buy Pleb(pending)2024-06-23 1:54:075 days ago1719107647IN
0x0ac850A3...8e680E7B3
0.4 ETH(Pending)(Pending)
Buy Pleb201019172024-06-16 4:19:3512 days ago1718511575IN
0x0ac850A3...8e680E7B3
0.43 ETH0.00489105150
Transfer200937812024-06-15 0:59:1113 days ago1718413151IN
0x0ac850A3...8e680E7B3
0 ETH0.000062972.9990385
Buy Pleb200892742024-06-14 9:53:5914 days ago1718358839IN
0x0ac850A3...8e680E7B3
5 ETH0.000253127.75993054
Buy Pleb200892742024-06-14 9:53:5914 days ago1718358839IN
0x0ac850A3...8e680E7B3
0.15 ETH0.000253127.75993054
Buy Pleb200892742024-06-14 9:53:5914 days ago1718358839IN
0x0ac850A3...8e680E7B3
1 ETH0.000253127.75993054
Buy Community Mi...200866162024-06-14 0:58:4714 days ago1718326727IN
0x0ac850A3...8e680E7B3
1 ETH0.000199586.77374176
Buy Community An...200851412024-06-13 20:00:2314 days ago1718308823IN
0x0ac850A3...8e680E7B3
0.24999904 ETH0.000546412.64443692
Buy Community Re...200851412024-06-13 20:00:2314 days ago1718308823IN
0x0ac850A3...8e680E7B3
0.24999904 ETH0.0005350112.64443692
Buy Holder200851412024-06-13 20:00:2314 days ago1718308823IN
0x0ac850A3...8e680E7B3
1 ETH0.0005124512.64443692
Buy Pleb200851412024-06-13 20:00:2314 days ago1718308823IN
0x0ac850A3...8e680E7B3
0.6 ETH0.0006524712.64443692
Buy Pleb200849762024-06-13 19:26:4714 days ago1718306807IN
0x0ac850A3...8e680E7B3
2 ETH0.0003383310.37219746
Buy Holder200849762024-06-13 19:26:4714 days ago1718306807IN
0x0ac850A3...8e680E7B3
0.3 ETH0.0004207310.37219746
Buy Pleb200849762024-06-13 19:26:4714 days ago1718306807IN
0x0ac850A3...8e680E7B3
0.2 ETH0.0003383310.37219746
Buy Pleb200849762024-06-13 19:26:4714 days ago1718306807IN
0x0ac850A3...8e680E7B3
1 ETH0.0003383310.37219746
Buy Pleb200849762024-06-13 19:26:4714 days ago1718306807IN
0x0ac850A3...8e680E7B3
0.4 ETH0.0003386510.38219746
Buy Pleb200835882024-06-13 14:46:4714 days ago1718290007IN
0x0ac850A3...8e680E7B3
0.05 ETH0.0011499422.31609418
Buy Pleb200819092024-06-13 9:08:2315 days ago1718269703IN
0x0ac850A3...8e680E7B3
0.12 ETH0.0005489710.63863731
Buy Pleb200818932024-06-13 9:05:1115 days ago1718269511IN
0x0ac850A3...8e680E7B3
0.0001 ETH0.0007045410.33000997
Buy Pleb200818602024-06-13 8:58:3515 days ago1718269115IN
0x0ac850A3...8e680E7B3
0.0001 ETH0.0009080710.64518637
Buy Pleb200818582024-06-13 8:58:1115 days ago1718269091IN
0x0ac850A3...8e680E7B3
0.035 ETH0.0006861410.06557121
Buy Pleb200818342024-06-13 8:53:2315 days ago1718268803IN
0x0ac850A3...8e680E7B3
0.01 ETH0.0007753411.37602941
Buy Holder200818292024-06-13 8:52:2315 days ago1718268743IN
0x0ac850A3...8e680E7B3
0.000756 ETH0.0009772512.07347812
Buy Pleb200817922024-06-13 8:44:4715 days ago1718268287IN
0x0ac850A3...8e680E7B3
0.04 ETH0.000883310.35911738
Buy Pleb200817812024-06-13 8:42:3515 days ago1718268155IN
0x0ac850A3...8e680E7B3
0.012 ETH0.000900710.55578224
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
200820962024-06-13 9:45:4715 days ago1718271947
0x0ac850A3...8e680E7B3
5,860.85 ETH
200820712024-06-13 9:40:4715 days ago1718271647
0x0ac850A3...8e680E7B3
1 ETH
200820172024-06-13 9:29:5915 days ago1718270999
0x0ac850A3...8e680E7B3
1 wei
200818932024-06-13 9:05:1115 days ago1718269511
0x0ac850A3...8e680E7B3
0.00009999 ETH
200818602024-06-13 8:58:3515 days ago1718269115
0x0ac850A3...8e680E7B3
0.00009793 ETH
200818582024-06-13 8:58:1115 days ago1718269091
0x0ac850A3...8e680E7B3
0.035 ETH
200818342024-06-13 8:53:2315 days ago1718268803
0x0ac850A3...8e680E7B3
0.01 ETH
200818292024-06-13 8:52:2315 days ago1718268743
0x0ac850A3...8e680E7B3
0.00013031 ETH
200817922024-06-13 8:44:4715 days ago1718268287
0x0ac850A3...8e680E7B3
0.04 ETH
200817812024-06-13 8:42:3515 days ago1718268155
0x0ac850A3...8e680E7B3
0.00198427 ETH
200817662024-06-13 8:39:3515 days ago1718267975
0x0ac850A3...8e680E7B3
0.01000572 ETH
200817632024-06-13 8:38:5915 days ago1718267939
0x0ac850A3...8e680E7B3
0.00400195 ETH
200817592024-06-13 8:38:1115 days ago1718267891
0x0ac850A3...8e680E7B3
0.00040219 ETH
200817542024-06-13 8:37:1115 days ago1718267831
0x0ac850A3...8e680E7B3
0.00999508 ETH
200817542024-06-13 8:37:1115 days ago1718267831
0x0ac850A3...8e680E7B3
0.00575872 ETH
200817532024-06-13 8:36:5915 days ago1718267819
0x0ac850A3...8e680E7B3
0.00219215 ETH
200817532024-06-13 8:36:5915 days ago1718267819
0x0ac850A3...8e680E7B3
0.01989133 ETH
200817532024-06-13 8:36:5915 days ago1718267819
0x0ac850A3...8e680E7B3
0.03998544 ETH
200817502024-06-13 8:36:2315 days ago1718267783
0x0ac850A3...8e680E7B3
0.05998492 ETH
200817502024-06-13 8:36:2315 days ago1718267783
0x0ac850A3...8e680E7B3
0.05800311 ETH
200817502024-06-13 8:36:2315 days ago1718267783
0x0ac850A3...8e680E7B3
0.0484223 ETH
200817482024-06-13 8:35:5915 days ago1718267759
0x0ac850A3...8e680E7B3
0.02000022 ETH
200817452024-06-13 8:35:2315 days ago1718267723
0x0ac850A3...8e680E7B3
0.0100003 ETH
200817442024-06-13 8:35:1115 days ago1718267711
0x0ac850A3...8e680E7B3
0.01990147 ETH
200817442024-06-13 8:35:1115 days ago1718267711
0x0ac850A3...8e680E7B3
0.04978835 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Sale

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
cancun EvmVersion
File 1 of 5 : Sale.sol
// SPDX-License-Identifier: LicenseRef-VPL WITH AGPL-3.0-only
pragma solidity ^0.8.25;

import {
  Ownable
} from "solady/auth/Ownable.sol";
import {
  MerkleProofLib
} from "solady/utils/MerkleProofLib.sol";
import {
  SafeTransferLib
} from "solady/utils/SafeTransferLib.sol";
import {
  ReentrancyGuard
} from "soledge/utils/ReentrancyGuard.sol";

/**
  This is the interface for determining particular ERC-721 or ERC-20 ownership.
*/
interface IBalanceOf {

  /**
    Retrieve the balance that a particular `_owner` has of this token.

    @param _owner The owner to query the balance for.

    @return _ The token balance of `_owner`.
  */
  function balanceOf (
    address _owner
  ) external view returns (uint256);
}

/**
  @custom:benediction DEVS BENEDICAT ET PROTEGAT CONTRACTVM MEVM
  @title A contract to sell the future Remilia ERC-20 token.
  @author Tim Clancy <tim-clancy.eth>
  @custom:terry "God is just. Work is rewarded with blessing if not money. Luck
    is the most important thing, but really it's God."

  A contract to sell the future Remilia ERC-20 token.

  No seed raise, no investors,
  no burdens, no promises,
  just conviction.

  I love you.

  @custom:date May 22nd, 2024.
*/
contract Sale is Ownable, ReentrancyGuard {

  /// An error emitted if the Sale is paused.
  error Paused ();

  /// An error emitted if a caller underpays.
  error InsufficientPayment ();

  /// An error emitted if a caller is not eligible per a snapshot.
  error Ineligible ();

  /// An error emitted if a round has sold out.
  error SoldOut ();

  /// An error emitted if a caller is over their allocation.
  error OverAllocated ();

  /// An error emitted if a caller is over the maximum size per call.
  error OverMax ();

  /// An error emitted if the caller is a loser.
  error Loser ();

  /**
    This struct represents the configuration options for this sale.

    @param owner The address of the initial contract owner.
    @param steps The number of discrete steps to apply for holder sales.
    @param maxSpend The maximum spend in Ether able to be purchased in one call.
    @param anyFill Total slots available to purchase in the any round of the
      community sale.
    @param miladyFill Total slots available to purchase in the Milady round of
      the community sale.
    @param remilioFill Total slots available to purchase in the Remilio round of
      the community sale.
    @param plebPremium The premium paid by plebs, in basis points.
    @param loserPremium The premium paid by losers, in basis points.
    @param basePrice The base price of the public round, in nanoether.
    @param endPrice The end price of the public round, in nanoether.
    @param available The total amount of `token` intended to be sold, 1e18.
    @param milady The address of the Milady NFT.
    @param communityPrice The nanoether price per token of the community round.
    @param remilio The address of the Remilio NFT.
    @param communityAllo The amount of `token` sold in each community slot.
    @param anyRoot The hash tree root of the any community snapshot.
    @param miladyRoot The hash tree root of the Milady community snapshot.
    @param remilioRoot The hash tree root of the Remilio community snapshot.
    @param losers An array of token collection addresses whose holders are
      losers.
  */
  struct Configuration {
    address owner;
    uint8 steps;
    uint8 maxSpend;
    uint16 anyFill;
    uint16 miladyFill;
    uint16 remilioFill;
    uint16 plebPremium;
    uint16 loserPremium;
    uint32 basePrice;
    uint32 endPrice;
    uint32 available;
    address milady;
    uint32 communityPrice;
    address remilio;
    uint96 communityAllo;
    bytes32 anyRoot;
    bytes32 miladyRoot;
    bytes32 remilioRoot;
    address[] losers;
  }

  /// The configuration of this sale.
  Configuration public config;

  /// Precalculate and cache a community round spend amount.
  uint256 private communitySpend;

  /// Track the total number of future token sold.
  uint256 public totalSold;

  /// Track the receipt balance of each address sold to.
  mapping ( address => uint256 ) public receiptBalance;

  /// A mapping to record community sale fill progress.
  mapping ( bytes32 => uint16 ) public communityFill;

  /// A mapping to record caller participation in the community sales.
  mapping ( address => mapping ( bytes32 => bool ) ) public participation;

  /// Whether or not interacting with the sale is paused.
  bool public paused = true;

  /**
    This struct represents the current prices to be paid by either Remilia
    community members or the general non-holding public for sale participation.

    @param remilia The nanoether price paid by Remilia holders.
    @param pleb The nanoether price paid by the general public.
    @param loser The nanoether premium price paid by losers.
  */
  struct CurrentPrices {
    uint256 remilia;
    uint256 pleb;
    uint256 loser;
  }

  /**
    This event is emitted whenever an address is credited with tokens.

    @param destination The address credited with tokens.
    @param amount The amount of tokens credited.
  */
  event Credit (
    address indexed destination,
    uint256 amount
  );

  /**
    A modifier to revert an operation if the owner has paused.
  */
  modifier notPaused () {
    if (paused) {
      revert Paused();
    }
    _;
  }

  /**
    Construct a new instance of the sale contract.

    @param _config A `Configuration` to prepare this sale.
  */
  constructor (
    Configuration memory _config
  ) {
    _initializeOwner(_config.owner);
    config = _config;
    communitySpend = _config.communityPrice * _config.communityAllo / 1e9;
    communityFill[_config.anyRoot] = _config.anyFill;
    communityFill[_config.miladyRoot] = _config.miladyFill;
    communityFill[_config.remilioRoot] = _config.remilioFill;
  }

  /**
    Return the amount of future tokens credited to an address.

    @param _holder The address to retrieve future token credits for.

    @return _ The amount of future token credited to `_holder`.
  */
  function balanceOf (
    address _holder
  ) external view returns (uint256) {
    return receiptBalance[_holder];
  }

  /**
    Allow the owner to pause or unpause the sale.

    @param _status The pause status to set.
  */
  function setPaused (
    bool _status
  ) external onlyOwner {
    paused = _status;
  }

  /**
    A utility function to help transfer Ether out of this contract.

    @param _to The address to transfer Ether to.
    @param _amount The amount of Ether to transfer.
  */
  function _transferEther (
    address _to,
    uint256 _amount
  ) private {
    bool success = SafeTransferLib.trySafeTransferETH(
      _to,
      _amount,
      SafeTransferLib.GAS_STIPEND_NO_STORAGE_WRITES
    );
    if (!success) {
      SafeTransferLib.forceSafeTransferETH(_to, _amount);
    }
  }

  /**
    This is a private helper function to handle the different possible
    community buy options. It exists to be wrapped in normie-digestible names.

    @param _destination An address to receive the purchased tokens.
    @param _root The hash tree root.
    @param _proof A hash tree proof of snapshot eligibility.
  */
  function _processCommunityBuy (
    address _destination,
    bytes32 _root,
    bytes32[] memory _proof
  ) private {

    // Determine payment required.
    if (communitySpend > msg.value) {
      revert InsufficientPayment();
    }

    // Determine snapshot eligibility.
    if (!MerkleProofLib.verify(
      _proof,
      _root,
      keccak256(abi.encodePacked(msg.sender))
    )) {
      revert Ineligible();
    }

    // Prevent overallocating to a single caller.
    if (participation[msg.sender][_root]) {
      revert OverAllocated();
    }

    // Prevent overselling this round.
    if (
      communityFill[_root] == 0 || 
      totalSold + config.communityAllo > uint256(config.available) * 1e18
    ) {
      revert SoldOut();
    }

    // Update state.
    totalSold += config.communityAllo;
    communityFill[_root] = communityFill[_root] - 1;
    participation[msg.sender][_root] = true;

    // Credit the `_destination` the purchased tokens.
    receiptBalance[_destination] =
      receiptBalance[_destination] + config.communityAllo;
    emit Credit(_destination, config.communityAllo);

    // Prevent infiltration by losers.
    for (uint256 i = 0; i < config.losers.length; i++) {
      if (IBalanceOf(config.losers[i]).balanceOf(msg.sender) > 0) {
        revert Loser();
      }
    }

    // Refund the caller any excess payment.
    if (msg.value > communitySpend) {
      uint256 excess = msg.value - communitySpend;
      _transferEther(msg.sender, excess);
    }
  }

  /**
    The Sale has a special, limited portion set aside at the lowest rate for
    any Remilia holder to purchase based on a snapshot. The quanitity available
    for each wallet to purchase is limited.

    @param _destination An address to receive the purchased tokens.
    @param _proof A hash tree proof of snapshot eligibility.
  */
  function buyCommunityAny (
    address _destination,
    bytes32[] memory _proof
  ) external payable nonReentrant notPaused {
    _processCommunityBuy(
      _destination,
      config.anyRoot,
      _proof
    );
  }

  /**
    The Sale has a special, limited portion set aside at the lowest rate for
    Milady holders to purchase based on a snapshot. The quanitity available
    for each wallet to purchase is limited.

    @param _destination An address to receive the purchased tokens.
    @param _proof A hash tree proof of snapshot eligibility.
  */
  function buyCommunityMilady (
    address _destination,
    bytes32[] memory _proof
  ) external payable nonReentrant notPaused {
    _processCommunityBuy(
      _destination,
      config.miladyRoot,
      _proof
    );
  }

  /**
    The Sale has a special, limited portion set aside at the lowest rate for
    Remilio holders to purchase based on a snapshot. The quanitity available
    for each wallet to purchase is limited.

    @param _destination An address to receive the purchased tokens.
    @param _proof A hash tree proof of snapshot eligibility.
  */
  function buyCommunityRemilio (
    address _destination,
    bytes32[] memory _proof
  ) external payable nonReentrant notPaused {
    _processCommunityBuy(
      _destination,
      config.remilioRoot,
      _proof
    );
  }

  /**
    Returns the current prices of the esteemed Remilia token. The price of the
    token depends on the elapsed progress of the sale.

    @return _ The current prices paid by different classes of buyers, refer to
      the `CurrentPrices` struct.
  */
  function currentPrices () public view returns (CurrentPrices memory) {
    uint256 currentBalance = (uint256(config.available) * 1e18) - totalSold;
    uint256 range = uint256(config.endPrice - config.basePrice) * 1e9;
    uint256 sold = (uint256(config.available) * 1e18) - currentBalance;
    uint256 progress = sold * 1e30 / (uint256(config.available) * 1e18);
    uint256 currentPrice = uint256(config.basePrice) * 1e9 + (range * progress) / 1e30; 

    // Progress is stepwise for holders.
    uint256 stepSize = (uint256(config.available) * 1e18) / config.steps;
    uint256 currentStep = sold / stepSize;
    uint256 stepIncrease = range / config.steps;
    uint256 holderPrice = uint256(config.basePrice) * 1e9 + (currentStep * stepIncrease);
    return CurrentPrices({
      remilia: holderPrice,
      pleb: currentPrice * (100_00 + config.plebPremium) / 100_00,
      loser: currentPrice * (100_00 + config.loserPremium) / 100_00
  });
  }

  /**
    Allow the caller to purchase some of the esteemed Remilia token as an
    esteemed Remilia holder.

    @param _amount The amount of token the caller is trying to buy.
    @param _destination An address to receive the purchased tokens.
    @param _proof A hash tree proof of snapshot eligibility.
  */
  function buyHolder (
    uint256 _amount,
    address _destination,
    bytes32[] memory _proof
  ) external payable nonReentrant notPaused {
    uint256 currentPrice = currentPrices().remilia;

    // Determine payment required.
    uint256 spent = currentPrice * _amount / 1e18;
    uint256 value = msg.value;
    if (spent > value) {
      revert InsufficientPayment();
    }

    // Determine snapshot eligibility.
    if (!MerkleProofLib.verify(
      _proof,
      config.anyRoot,
      keccak256(abi.encodePacked(msg.sender))
    ) && IBalanceOf(config.milady).balanceOf(msg.sender) == 0
      && IBalanceOf(config.remilio).balanceOf(msg.sender) == 0) {
      revert Ineligible();
    }

    // Prevent infiltration by losers.
    for (uint256 i = 0; i < config.losers.length; i++) {
      if (IBalanceOf(config.losers[i]).balanceOf(msg.sender) > 0) {
        revert Loser();
      }
    }

    // Prevent overpurchasing in one call.
    if (value > uint256(config.maxSpend) * 1e18) {
      revert OverMax();
    }

    // Prevent overselling this round.
    if (totalSold + _amount > uint256(config.available) * 1e18) {
      revert SoldOut();
    }

    // Credit the `_destination` the purchased tokens.
    totalSold += _amount;
    receiptBalance[_destination] = receiptBalance[_destination] + _amount;
    emit Credit(_destination, _amount);

    // Refund the caller any excess payment.
    if (value > spent) {
      uint256 excess = value - spent;
      _transferEther(msg.sender, excess);
    }
  }

  /**
    Allow the caller to purchase some of the esteemed Remilia token.

    @param _amount The amount of token the caller is trying to buy.
    @param _destination An address to receive the purchased tokens.
  */
  function buyPleb (
    uint256 _amount,
    address _destination
  ) external payable nonReentrant notPaused {
    uint256 currentPrice = currentPrices().pleb;

    // Determine payment required.
    uint256 spent = currentPrice * _amount / 1e18;
    uint256 value = msg.value;
    if (spent > value) {
      revert InsufficientPayment();
    }

    // Prevent infiltration by losers.
    for (uint256 i = 0; i < config.losers.length; i++) {
      if (IBalanceOf(config.losers[i]).balanceOf(msg.sender) > 0) {
        revert Loser();
      }
    }

    // Prevent overpurchasing in one call.
    if (value > uint256(config.maxSpend) * 1e18) {
      revert OverMax();
    }

    // Prevent overselling this round.
    if (totalSold + _amount > uint256(config.available) * 1e18) {
      revert SoldOut();
    }

    // Credit the `_destination` the purchased tokens.
    totalSold += _amount;
    receiptBalance[_destination] = receiptBalance[_destination] + _amount;
    emit Credit(_destination, _amount);

    // Refund the caller any excess payment.
    if (value > spent) {
      uint256 excess = value - spent;
      _transferEther(msg.sender, excess);
    }
  }

  /**
    Allow the caller to purchase some of the esteemed Remilia token.
    Even if they are a loser.

    @param _amount The amount of token the caller is trying to buy.
    @param _destination An address to receive the purchased tokens.
  */
  function buyLoser (
    uint256 _amount,
    address _destination
  ) external payable nonReentrant notPaused {
    uint256 currentPrice = currentPrices().loser;

    // Determine payment required.
    uint256 spent = currentPrice * _amount / 1e18;
    uint256 value = msg.value;
    if (spent > value) {
      revert InsufficientPayment();
    }

    // Prevent overpurchasing in one call.
    if (value > uint256(config.maxSpend) * 1e18) {
      revert OverMax();
    }

    // Prevent overselling this round.
    if (totalSold + _amount > uint256(config.available) * 1e18) {
      revert SoldOut();
    }

    // Credit the `_destination` the purchased tokens.
    totalSold += _amount;
    receiptBalance[_destination] = receiptBalance[_destination] + _amount;
    emit Credit(_destination, _amount);

    // Refund the caller any excess payment.
    if (value > spent) {
      uint256 excess = value - spent;
      _transferEther(msg.sender, excess);
    }
  }

  /**
    Allow the owner to reconfigure this instance of the sale contract.

    @param _config A `Configuration` to prepare this sale.
  */
  function reconfigure (
    Configuration memory _config
  ) external payable onlyOwner {
    config = _config;
    communitySpend = _config.communityPrice * _config.communityAllo / 1e9;
    communityFill[_config.anyRoot] = _config.anyFill;
    communityFill[_config.miladyRoot] = _config.miladyFill;
    communityFill[_config.remilioRoot] = _config.remilioFill;
  }

  /**
    Allow the owner to transfer Ether out of this contract.

    @param _to The address to transfer Ether to.
    @param _amount The amount of Ether to transfer.
  */
  function transferEther (
    address _to,
    uint256 _amount
  ) external payable onlyOwner {
    _transferEther(_to, _amount);
  }

  /**
    Allow the owner of the Sale to transfer ERC-20 tokens out of this contract.
    This is only needed in case we need to save someone very very stupid.

    @param _token The address of the ERC-20 token to transfer.
    @param _to The address to transfer the ERC-20 `_token` to.
    @param _amount The amount of `_token` to transfer.
  */
  function transferToken (
    address _token,
    address _to,
    uint256 _amount
  ) external payable onlyOwner {
    SafeTransferLib.safeTransfer(_token, _to, _amount);
  }
}

File 2 of 5 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 3 of 5 : MerkleProofLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
library MerkleProofLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            MERKLE PROOF VERIFICATION OPERATIONS            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf)
        internal
        pure
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(proof) {
                // Initialize `offset` to the offset of `proof` elements in memory.
                let offset := add(proof, 0x20)
                // Left shift by 5 is equivalent to multiplying by 0x20.
                let end := add(offset, shl(5, mload(proof)))
                // Iterate over proof elements to compute root hash.
                for {} 1 {} {
                    // Slot of `leaf` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(leaf, mload(offset)))
                    // Store elements to hash contiguously in scratch space.
                    // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
                    mstore(scratch, leaf)
                    mstore(xor(scratch, 0x20), mload(offset))
                    // Reuse `leaf` to store the hash to reduce stack operations.
                    leaf := keccak256(0x00, 0x40)
                    offset := add(offset, 0x20)
                    if iszero(lt(offset, end)) { break }
                }
            }
            isValid := eq(leaf, root)
        }
    }

    /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf)
        internal
        pure
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            if proof.length {
                // Left shift by 5 is equivalent to multiplying by 0x20.
                let end := add(proof.offset, shl(5, proof.length))
                // Initialize `offset` to the offset of `proof` in the calldata.
                let offset := proof.offset
                // Iterate over proof elements to compute root hash.
                for {} 1 {} {
                    // Slot of `leaf` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(leaf, calldataload(offset)))
                    // Store elements to hash contiguously in scratch space.
                    // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
                    mstore(scratch, leaf)
                    mstore(xor(scratch, 0x20), calldataload(offset))
                    // Reuse `leaf` to store the hash to reduce stack operations.
                    leaf := keccak256(0x00, 0x40)
                    offset := add(offset, 0x20)
                    if iszero(lt(offset, end)) { break }
                }
            }
            isValid := eq(leaf, root)
        }
    }

    /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
    /// given `proof` and `flags`.
    ///
    /// Note:
    /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
    ///   will always return false.
    /// - The sum of the lengths of `proof` and `leaves` must never overflow.
    /// - Any non-zero word in the `flags` array is treated as true.
    /// - The memory offset of `proof` must be non-zero
    ///   (i.e. `proof` is not pointing to the scratch space).
    function verifyMultiProof(
        bytes32[] memory proof,
        bytes32 root,
        bytes32[] memory leaves,
        bool[] memory flags
    ) internal pure returns (bool isValid) {
        // Rebuilds the root by consuming and producing values on a queue.
        // The queue starts with the `leaves` array, and goes into a `hashes` array.
        // After the process, the last element on the queue is verified
        // to be equal to the `root`.
        //
        // The `flags` array denotes whether the sibling
        // should be popped from the queue (`flag == true`), or
        // should be popped from the `proof` (`flag == false`).
        /// @solidity memory-safe-assembly
        assembly {
            // Cache the lengths of the arrays.
            let leavesLength := mload(leaves)
            let proofLength := mload(proof)
            let flagsLength := mload(flags)

            // Advance the pointers of the arrays to point to the data.
            leaves := add(0x20, leaves)
            proof := add(0x20, proof)
            flags := add(0x20, flags)

            // If the number of flags is correct.
            for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} {
                // For the case where `proof.length + leaves.length == 1`.
                if iszero(flagsLength) {
                    // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
                    isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root)
                    break
                }

                // The required final proof offset if `flagsLength` is not zero, otherwise zero.
                let proofEnd := add(proof, shl(5, proofLength))
                // We can use the free memory space for the queue.
                // We don't need to allocate, since the queue is temporary.
                let hashesFront := mload(0x40)
                // Copy the leaves into the hashes.
                // Sometimes, a little memory expansion costs less than branching.
                // Should cost less, even with a high free memory offset of 0x7d00.
                leavesLength := shl(5, leavesLength)
                for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } {
                    mstore(add(hashesFront, i), mload(add(leaves, i)))
                }
                // Compute the back of the hashes.
                let hashesBack := add(hashesFront, leavesLength)
                // This is the end of the memory for the queue.
                // We recycle `flagsLength` to save on stack variables (sometimes save gas).
                flagsLength := add(hashesBack, shl(5, flagsLength))

                for {} 1 {} {
                    // Pop from `hashes`.
                    let a := mload(hashesFront)
                    // Pop from `hashes`.
                    let b := mload(add(hashesFront, 0x20))
                    hashesFront := add(hashesFront, 0x40)

                    // If the flag is false, load the next proof,
                    // else, pops from the queue.
                    if iszero(mload(flags)) {
                        // Loads the next proof.
                        b := mload(proof)
                        proof := add(proof, 0x20)
                        // Unpop from `hashes`.
                        hashesFront := sub(hashesFront, 0x20)
                    }

                    // Advance to the next flag.
                    flags := add(flags, 0x20)

                    // Slot of `a` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(a, b))
                    // Hash the scratch space and push the result onto the queue.
                    mstore(scratch, a)
                    mstore(xor(scratch, 0x20), b)
                    mstore(hashesBack, keccak256(0x00, 0x40))
                    hashesBack := add(hashesBack, 0x20)
                    if iszero(lt(hashesBack, flagsLength)) { break }
                }
                isValid :=
                    and(
                        // Checks if the last value in the queue is same as the root.
                        eq(mload(sub(hashesBack, 0x20)), root),
                        // And whether all the proofs are used, if required.
                        eq(proofEnd, proof)
                    )
                break
            }
        }
    }

    /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
    /// given `proof` and `flags`.
    ///
    /// Note:
    /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
    ///   will always return false.
    /// - Any non-zero word in the `flags` array is treated as true.
    /// - The calldata offset of `proof` must be non-zero
    ///   (i.e. `proof` is from a regular Solidity function with a 4-byte selector).
    function verifyMultiProofCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32[] calldata leaves,
        bool[] calldata flags
    ) internal pure returns (bool isValid) {
        // Rebuilds the root by consuming and producing values on a queue.
        // The queue starts with the `leaves` array, and goes into a `hashes` array.
        // After the process, the last element on the queue is verified
        // to be equal to the `root`.
        //
        // The `flags` array denotes whether the sibling
        // should be popped from the queue (`flag == true`), or
        // should be popped from the `proof` (`flag == false`).
        /// @solidity memory-safe-assembly
        assembly {
            // If the number of flags is correct.
            for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} {
                // For the case where `proof.length + leaves.length == 1`.
                if iszero(flags.length) {
                    // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
                    // forgefmt: disable-next-item
                    isValid := eq(
                        calldataload(
                            xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length))
                        ),
                        root
                    )
                    break
                }

                // The required final proof offset if `flagsLength` is not zero, otherwise zero.
                let proofEnd := add(proof.offset, shl(5, proof.length))
                // We can use the free memory space for the queue.
                // We don't need to allocate, since the queue is temporary.
                let hashesFront := mload(0x40)
                // Copy the leaves into the hashes.
                // Sometimes, a little memory expansion costs less than branching.
                // Should cost less, even with a high free memory offset of 0x7d00.
                calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length))
                // Compute the back of the hashes.
                let hashesBack := add(hashesFront, shl(5, leaves.length))
                // This is the end of the memory for the queue.
                // We recycle `flagsLength` to save on stack variables (sometimes save gas).
                flags.length := add(hashesBack, shl(5, flags.length))

                // We don't need to make a copy of `proof.offset` or `flags.offset`,
                // as they are pass-by-value (this trick may not always save gas).

                for {} 1 {} {
                    // Pop from `hashes`.
                    let a := mload(hashesFront)
                    // Pop from `hashes`.
                    let b := mload(add(hashesFront, 0x20))
                    hashesFront := add(hashesFront, 0x40)

                    // If the flag is false, load the next proof,
                    // else, pops from the queue.
                    if iszero(calldataload(flags.offset)) {
                        // Loads the next proof.
                        b := calldataload(proof.offset)
                        proof.offset := add(proof.offset, 0x20)
                        // Unpop from `hashes`.
                        hashesFront := sub(hashesFront, 0x20)
                    }

                    // Advance to the next flag offset.
                    flags.offset := add(flags.offset, 0x20)

                    // Slot of `a` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(a, b))
                    // Hash the scratch space and push the result onto the queue.
                    mstore(scratch, a)
                    mstore(xor(scratch, 0x20), b)
                    mstore(hashesBack, keccak256(0x00, 0x40))
                    hashesBack := add(hashesBack, 0x20)
                    if iszero(lt(hashesBack, flags.length)) { break }
                }
                isValid :=
                    and(
                        // Checks if the last value in the queue is same as the root.
                        eq(mload(sub(hashesBack, 0x20)), root),
                        // And whether all the proofs are used, if required.
                        eq(proofEnd, proof.offset)
                    )
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes32 array.
    function emptyProof() internal pure returns (bytes32[] calldata proof) {
        /// @solidity memory-safe-assembly
        assembly {
            proof.length := 0
        }
    }

    /// @dev Returns an empty calldata bytes32 array.
    function emptyLeaves() internal pure returns (bytes32[] calldata leaves) {
        /// @solidity memory-safe-assembly
        assembly {
            leaves.length := 0
        }
    }

    /// @dev Returns an empty calldata bool array.
    function emptyFlags() internal pure returns (bool[] calldata flags) {
        /// @solidity memory-safe-assembly
        assembly {
            flags.length := 0
        }
    }
}

File 4 of 5 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success :=
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 5 of 5 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @notice Reentrancy guard mixin.
/// @author Soledge (https://github.com/vectorized/soledge/blob/main/src/utils/ReentrancyGuard.sol)
///
/// Note: This implementation utilizes the `TSTORE` and `TLOAD` opcodes.
/// Please ensure that the chain you are deploying on supports them.
abstract contract ReentrancyGuard {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CUSTOM ERRORS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions in practice,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      REENTRANCY GUARD                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            tstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/",
    "soledge/=lib/soledge/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"steps","type":"uint8"},{"internalType":"uint8","name":"maxSpend","type":"uint8"},{"internalType":"uint16","name":"anyFill","type":"uint16"},{"internalType":"uint16","name":"miladyFill","type":"uint16"},{"internalType":"uint16","name":"remilioFill","type":"uint16"},{"internalType":"uint16","name":"plebPremium","type":"uint16"},{"internalType":"uint16","name":"loserPremium","type":"uint16"},{"internalType":"uint32","name":"basePrice","type":"uint32"},{"internalType":"uint32","name":"endPrice","type":"uint32"},{"internalType":"uint32","name":"available","type":"uint32"},{"internalType":"address","name":"milady","type":"address"},{"internalType":"uint32","name":"communityPrice","type":"uint32"},{"internalType":"address","name":"remilio","type":"address"},{"internalType":"uint96","name":"communityAllo","type":"uint96"},{"internalType":"bytes32","name":"anyRoot","type":"bytes32"},{"internalType":"bytes32","name":"miladyRoot","type":"bytes32"},{"internalType":"bytes32","name":"remilioRoot","type":"bytes32"},{"internalType":"address[]","name":"losers","type":"address[]"}],"internalType":"struct Sale.Configuration","name":"_config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"Ineligible","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"Loser","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"OverAllocated","type":"error"},{"inputs":[],"name":"OverMax","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"destination","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Credit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"buyCommunityAny","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"buyCommunityMilady","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"buyCommunityRemilio","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"buyHolder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"}],"name":"buyLoser","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_destination","type":"address"}],"name":"buyPleb","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"communityFill","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"steps","type":"uint8"},{"internalType":"uint8","name":"maxSpend","type":"uint8"},{"internalType":"uint16","name":"anyFill","type":"uint16"},{"internalType":"uint16","name":"miladyFill","type":"uint16"},{"internalType":"uint16","name":"remilioFill","type":"uint16"},{"internalType":"uint16","name":"plebPremium","type":"uint16"},{"internalType":"uint16","name":"loserPremium","type":"uint16"},{"internalType":"uint32","name":"basePrice","type":"uint32"},{"internalType":"uint32","name":"endPrice","type":"uint32"},{"internalType":"uint32","name":"available","type":"uint32"},{"internalType":"address","name":"milady","type":"address"},{"internalType":"uint32","name":"communityPrice","type":"uint32"},{"internalType":"address","name":"remilio","type":"address"},{"internalType":"uint96","name":"communityAllo","type":"uint96"},{"internalType":"bytes32","name":"anyRoot","type":"bytes32"},{"internalType":"bytes32","name":"miladyRoot","type":"bytes32"},{"internalType":"bytes32","name":"remilioRoot","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPrices","outputs":[{"components":[{"internalType":"uint256","name":"remilia","type":"uint256"},{"internalType":"uint256","name":"pleb","type":"uint256"},{"internalType":"uint256","name":"loser","type":"uint256"}],"internalType":"struct Sale.CurrentPrices","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"participation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"receiptBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"steps","type":"uint8"},{"internalType":"uint8","name":"maxSpend","type":"uint8"},{"internalType":"uint16","name":"anyFill","type":"uint16"},{"internalType":"uint16","name":"miladyFill","type":"uint16"},{"internalType":"uint16","name":"remilioFill","type":"uint16"},{"internalType":"uint16","name":"plebPremium","type":"uint16"},{"internalType":"uint16","name":"loserPremium","type":"uint16"},{"internalType":"uint32","name":"basePrice","type":"uint32"},{"internalType":"uint32","name":"endPrice","type":"uint32"},{"internalType":"uint32","name":"available","type":"uint32"},{"internalType":"address","name":"milady","type":"address"},{"internalType":"uint32","name":"communityPrice","type":"uint32"},{"internalType":"address","name":"remilio","type":"address"},{"internalType":"uint96","name":"communityAllo","type":"uint96"},{"internalType":"bytes32","name":"anyRoot","type":"bytes32"},{"internalType":"bytes32","name":"miladyRoot","type":"bytes32"},{"internalType":"bytes32","name":"remilioRoot","type":"bytes32"},{"internalType":"address[]","name":"losers","type":"address[]"}],"internalType":"struct Sale.Configuration","name":"_config","type":"tuple"}],"name":"reconfigure","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"_status","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferEther","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToken","outputs":[],"stateMutability":"payable","type":"function"}]

608060405234610597576120c1803803908161001a8161059b565b9182396020818381010312610597578051906001600160401b038211610597576102608282018483010312610597576040519261026084016001600160401b03811185821017610568576040526100728383016105c0565b84526100826020848401016105d4565b60208501526100956040848401016105d4565b60408501526100a86060848401016105e2565b60608501526100bb6080848401016105e2565b60808501526100ce60a0848401016105e2565b60a08501526100e160c0848401016105e2565b60c08501526100f460e0848401016105e2565b60e0850152610108610100848401016105f1565b61010085015261011d610120848401016105f1565b610120850152610132610140848401016105f1565b610140850152610147610160848401016105c0565b61016085015261015c610180848401016105f1565b6101808501526101716101a0848401016105c0565b6101a08501528183016101c001516001600160601b0381168103610597576101c08501528183016101e08181015190860152610200808201519086015261022080820151908601526102400151926001600160401b03841161059757818301601f858386010101121561059757828101840151936001600160401b038511610568578460051b90602061020581840161059b565b8097815201938501602083838689010101011161059757848301810160200193925b60208383838901010101851061057c576102408801878152600d805460ff1916600117905588516001600160a01b0316638b78c6d8198190558991905f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a38151602080840151604080860151606080880151608089015160a08a81015160c0808d015160e0808f01519a90941b60ff60a01b166001600160a01b039c909c169b909b1760a89790971b60ff60a81b169690961760b09490941b61ffff60b01b16939093179190941b61ffff60c01b161760d09190911b61ffff60d01b16179590911b61ffff60e01b169490941760f09290921b6001600160f01b031916919091175f5561010085015161012086015161014087015161016088015191851b67ffffffff000000001663ffffffff93841617931b6bffffffff000000000000000016929092179190931b6001600160601b031990811691909117600155610180850151600280546101a08801516001600160c01b03199190911692909516919091179390921b600160201b600160c01b03169290921790556101c0830151600380549092166001600160601b03919091161790556101e0820151600455610200820151600555610220820151600655518051906001600160401b038211610568576801000000000000000082116105685760075482600755808310610524575b5060200160075f5260205f205f5b838110610507576101808501516101c0860151869163ffffffff166001600160601b03918216029081169081036104f357633b9aca0090046001600160601b031660085560608101516101e08201515f908152600b6020526040808220805461ffff1990811661ffff95861617909155608085015161020086015184528284208054831691861691909117905560a0850151610220909501518352918190208054909216939092169290921790915551611abe90816106038239f35b634e487b7160e01b5f52601160045260245ffd5b82516001600160a01b031681830155602090920191600101610437565b60075f527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889081019083015b81811061055d5750610429565b5f8155600101610550565b634e487b7160e01b5f52604160045260245ffd5b602080809561058a886105c0565b8152019501949350610227565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761056857604052565b51906001600160a01b038216820361059757565b519060ff8216820361059757565b519061ffff8216820361059757565b519063ffffffff821682036105975756fe60806040526004361015610011575f80fd5b5f3560e01c806305b1137b146113535780630c26fbcb1461132557806316c38b3c146112ed57806325692962146112a4578063259bfdd71461126e57806331abae3d14610f0357806335c7d1d314610fdb57806343d5b5c414610fa157806354d1f13d14610f5d5780635c975abb14610f3b57806370a0823114610f03578063715018a614610eba57806379502c5514610db65780637c05399f14610d1c5780638c1ee1e914610ce25780638da5cb5b14610cb85780639106d7ba14610c9b578063b281281c146109fb578063cb42f3571461097e578063db9341e61461029f578063f04e283e14610252578063f2fde38b14610215578063f5537ede146101ab578063f7a924db146101625763fee81cf41461012c575f80fd5b3461015e57602036600319011261015e5761014561137b565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b3461015e57604036600319011261015e576001600160a01b0361018361137b565b165f52600c60205260405f206024355f52602052602060ff60405f2054166040519015158152f35b606036600319011261015e5760205f60446010826101c761137b565b6101cf611391565b6101d7611706565b60145283356034526fa9059cbb00000000000000000000000082525af13d1560015f5114171615610208575f603452005b6390b8ec185f526004601cfd5b602036600319011261015e5761022961137b565b610231611706565b8060601b156102455761024390611a4a565b005b637448fbae5f526004601cfd5b602036600319011261015e5761026661137b565b61026e611706565b63389a75e1600c52805f526020600c209081544211610292575f6102439255611a4a565b636f5e88185f526004601cfd5b602036600319011261015e5767ffffffffffffffff6004351161015e576102606004353603600319011261015e57604051610260810181811067ffffffffffffffff82111761094a576040526102f96004356004016113a7565b81526103096024600435016114b1565b602082015261031c6044600435016114b1565b604082015261032f6064600435016114bf565b60608201526103426084600435016114bf565b608082015261035560a4600435016114bf565b60a082015261036860c4600435016114bf565b60c082015261037b60e4600435016114bf565b60e082015261038f610104600435016114ce565b6101008201526103a4610124600435016114ce565b6101208201526103b9610144600435016114ce565b6101408201526103ce610164600435016113a7565b6101608201526103e3610184600435016114ce565b6101808201526103f86101a4600435016113a7565b6101a08201526101c460043501356bffffffffffffffffffffffff8116810361015e576101c08201526004356101e48101356101e0830152610204810135610200830152610224810135610220830152610244013567ffffffffffffffff811161015e57366023826004350101121561015e57600481813501013561047c816113f9565b9161048a60405193846113d7565b81835260208301903660246004358301600586901b01011161015e576024816004350101915b60246004358301600586901b0101831061095e57858561024082019081526104d6611706565b81516001600160a01b03165f5490602084015160a01b74ff000000000000000000000000000000000000000016604085015160a81b75ff00000000000000000000000000000000000000000016606086015160b01b77ffff0000000000000000000000000000000000000000000016608087015160c01b79ffff000000000000000000000000000000000000000000000000169160a088015160d01b7bffff0000000000000000000000000000000000000000000000000000169360c089015160e01b7dffff00000000000000000000000000000000000000000000000000000000169560e08a015160f01b7fffff00000000000000000000000000000000000000000000000000000000000016977fffffffffffffffffffff0000000000000000000000000000000000000000000016177fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff16177fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16177fffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffff16177fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16177dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161717175f5561010082015163ffffffff1663ffffffff19600154161760015561012082015160015461014084015160401b6bffffffff000000000000000016906bffffffffffffffffffffffff1961016086015160601b169260201b67ffffffff00000000169063ffffffff1617171760015561018082015163ffffffff1663ffffffff1960025416176002556101a08201516002549060201b77ffffffffffffffffffffffffffffffffffffffff0000000016907fffffffffffffffff0000000000000000000000000000000000000000ffffffff16176002556101c08201516bffffffffffffffffffffffff166bffffffffffffffffffffffff1960035416176003556101e08201516004556102008201516005556102208201516006555180519067ffffffffffffffff821161094a5768010000000000000000821161094a5760075482600755808310610906575b5060200160075f5260205f205f5b8381106108e9578463ffffffff610180820151166bffffffffffffffffffffffff6101c083015116026bffffffffffffffffffffffff81169081036108d557633b9aca0090046bffffffffffffffffffffffff1660085560608101516101e08201515f908152600b6020526040808220805461ffff1990811661ffff95861617909155608085015161020086015184528284208054831691861691909117905560a08501516102209095015183529120805490911692909116919091179055005b634e487b7160e01b5f52601160045260245ffd5b60019060206001600160a01b038551169401938184015501610814565b60075f527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889081019083015b81811061093f5750610806565b5f8155600101610932565b634e487b7160e01b5f52604160045260245ffd5b602091828060049361096f876113a7565b815201940193915091506104b0565b6109873661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576004546109b8926117c5565b5f68929eee149b4bd212685d005b7f9e87fac8000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ab143c065f526004601cfd5b604036600319011261015e57600435610a12611391565b9068929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a7640000610a56826020610a4f61153e565b01516114df565b0491348311610c73576007545f5b818110610bbe57505060ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b63ffffffff60015460401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d55711610b6e576001600160a01b03602091610b13857f1bbf55d483639f8103dc4e035af71a4fbdb16c80be740fa3eef81198acefa0949561151d565b6009551692835f52600a8252610b2d8160405f205461151d565b845f52600a835260405f2055604051908152a2803411610b55575f68929eee149b4bd212685d005b610b62610b6891346114f2565b33611722565b806109b8565b7f52df9fe5000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8529eb36000000000000000000000000000000000000000000000000000000005f5260045ffd5b602460206001600160a01b03610bd3846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f91610c37575b50610c0f57600101610a64565b7fe95dadd7000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506020813d8211610c60575b81610c51602093836113d7565b8101031261015e575186610c02565b3d9150610c44565b6040513d5f823e3d90fd5b7fcd1c8867000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015e575f36600319011261015e576020600954604051908152f35b3461015e575f36600319011261015e576020638b78c6d819546001600160a01b0360405191168152f35b610ceb3661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576005546109b8926117c5565b604036600319011261015e57600435610d33611391565b9068929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a7640000610d70826040610a4f61153e565b0491348311610c735760ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b3461015e575f36600319011261015e576102405f546001546002546bffffffffffffffffffffffff60035416600454906001600160a01b03600554936006549560405197838116895260ff8160a01c1660208a015260ff8160a81c1660408a015261ffff8160b01c1660608a015261ffff8160c01c1660808a015261ffff8160d01c1660a08a015261ffff8160e01c1660c08a015260f01c60e089015263ffffffff811661010089015263ffffffff8160201c1661012089015263ffffffff8160401c1661014089015260601c61016088015263ffffffff811661018088015260201c166101a08601526101c08501526101e0840152610200830152610220820152f35b5f36600319011261015e57610ecd611706565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f638b78c6d81955005b3461015e57602036600319011261015e576001600160a01b03610f2461137b565b165f52600a602052602060405f2054604051908152f35b3461015e575f36600319011261015e57602060ff600d54166040519015158152f35b5f36600319011261015e5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b610faa3661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576006546109b8926117c5565b606036600319011261015e57600435610ff2611391565b9060443567ffffffffffffffff811161015e57611013903690600401611411565b9168929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a76400006110548361104e61153e565b516114df565b0492348411610c735761108a9060045460405160208101903360601b8252601481526110816034826113d7565b5190209161177a565b1580611203575b80611190575b611168576007545f5b8181106110e657505060ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b602460206001600160a01b036110fb846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f91611137575b50610c0f576001016110a0565b90506020813d8211611160575b81611151602093836113d7565b8101031261015e57518661112a565b3d9150611144565b7f3cb97240000000000000000000000000000000000000000000000000000000005f5260045ffd5b50602460206001600160a01b03600254821c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f916111d1575b5015611097565b90506020813d6020116111fb575b816111ec602093836113d7565b8101031261015e5751846111ca565b3d91506111df565b506024602060015460601c604051928380926370a0823160e01b82523360048301525afa908115610c68575f9161123c575b5015611091565b90506020813d602011611266575b81611257602093836113d7565b8101031261015e575184611235565b3d915061124a565b3461015e575f36600319011261015e57606061128861153e565b6040805191805183526020810151602084015201516040820152f35b5f36600319011261015e5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461015e57602036600319011261015e5760043580151580910361015e57611313611706565b60ff8019600d5416911617600d555f80f35b3461015e57602036600319011261015e576004355f52600b602052602061ffff60405f205416604051908152f35b604036600319011261015e5761024361136a61137b565b611372611706565b60243590611722565b600435906001600160a01b038216820361015e57565b602435906001600160a01b038216820361015e57565b35906001600160a01b038216820361015e57565b6060810190811067ffffffffffffffff82111761094a57604052565b90601f8019910116810190811067ffffffffffffffff82111761094a57604052565b67ffffffffffffffff811161094a5760051b60200190565b9080601f8301121561015e578135611428816113f9565b9261143660405194856113d7565b81845260208085019260051b82010192831161015e57602001905b82821061145e5750505090565b8135815260209182019101611451565b90604060031983011261015e576004356001600160a01b038116810361015e57916024359067ffffffffffffffff821161015e576114ae91600401611411565b90565b359060ff8216820361015e57565b359061ffff8216820361015e57565b359063ffffffff8216820361015e57565b818102929181159184041417156108d557565b919082039182116108d557565b8115611509570490565b634e487b7160e01b5f52601260045260245ffd5b919082018092116108d557565b61ffff16612710019061ffff82116108d557565b5f6040805161154c816113bb565b828152826020820152015260015463ffffffff8160401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d55763ffffffff611597600954846114f2565b9181811691829160201c160363ffffffff81116108d55763ffffffff1691633b9aca00830292808404633b9aca0014901517156108d5576115d890846114f2565b916c0c9f2c9cd04674edea4000000083028381046c0c9f2c9cd04674edea4000000014841517156108d5578461160d916114ff565b90633b9aca00830292808404633b9aca0014901517156108d557612710926116848261167e61165a6c0c9f2c9cd04674edea400000006116536116bc9861168a986114df565b048561151d565b986116785f549961167260ff8c60a01c1680946114ff565b906114ff565b926114ff565b906114df565b9061151d565b9361ffff6116b5846116ab836116a4818a60e01c1661152a565b16856114df565b049560f01c61152a565b16906114df565b0490604051926116cb846113bb565b83526020830152604082015290565b6007548110156116f25760075f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b638b78c6d81954330361171557565b6382b429005f526004601cfd5b5f38818085856108fcf115611735575050565b81471061176d575f3881808585620186a0f115611750575050565b601691600b915f526073825360ff602053f01561176957565b3838fd5b63b12d13eb5f526004601cfd5b90918151918261178c575b5090501490565b8060208092019360051b0101905b8251811160051b90815260208351911852602060405f2092019181831061179a57915050805f611785565b90916008543410610c73576117f2908360405160208101903360601b8252601481526110816034826113d7565b1561116857335f52600c60205260405f20825f5260205260ff60405f205416611a2257815f52600b60205261ffff60405f2054161580156119d0575b610b6e5761184e6bffffffffffffffffffffffff6003541660095461151d565b600955815f52600b6020525f1961ffff60405f205416019161ffff83116108d5576001600160a01b0392815f52600b60205261ffff60405f20911661ffff19825416179055335f52600c60205260405f20905f5260205260405f20600160ff1982541617905516805f52600a6020526118dc60405f20546bffffffffffffffffffffffff600354169061151d565b815f52600a60205260405f20557f1bbf55d483639f8103dc4e035af71a4fbdb16c80be740fa3eef81198acefa09460206bffffffffffffffffffffffff60035416604051908152a26007545f5b81811061194e57505060085480341161193f5750565b610b6261194c91346114f2565b565b602460206001600160a01b03611963846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f9161199f575b50610c0f57600101611929565b90506020813d82116119c8575b816119b9602093836113d7565b8101031261015e57515f611992565b3d91506119ac565b506119ee6009546bffffffffffffffffffffffff600354169061151d565b63ffffffff60015460401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d5571161182e565b7f5088d84e000000000000000000000000000000000000000000000000000000005f5260045ffd5b6001600160a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3638b78c6d8195556fea2646970667358221220c69d82867dbab0b1dbe4f2abc91d12b24c00afdf28aec9001e8ed83e0be47f6864736f6c634300081a00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f120916a94780633c372e89132262a378d02f8f50000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000017a60000000000000000000000000000000000000000000000000000000059682f000000000000000000000000005af0d9827e0c53e4799bb226655a1de152a425a500000000000000000000000000000000000000000000000000000000000005e9000000000000000000000000d3d9ddd0cf0a5f0bfb8f7fceae075df687eaebab0000000000000000000000000000000000000000000022fd5a6400bf7e880000f9aa34f50c8f3c1c0af2dc07104467e3757130801b85c6e0b9b3e76c8846a3666032a3bdce699fd2161cd712aaa7d0cd1053bbdb4458b4fd078d3d272b760c6f16d28be8f9647d24d66f6fcb4ad91ac859f29edb99528bffcdfa2e1d53bbba0800000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bc4ca0eda7647a8ab7c2061c2e118a18a936f13d00000000000000000000000060e4d786628fea6478f785a6d7e704777c86a7c6

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c806305b1137b146113535780630c26fbcb1461132557806316c38b3c146112ed57806325692962146112a4578063259bfdd71461126e57806331abae3d14610f0357806335c7d1d314610fdb57806343d5b5c414610fa157806354d1f13d14610f5d5780635c975abb14610f3b57806370a0823114610f03578063715018a614610eba57806379502c5514610db65780637c05399f14610d1c5780638c1ee1e914610ce25780638da5cb5b14610cb85780639106d7ba14610c9b578063b281281c146109fb578063cb42f3571461097e578063db9341e61461029f578063f04e283e14610252578063f2fde38b14610215578063f5537ede146101ab578063f7a924db146101625763fee81cf41461012c575f80fd5b3461015e57602036600319011261015e5761014561137b565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b3461015e57604036600319011261015e576001600160a01b0361018361137b565b165f52600c60205260405f206024355f52602052602060ff60405f2054166040519015158152f35b606036600319011261015e5760205f60446010826101c761137b565b6101cf611391565b6101d7611706565b60145283356034526fa9059cbb00000000000000000000000082525af13d1560015f5114171615610208575f603452005b6390b8ec185f526004601cfd5b602036600319011261015e5761022961137b565b610231611706565b8060601b156102455761024390611a4a565b005b637448fbae5f526004601cfd5b602036600319011261015e5761026661137b565b61026e611706565b63389a75e1600c52805f526020600c209081544211610292575f6102439255611a4a565b636f5e88185f526004601cfd5b602036600319011261015e5767ffffffffffffffff6004351161015e576102606004353603600319011261015e57604051610260810181811067ffffffffffffffff82111761094a576040526102f96004356004016113a7565b81526103096024600435016114b1565b602082015261031c6044600435016114b1565b604082015261032f6064600435016114bf565b60608201526103426084600435016114bf565b608082015261035560a4600435016114bf565b60a082015261036860c4600435016114bf565b60c082015261037b60e4600435016114bf565b60e082015261038f610104600435016114ce565b6101008201526103a4610124600435016114ce565b6101208201526103b9610144600435016114ce565b6101408201526103ce610164600435016113a7565b6101608201526103e3610184600435016114ce565b6101808201526103f86101a4600435016113a7565b6101a08201526101c460043501356bffffffffffffffffffffffff8116810361015e576101c08201526004356101e48101356101e0830152610204810135610200830152610224810135610220830152610244013567ffffffffffffffff811161015e57366023826004350101121561015e57600481813501013561047c816113f9565b9161048a60405193846113d7565b81835260208301903660246004358301600586901b01011161015e576024816004350101915b60246004358301600586901b0101831061095e57858561024082019081526104d6611706565b81516001600160a01b03165f5490602084015160a01b74ff000000000000000000000000000000000000000016604085015160a81b75ff00000000000000000000000000000000000000000016606086015160b01b77ffff0000000000000000000000000000000000000000000016608087015160c01b79ffff000000000000000000000000000000000000000000000000169160a088015160d01b7bffff0000000000000000000000000000000000000000000000000000169360c089015160e01b7dffff00000000000000000000000000000000000000000000000000000000169560e08a015160f01b7fffff00000000000000000000000000000000000000000000000000000000000016977fffffffffffffffffffff0000000000000000000000000000000000000000000016177fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff16177fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16177fffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffff16177fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16177dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161717175f5561010082015163ffffffff1663ffffffff19600154161760015561012082015160015461014084015160401b6bffffffff000000000000000016906bffffffffffffffffffffffff1961016086015160601b169260201b67ffffffff00000000169063ffffffff1617171760015561018082015163ffffffff1663ffffffff1960025416176002556101a08201516002549060201b77ffffffffffffffffffffffffffffffffffffffff0000000016907fffffffffffffffff0000000000000000000000000000000000000000ffffffff16176002556101c08201516bffffffffffffffffffffffff166bffffffffffffffffffffffff1960035416176003556101e08201516004556102008201516005556102208201516006555180519067ffffffffffffffff821161094a5768010000000000000000821161094a5760075482600755808310610906575b5060200160075f5260205f205f5b8381106108e9578463ffffffff610180820151166bffffffffffffffffffffffff6101c083015116026bffffffffffffffffffffffff81169081036108d557633b9aca0090046bffffffffffffffffffffffff1660085560608101516101e08201515f908152600b6020526040808220805461ffff1990811661ffff95861617909155608085015161020086015184528284208054831691861691909117905560a08501516102209095015183529120805490911692909116919091179055005b634e487b7160e01b5f52601160045260245ffd5b60019060206001600160a01b038551169401938184015501610814565b60075f527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889081019083015b81811061093f5750610806565b5f8155600101610932565b634e487b7160e01b5f52604160045260245ffd5b602091828060049361096f876113a7565b815201940193915091506104b0565b6109873661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576004546109b8926117c5565b5f68929eee149b4bd212685d005b7f9e87fac8000000000000000000000000000000000000000000000000000000005f5260045ffd5b63ab143c065f526004601cfd5b604036600319011261015e57600435610a12611391565b9068929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a7640000610a56826020610a4f61153e565b01516114df565b0491348311610c73576007545f5b818110610bbe57505060ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b63ffffffff60015460401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d55711610b6e576001600160a01b03602091610b13857f1bbf55d483639f8103dc4e035af71a4fbdb16c80be740fa3eef81198acefa0949561151d565b6009551692835f52600a8252610b2d8160405f205461151d565b845f52600a835260405f2055604051908152a2803411610b55575f68929eee149b4bd212685d005b610b62610b6891346114f2565b33611722565b806109b8565b7f52df9fe5000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8529eb36000000000000000000000000000000000000000000000000000000005f5260045ffd5b602460206001600160a01b03610bd3846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f91610c37575b50610c0f57600101610a64565b7fe95dadd7000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506020813d8211610c60575b81610c51602093836113d7565b8101031261015e575186610c02565b3d9150610c44565b6040513d5f823e3d90fd5b7fcd1c8867000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461015e575f36600319011261015e576020600954604051908152f35b3461015e575f36600319011261015e576020638b78c6d819546001600160a01b0360405191168152f35b610ceb3661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576005546109b8926117c5565b604036600319011261015e57600435610d33611391565b9068929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a7640000610d70826040610a4f61153e565b0491348311610c735760ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b3461015e575f36600319011261015e576102405f546001546002546bffffffffffffffffffffffff60035416600454906001600160a01b03600554936006549560405197838116895260ff8160a01c1660208a015260ff8160a81c1660408a015261ffff8160b01c1660608a015261ffff8160c01c1660808a015261ffff8160d01c1660a08a015261ffff8160e01c1660c08a015260f01c60e089015263ffffffff811661010089015263ffffffff8160201c1661012089015263ffffffff8160401c1661014089015260601c61016088015263ffffffff811661018088015260201c166101a08601526101c08501526101e0840152610200830152610220820152f35b5f36600319011261015e57610ecd611706565b5f638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35f638b78c6d81955005b3461015e57602036600319011261015e576001600160a01b03610f2461137b565b165f52600a602052602060405f2054604051908152f35b3461015e575f36600319011261015e57602060ff600d54166040519015158152f35b5f36600319011261015e5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b610faa3661146e565b68929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c6576006546109b8926117c5565b606036600319011261015e57600435610ff2611391565b9060443567ffffffffffffffff811161015e57611013903690600401611411565b9168929eee149b4bd212685c6109ee573068929eee149b4bd212685d60ff600d54166109c657670de0b6b3a76400006110548361104e61153e565b516114df565b0492348411610c735761108a9060045460405160208101903360601b8252601481526110816034826113d7565b5190209161177a565b1580611203575b80611190575b611168576007545f5b8181106110e657505060ff5f5460a81c16670de0b6b3a7640000810290808204670de0b6b3a764000014901517156108d5573411610b965760095490610aaa838361151d565b602460206001600160a01b036110fb846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f91611137575b50610c0f576001016110a0565b90506020813d8211611160575b81611151602093836113d7565b8101031261015e57518661112a565b3d9150611144565b7f3cb97240000000000000000000000000000000000000000000000000000000005f5260045ffd5b50602460206001600160a01b03600254821c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f916111d1575b5015611097565b90506020813d6020116111fb575b816111ec602093836113d7565b8101031261015e5751846111ca565b3d91506111df565b506024602060015460601c604051928380926370a0823160e01b82523360048301525afa908115610c68575f9161123c575b5015611091565b90506020813d602011611266575b81611257602093836113d7565b8101031261015e575184611235565b3d915061124a565b3461015e575f36600319011261015e57606061128861153e565b6040805191805183526020810151602084015201516040820152f35b5f36600319011261015e5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461015e57602036600319011261015e5760043580151580910361015e57611313611706565b60ff8019600d5416911617600d555f80f35b3461015e57602036600319011261015e576004355f52600b602052602061ffff60405f205416604051908152f35b604036600319011261015e5761024361136a61137b565b611372611706565b60243590611722565b600435906001600160a01b038216820361015e57565b602435906001600160a01b038216820361015e57565b35906001600160a01b038216820361015e57565b6060810190811067ffffffffffffffff82111761094a57604052565b90601f8019910116810190811067ffffffffffffffff82111761094a57604052565b67ffffffffffffffff811161094a5760051b60200190565b9080601f8301121561015e578135611428816113f9565b9261143660405194856113d7565b81845260208085019260051b82010192831161015e57602001905b82821061145e5750505090565b8135815260209182019101611451565b90604060031983011261015e576004356001600160a01b038116810361015e57916024359067ffffffffffffffff821161015e576114ae91600401611411565b90565b359060ff8216820361015e57565b359061ffff8216820361015e57565b359063ffffffff8216820361015e57565b818102929181159184041417156108d557565b919082039182116108d557565b8115611509570490565b634e487b7160e01b5f52601260045260245ffd5b919082018092116108d557565b61ffff16612710019061ffff82116108d557565b5f6040805161154c816113bb565b828152826020820152015260015463ffffffff8160401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d55763ffffffff611597600954846114f2565b9181811691829160201c160363ffffffff81116108d55763ffffffff1691633b9aca00830292808404633b9aca0014901517156108d5576115d890846114f2565b916c0c9f2c9cd04674edea4000000083028381046c0c9f2c9cd04674edea4000000014841517156108d5578461160d916114ff565b90633b9aca00830292808404633b9aca0014901517156108d557612710926116848261167e61165a6c0c9f2c9cd04674edea400000006116536116bc9861168a986114df565b048561151d565b986116785f549961167260ff8c60a01c1680946114ff565b906114ff565b926114ff565b906114df565b9061151d565b9361ffff6116b5846116ab836116a4818a60e01c1661152a565b16856114df565b049560f01c61152a565b16906114df565b0490604051926116cb846113bb565b83526020830152604082015290565b6007548110156116f25760075f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b638b78c6d81954330361171557565b6382b429005f526004601cfd5b5f38818085856108fcf115611735575050565b81471061176d575f3881808585620186a0f115611750575050565b601691600b915f526073825360ff602053f01561176957565b3838fd5b63b12d13eb5f526004601cfd5b90918151918261178c575b5090501490565b8060208092019360051b0101905b8251811160051b90815260208351911852602060405f2092019181831061179a57915050805f611785565b90916008543410610c73576117f2908360405160208101903360601b8252601481526110816034826113d7565b1561116857335f52600c60205260405f20825f5260205260ff60405f205416611a2257815f52600b60205261ffff60405f2054161580156119d0575b610b6e5761184e6bffffffffffffffffffffffff6003541660095461151d565b600955815f52600b6020525f1961ffff60405f205416019161ffff83116108d5576001600160a01b0392815f52600b60205261ffff60405f20911661ffff19825416179055335f52600c60205260405f20905f5260205260405f20600160ff1982541617905516805f52600a6020526118dc60405f20546bffffffffffffffffffffffff600354169061151d565b815f52600a60205260405f20557f1bbf55d483639f8103dc4e035af71a4fbdb16c80be740fa3eef81198acefa09460206bffffffffffffffffffffffff60035416604051908152a26007545f5b81811061194e57505060085480341161193f5750565b610b6261194c91346114f2565b565b602460206001600160a01b03611963846116da565b90549060031b1c16604051928380926370a0823160e01b82523360048301525afa908115610c68575f9161199f575b50610c0f57600101611929565b90506020813d82116119c8575b816119b9602093836113d7565b8101031261015e57515f611992565b3d91506119ac565b506119ee6009546bffffffffffffffffffffffff600354169061151d565b63ffffffff60015460401c1690670de0b6b3a7640000820291808304670de0b6b3a764000014901517156108d5571161182e565b7f5088d84e000000000000000000000000000000000000000000000000000000005f5260045ffd5b6001600160a01b031680638b78c6d819547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3638b78c6d8195556fea2646970667358221220c69d82867dbab0b1dbe4f2abc91d12b24c00afdf28aec9001e8ed83e0be47f6864736f6c634300081a0033

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

0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000f120916a94780633c372e89132262a378d02f8f50000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000017a60000000000000000000000000000000000000000000000000000000059682f000000000000000000000000005af0d9827e0c53e4799bb226655a1de152a425a500000000000000000000000000000000000000000000000000000000000005e9000000000000000000000000d3d9ddd0cf0a5f0bfb8f7fceae075df687eaebab0000000000000000000000000000000000000000000022fd5a6400bf7e880000f9aa34f50c8f3c1c0af2dc07104467e3757130801b85c6e0b9b3e76c8846a3666032a3bdce699fd2161cd712aaa7d0cd1053bbdb4458b4fd078d3d272b760c6f16d28be8f9647d24d66f6fcb4ad91ac859f29edb99528bffcdfa2e1d53bbba0800000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bc4ca0eda7647a8ab7c2061c2e118a18a936f13d00000000000000000000000060e4d786628fea6478f785a6d7e704777c86a7c6

-----Decoded View---------------
Arg [0] : _config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
23 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 000000000000000000000000f120916a94780633c372e89132262a378d02f8f5
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000078
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000fa
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000fa
Arg [7] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [8] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [9] : 00000000000000000000000000000000000000000000000000000000000005e9
Arg [10] : 00000000000000000000000000000000000000000000000000000000000017a6
Arg [11] : 0000000000000000000000000000000000000000000000000000000059682f00
Arg [12] : 0000000000000000000000005af0d9827e0c53e4799bb226655a1de152a425a5
Arg [13] : 00000000000000000000000000000000000000000000000000000000000005e9
Arg [14] : 000000000000000000000000d3d9ddd0cf0a5f0bfb8f7fceae075df687eaebab
Arg [15] : 0000000000000000000000000000000000000000000022fd5a6400bf7e880000
Arg [16] : f9aa34f50c8f3c1c0af2dc07104467e3757130801b85c6e0b9b3e76c8846a366
Arg [17] : 6032a3bdce699fd2161cd712aaa7d0cd1053bbdb4458b4fd078d3d272b760c6f
Arg [18] : 16d28be8f9647d24d66f6fcb4ad91ac859f29edb99528bffcdfa2e1d53bbba08
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000260
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [21] : 000000000000000000000000bc4ca0eda7647a8ab7c2061c2e118a18a936f13d
Arg [22] : 00000000000000000000000060e4d786628fea6478f785a6d7e704777c86a7c6


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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