ETH Price: $3,154.05 (-5.61%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ArchetypeLogic

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 7 : ArchetypeLogic.sol
// SPDX-License-Identifier: MIT
// ArchetypeLogic v0.7.0
//
//        d8888                 888               888
//       d88888                 888               888
//      d88P888                 888               888
//     d88P 888 888d888 .d8888b 88888b.   .d88b.  888888 888  888 88888b.   .d88b.
//    d88P  888 888P"  d88P"    888 "88b d8P  Y8b 888    888  888 888 "88b d8P  Y8b
//   d88P   888 888    888      888  888 88888888 888    888  888 888  888 88888888
//  d8888888888 888    Y88b.    888  888 Y8b.     Y88b.  Y88b 888 888 d88P Y8b.
// d88P     888 888     "Y8888P 888  888  "Y8888   "Y888  "Y88888 88888P"   "Y8888
//                                                            888 888
//                                                       Y8b d88P 888
//                                                        "Y88P"  888

pragma solidity ^0.8.4;

import "./ArchetypePayouts.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "solady/src/utils/MerkleProofLib.sol";
import "solady/src/utils/ECDSA.sol";

error InvalidConfig();
error MintNotYetStarted();
error MintEnded();
error WalletUnauthorizedToMint();
error InsufficientEthSent();
error ExcessiveEthSent();
error Erc20BalanceTooLow();
error MaxSupplyExceeded();
error ListMaxSupplyExceeded();
error NumberOfMintsExceeded();
error MintingPaused();
error InvalidReferral();
error InvalidSignature();
error MaxBatchSizeExceeded();
error BurnToMintDisabled();
error NotTokenOwner();
error NotPlatform();
error NotOwner();
error NotShareholder();
error NotApprovedToTransfer();
error InvalidAmountOfTokens();
error WrongPassword();
error LockedForever();
error Blacklisted();

//
// STRUCTS
//
struct Auth {
  bytes32 key;
  bytes32[] proof;
}

struct MintTier {
  uint16 numMints;
  uint16 mintDiscount; //BPS
}

struct Discount {
  uint16 affiliateDiscount; //BPS
  MintTier[] mintTiers;
}

struct Config {
  string baseUri;
  address affiliateSigner;
  uint32 maxSupply;
  uint32 maxBatchSize;
  uint16 affiliateFee; //BPS
  uint16 defaultRoyalty; //BPS
  Discount discounts;
}

// allocation splits for withdrawn owner funds, must sum to 100%
struct PayoutConfig {
  uint16 ownerBps;
  uint16 platformBps;
  uint16 partnerBps;
  uint16 superAffiliateBps;
  address partner;
  address superAffiliate;
}

struct Options {
  bool uriLocked;
  bool maxSupplyLocked;
  bool affiliateFeeLocked;
  bool discountsLocked;
  bool ownerAltPayoutLocked;
}

struct DutchInvite {
  uint128 price;
  uint128 reservePrice;
  uint128 delta;
  uint32 start;
  uint32 end;
  uint32 limit;
  uint32 maxSupply;
  uint32 interval;
  uint32 unitSize; // mint 1 get x
  address tokenAddress;
  bool isBlacklist;
}

struct Invite {
  uint128 price;
  uint32 start;
  uint32 end;
  uint32 limit;
  uint32 maxSupply;
  uint32 unitSize; // mint 1 get x
  address tokenAddress;
  bool isBlacklist;
}

struct BurnConfig {
  IERC721 archetype;
  address burnAddress;
  bool enabled;
  bool reversed; // side of the ratio (false=burn {ratio} get 1, true=burn 1 get {ratio})
  uint16 ratio;
  uint64 start;
  uint64 limit;
}

struct ValidationArgs {
  address owner;
  address affiliate;
  uint256 quantity;
  uint256 curSupply;
  uint256 listSupply;
}

// UPDATE CONSTANTS BEFORE DEPLOY
address constant PLATFORM = 0x86B82972282Dd22348374bC63fd21620F7ED847B;
address constant BATCH = 0x6Bc558A6DC48dEfa0e7022713c23D65Ab26e4Fa7;
address constant PAYOUTS = 0xaAfdfA4a935d8511bF285af11A0544ce7e4a1199;
uint16 constant MAXBPS = 5000; // max fee or discount is 50%
uint32 constant UINT32_MAX = 2**32 - 1;

library ArchetypeLogic {
  //
  // EVENTS
  //
  event Invited(bytes32 indexed key, bytes32 indexed cid);
  event Referral(address indexed affiliate, address token, uint128 wad, uint256 numMints);
  event Withdrawal(address indexed src, address token, uint128 wad);

  // calculate price based on affiliate usage and mint discounts
  function computePrice(
    DutchInvite storage invite,
    Discount storage discounts,
    uint256 numTokens,
    uint256 listSupply,
    bool affiliateUsed
  ) public view returns (uint256) {
    uint256 price = invite.price;
    uint256 cost;
    if (invite.interval > 0 && invite.delta > 0) {
      // Apply dutch pricing
      uint256 diff = (((block.timestamp - invite.start) / invite.interval) * invite.delta);
      if (price > invite.reservePrice) {
        if (diff > price - invite.reservePrice) {
          price = invite.reservePrice;
        } else {
          price = price - diff;
        }
      } else if (price < invite.reservePrice) {
        if (diff > invite.reservePrice - price) {
          price = invite.reservePrice;
        } else {
          price = price + diff;
        }
      }
      cost = price * numTokens;
    } else if (invite.interval == 0 && invite.delta > 0) {
      // Apply linear curve
      uint256 lastPrice = price + invite.delta * listSupply;
      cost = lastPrice * numTokens + (invite.delta * numTokens * (numTokens - 1)) / 2;
    } else {
      cost = price * numTokens;
    }

    if (affiliateUsed) {
      cost = cost - ((cost * discounts.affiliateDiscount) / 10000);
    }

    uint256 numMints = discounts.mintTiers.length;
    for (uint256 i; i < numMints; ) {
      uint256 tierNumMints = discounts.mintTiers[i].numMints;
      if (numTokens >= tierNumMints) {
        return cost - ((cost * discounts.mintTiers[i].mintDiscount) / 10000);
      }
      unchecked {
        ++i;
      }
    }
    return cost;
  }

  function validateMint(
    DutchInvite storage i,
    Config storage config,
    Auth calldata auth,
    mapping(address => mapping(bytes32 => uint256)) storage minted,
    bytes calldata signature,
    ValidationArgs memory args,
    uint128 cost
  ) public view {
    address msgSender = _msgSender();
    if (args.affiliate != address(0)) {
      if (
        args.affiliate == PLATFORM || args.affiliate == args.owner || args.affiliate == msgSender
      ) {
        revert InvalidReferral();
      }
      validateAffiliate(args.affiliate, signature, config.affiliateSigner);
    }

    if (i.limit == 0) {
      revert MintingPaused();
    }

    if (!i.isBlacklist) {
      if (!verify(auth, i.tokenAddress, msgSender)) {
        revert WalletUnauthorizedToMint();
      }
    } else {
      if (verify(auth, i.tokenAddress, msgSender)) {
        revert Blacklisted();
      }
    }

    if (block.timestamp < i.start) {
      revert MintNotYetStarted();
    }

    if (i.end > i.start && block.timestamp > i.end) {
      revert MintEnded();
    }

    if (i.limit < i.maxSupply) {
      uint256 totalAfterMint = minted[msgSender][auth.key] + args.quantity;

      if (totalAfterMint > i.limit) {
        revert NumberOfMintsExceeded();
      }
    }

    if (i.maxSupply < config.maxSupply) {
      uint256 totalAfterMint = args.listSupply + args.quantity;
      if (totalAfterMint > i.maxSupply) {
        revert ListMaxSupplyExceeded();
      }
    }

    if (args.quantity > config.maxBatchSize) {
      revert MaxBatchSizeExceeded();
    }

    if ((args.curSupply + args.quantity) > config.maxSupply) {
      revert MaxSupplyExceeded();
    }

    if (i.tokenAddress != address(0)) {
      IERC20 erc20Token = IERC20(i.tokenAddress);
      if (erc20Token.allowance(msgSender, address(this)) < cost) {
        revert NotApprovedToTransfer();
      }

      if (erc20Token.balanceOf(msgSender) < cost) {
        revert Erc20BalanceTooLow();
      }

      if (msg.value != 0) {
        revert ExcessiveEthSent();
      }
    } else {
      if (msg.value < cost) {
        revert InsufficientEthSent();
      }
    }
  }

  function validateBurnToMint(
    Config storage config,
    BurnConfig storage burnConfig,
    uint256[] calldata tokenIds,
    uint256 curSupply,
    mapping(address => mapping(bytes32 => uint256)) storage minted
  ) public view {
    if (!burnConfig.enabled) {
      revert BurnToMintDisabled();
    }

    if (block.timestamp < burnConfig.start) {
      revert MintNotYetStarted();
    }

    // check if msgSender owns tokens and has correct approvals
    address msgSender = _msgSender();
    for (uint256 i; i < tokenIds.length; ) {
      if (burnConfig.archetype.ownerOf(tokenIds[i]) != msgSender) {
        revert NotTokenOwner();
      }
      unchecked {
        ++i;
      }
    }

    if (!burnConfig.archetype.isApprovedForAll(msgSender, address(this))) {
      revert NotApprovedToTransfer();
    }

    uint256 quantity;
    if (burnConfig.reversed) {
      quantity = tokenIds.length * burnConfig.ratio;
    } else {
      if (tokenIds.length % burnConfig.ratio != 0) {
        revert InvalidAmountOfTokens();
      }
      quantity = tokenIds.length / burnConfig.ratio;
    }

    if (quantity > config.maxBatchSize) {
      revert MaxBatchSizeExceeded();
    }

    if (burnConfig.limit < config.maxSupply) {
      uint256 totalAfterMint = minted[msgSender][bytes32("burn")] + quantity;

      if (totalAfterMint > burnConfig.limit) {
        revert NumberOfMintsExceeded();
      }
    }

    if ((curSupply + quantity) > config.maxSupply) {
      revert MaxSupplyExceeded();
    }
  }

  function updateBalances(
    DutchInvite storage i,
    Config storage config,
    mapping(address => uint128) storage _ownerBalance,
    mapping(address => mapping(address => uint128)) storage _affiliateBalance,
    address affiliate,
    uint256 quantity,
    uint128 value
  ) public {
    address tokenAddress = i.tokenAddress;

    uint128 affiliateWad;
    if (affiliate != address(0)) {
      affiliateWad = (value * config.affiliateFee) / 10000;
      _affiliateBalance[affiliate][tokenAddress] += affiliateWad;
      emit Referral(affiliate, tokenAddress, affiliateWad, quantity);
    }

    uint128 balance = _ownerBalance[tokenAddress];
    uint128 ownerWad = value - affiliateWad;
    _ownerBalance[tokenAddress] = balance + ownerWad;

    if (tokenAddress != address(0)) {
      IERC20 erc20Token = IERC20(tokenAddress);
      bool success = erc20Token.transferFrom(_msgSender(), address(this), value);
      if (!success) {
        revert TransferFailed();
      }
    }
  }

  function withdrawTokensAffiliate(
    mapping(address => mapping(address => uint128)) storage _affiliateBalance,
    address[] calldata tokens
  ) public {
    address msgSender = _msgSender();

    for (uint256 i; i < tokens.length; i++) {
      address tokenAddress = tokens[i];
      uint128 wad = _affiliateBalance[msgSender][tokenAddress];
      _affiliateBalance[msgSender][tokenAddress] = 0;

      if (wad == 0) {
        revert BalanceEmpty();
      }

      if (tokenAddress == address(0)) {
        bool success = false;
        (success, ) = msgSender.call{ value: wad }("");
        if (!success) {
          revert TransferFailed();
        }
      } else {
        IERC20 erc20Token = IERC20(tokenAddress);
        bool success = erc20Token.transfer(msgSender, wad);
        if (!success) {
          revert TransferFailed();
        }
      }

      emit Withdrawal(msgSender, tokenAddress, wad);
    }
  }

  function withdrawTokens(
    PayoutConfig storage payoutConfig,
    mapping(address => uint128) storage _ownerBalance,
    address owner,
    address[] calldata tokens
  ) public {
    address msgSender = _msgSender();
    for (uint256 i; i < tokens.length; i++) {
      address tokenAddress = tokens[i];
      uint128 wad;

      if (
        msgSender == owner ||
        msgSender == PLATFORM ||
        msgSender == payoutConfig.partner ||
        msgSender == payoutConfig.superAffiliate
      ) {
        wad = _ownerBalance[tokenAddress];
        _ownerBalance[tokenAddress] = 0;
      } else {
        revert NotShareholder();
      }

      if (wad == 0) {
        revert BalanceEmpty();
      }

      address[] memory recipients = new address[](4);
      recipients[0] = owner;
      recipients[1] = PLATFORM;
      recipients[2] = payoutConfig.partner;
      recipients[3] = payoutConfig.superAffiliate;

      uint16[] memory splits = new uint16[](4);
      splits[0] = payoutConfig.ownerBps;
      splits[1] = payoutConfig.platformBps;
      splits[2] = payoutConfig.partnerBps;
      splits[3] = payoutConfig.superAffiliateBps;

      if (tokenAddress == address(0)) {
        ArchetypePayouts(PAYOUTS).updateBalances{ value: wad }(
          wad,
          tokenAddress,
          recipients,
          splits
        );
      } else {
        ArchetypePayouts(PAYOUTS).updateBalances(wad, tokenAddress, recipients, splits);
      }
      emit Withdrawal(msgSender, tokenAddress, wad);
    }
  }

  function validateAffiliate(
    address affiliate,
    bytes calldata signature,
    address affiliateSigner
  ) public view {
    bytes32 signedMessagehash = ECDSA.toEthSignedMessageHash(
      keccak256(abi.encodePacked(affiliate))
    );
    address signer = ECDSA.recover(signedMessagehash, signature);

    if (signer != affiliateSigner) {
      revert InvalidSignature();
    }
  }

  function verify(
    Auth calldata auth,
    address tokenAddress,
    address account
  ) public pure returns (bool) {
    // keys 0-255 and tokenAddress are public
    if (uint256(auth.key) <= 0xff || auth.key == keccak256(abi.encodePacked(tokenAddress))) {
      return true;
    }

    return MerkleProofLib.verify(auth.proof, auth.key, keccak256(abi.encodePacked(account)));
  }

  function _msgSender() internal view returns (address) {
    return msg.sender == BATCH ? tx.origin : msg.sender;
  }
}

File 2 of 7 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 3 of 7 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 4 of 7 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 5 of 7 : ArchetypePayouts.sol
// SPDX-License-Identifier: MIT
// ArchetypePayouts v0.7.0
//
//        d8888                 888               888
//       d88888                 888               888
//      d88P888                 888               888
//     d88P 888 888d888 .d8888b 88888b.   .d88b.  888888 888  888 88888b.   .d88b.
//    d88P  888 888P"  d88P"    888 "88b d8P  Y8b 888    888  888 888 "88b d8P  Y8b
//   d88P   888 888    888      888  888 88888888 888    888  888 888  888 88888888
//  d8888888888 888    Y88b.    888  888 Y8b.     Y88b.  Y88b 888 888 d88P Y8b.
// d88P     888 888     "Y8888P 888  888  "Y8888   "Y888  "Y88888 88888P"   "Y8888
//                                                            888 888
//                                                       Y8b d88P 888
//

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

error InvalidLength();
error InvalidSplitShares();
error TransferFailed();
error BalanceEmpty();
error NotApprovedToWithdraw();

contract ArchetypePayouts {
  event Withdrawal(address indexed src, address token, uint256 wad);
  event FundsAdded(address indexed recipient, address token, uint256 amount);

  mapping(address => mapping(address => uint256)) private _balance;
  mapping(address => mapping(address => bool)) private _approvals;

  function updateBalances(
    uint256 totalAmount,
    address token,
    address[] calldata recipients,
    uint16[] calldata splits
  ) public payable {
    if (recipients.length != splits.length) {
      revert InvalidLength();
    }

    uint256 totalShares = 0;
    for (uint256 i = 0; i < splits.length; i++) {
      totalShares += splits[i];
    }
    if (totalShares != 10000) {
      revert InvalidSplitShares();
    }

    if (token == address(0)) {
      // ETH payments
      uint256 totalReceived = msg.value;
      for (uint256 i = 0; i < recipients.length; i++) {
        if (splits[i] > 0) {
          uint256 amountToAdd = (totalReceived * splits[i]) / 10000;
          _balance[recipients[i]][token] += amountToAdd;
          emit FundsAdded(recipients[i], token, amountToAdd);
        }
      }
    } else {
      // ERC20 payments
      IERC20 paymentToken = IERC20(token);
      bool success = paymentToken.transferFrom(msg.sender, address(this), totalAmount);
      if (!success) {
        revert TransferFailed();
      }

      for (uint256 i = 0; i < recipients.length; i++) {
        if (splits[i] > 0) {
          uint256 amountToAdd = (totalAmount * splits[i]) / 10000;
          _balance[recipients[i]][token] += amountToAdd;
          emit FundsAdded(recipients[i], token, amountToAdd);
        }
      }
    }
  }

  function withdraw() external {
    address msgSender = msg.sender;
    _withdraw(msgSender, msgSender, address(0));
  }

  function withdrawTokens(address[] memory tokens) external {
    address msgSender = msg.sender;

    for (uint256 i = 0; i < tokens.length; i++) {
      _withdraw(msgSender, msgSender, tokens[i]);
    }
  }

  function withdrawFrom(address from, address to) public {
    if (from != msg.sender && !_approvals[from][to]) {
      revert NotApprovedToWithdraw();
    }
    _withdraw(from, to, address(0));
  }

  function withdrawTokensFrom(
    address from,
    address to,
    address[] memory tokens
  ) public {
    if (from != msg.sender && !_approvals[from][to]) {
      revert NotApprovedToWithdraw();
    }
    for (uint256 i = 0; i < tokens.length; i++) {
      _withdraw(from, to, tokens[i]);
    }
  }

  function _withdraw(
    address from,
    address to,
    address token
  ) internal {
    uint256 wad;

    wad = _balance[from][token];
    _balance[from][token] = 0;

    if (wad == 0) {
      revert BalanceEmpty();
    }

    if (token == address(0)) {
      bool success = false;
      (success, ) = to.call{ value: wad }("");
      if (!success) {
        revert TransferFailed();
      }
    } else {
      IERC20 erc20Token = IERC20(token);
      bool success = erc20Token.transfer(to, wad);
      if (!success) {
        revert TransferFailed();
      }
    }
    emit Withdrawal(from, token, wad);
  }

  function approveWithdrawal(address delegate, bool approved) external {
    _approvals[msg.sender][delegate] = approved;
  }

  function isApproved(address from, address delegate) external view returns (bool) {
    return _approvals[from][delegate];
  }

  function balance(address recipient) external view returns (uint256) {
    return _balance[recipient][address(0)];
  }

  function balanceToken(address recipient, address token) external view returns (uint256) {
    return _balance[recipient][token];
  }
}

File 6 of 7 : ECDSA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
library ECDSA {
    function recover(bytes32 hash, bytes calldata signature) internal view returns (address result) {
        assembly {
            if eq(signature.length, 65) {
                // Copy the free memory pointer so that we can restore it later.
                let m := mload(0x40)
                // Directly copy `r` and `s` from the calldata.
                calldatacopy(0x40, signature.offset, 0x40)

                // If `s` in lower half order, such that the signature is not malleable.
                // prettier-ignore
                if iszero(gt(mload(0x60), 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0)) {
                    mstore(0x00, hash)
                    // Compute `v` and store it in the scratch space.
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40))))
                    pop(
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            0x01, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x40, // Start of output.
                            0x20 // Size of output.
                        )
                    )
                    // Restore the zero slot.
                    mstore(0x60, 0)
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    result := mload(sub(0x60, returndatasize()))
                }
                // Restore the free memory pointer.
                mstore(0x40, m)
            }
        }
    }

    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (address result) {
        assembly {
            // Copy the free memory pointer so that we can restore it later.
            let m := mload(0x40)
            // prettier-ignore
            let s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)

            // If `s` in lower half order, such that the signature is not malleable.
            // prettier-ignore
            if iszero(gt(s, 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0)) {
                mstore(0x00, hash)
                mstore(0x20, add(shr(255, vs), 27))
                mstore(0x40, r)
                mstore(0x60, s)
                pop(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        0x01, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x40, // Start of output.
                        0x20 // Size of output.
                    )
                )
                // Restore the zero slot.
                mstore(0x60, 0)
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                result := mload(sub(0x60, returndatasize()))
            }
            // Restore the free memory pointer.
            mstore(0x40, m)
        }
    }

    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        assembly {
            // Store into scratch space for keccak256.
            mstore(0x20, hash)
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32")
            // 0x40 - 0x04 = 0x3c
            result := keccak256(0x04, 0x3c)
        }
    }

    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        assembly {
            // We need at most 128 bytes for Ethereum signed message header.
            // The max length of the ASCII reprenstation of a uint256 is 78 bytes.
            // The length of "\x19Ethereum Signed Message:\n" is 26 bytes (i.e. 0x1a).
            // The next multiple of 32 above 78 + 26 is 128 (i.e. 0x80).

            // Instead of allocating, we temporarily copy the 128 bytes before the
            // start of `s` data to some variables.
            let m3 := mload(sub(s, 0x60))
            let m2 := mload(sub(s, 0x40))
            let m1 := mload(sub(s, 0x20))
            // The length of `s` is in bytes.
            let sLength := mload(s)

            let ptr := add(s, 0x20)

            // `end` marks the end of the memory which we will compute the keccak256 of.
            let end := add(ptr, sLength)

            // Convert the length of the bytes to ASCII decimal representation
            // and store it into the memory.
            // prettier-ignore
            for { let temp := sLength } 1 {} {
                ptr := sub(ptr, 1)
                mstore8(ptr, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            // Copy the header over to the memory.
            mstore(sub(ptr, 0x20), "\x00\x00\x00\x00\x00\x00\x19Ethereum Signed Message:\n")
            // Compute the keccak256 of the memory.
            result := keccak256(sub(ptr, 0x1a), sub(end, sub(ptr, 0x1a)))

            // Restore the previous memory.
            mstore(s, sLength)
            mstore(sub(s, 0x20), m1)
            mstore(sub(s, 0x40), m2)
            mstore(sub(s, 0x60), m3)
        }
    }
}

File 7 of 7 : 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 {
    function verify(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool isValid) {
        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.
                // prettier-ignore
                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)
                    // prettier-ignore
                    if iszero(lt(offset, end)) { break }
                }
            }
            isValid := eq(leaf, root)
        }
    }

    function verifyMultiProof(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32[] calldata leafs,
        bool[] calldata flags
    ) internal pure returns (bool isValid) {
        // Rebuilds the root by consuming and producing values on a queue.
        // The queue starts with the `leafs` 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`).
        assembly {
            // If the number of flags is correct.
            // prettier-ignore
            for {} eq(add(leafs.length, proof.length), add(flags.length, 1)) {} {
                // Left shift by 5 is equivalent to multiplying by 0x20.
                // Compute the end calldata offset of `leafs`.
                let leafsEnd := add(leafs.offset, shl(5, leafs.length))
                // These are the calldata offsets.
                let leafsOffset := leafs.offset
                let flagsOffset := flags.offset
                let proofOffset := proof.offset

                // 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)
                let hashesBack := hashesFront
                // This is the end of the memory for the queue.
                let end := add(hashesBack, shl(5, flags.length))

                // For the case where `proof.length + leafs.length == 1`.
                if iszero(flags.length) {
                    // If `proof.length` is zero, `leafs.length` is 1.
                    if iszero(proof.length) {
                        isValid := eq(calldataload(leafsOffset), root)
                        break
                    }
                    // If `leafs.length` is zero, `proof.length` is 1.
                    if iszero(leafs.length) {
                        isValid := eq(calldataload(proofOffset), root)
                        break
                    }
                }

                // prettier-ignore
                for {} 1 {} {
                    let a := 0
                    // Pops a value from the queue into `a`.
                    switch lt(leafsOffset, leafsEnd)
                    case 0 {
                        // Pop from `hashes` if there are no more leafs.
                        a := mload(hashesFront)
                        hashesFront := add(hashesFront, 0x20)
                    }
                    default {
                        // Otherwise, pop from `leafs`.
                        a := calldataload(leafsOffset)
                        leafsOffset := add(leafsOffset, 0x20)
                    }

                    let b := 0
                    // If the flag is false, load the next proof,
                    // else, pops from the queue.
                    switch calldataload(flagsOffset)
                    case 0 {
                        // Loads the next proof.
                        b := calldataload(proofOffset)
                        proofOffset := add(proofOffset, 0x20)
                    }
                    default {
                        // Pops a value from the queue into `a`.
                        switch lt(leafsOffset, leafsEnd)
                        case 0 {
                            // Pop from `hashes` if there are no more leafs.
                            b := mload(hashesFront)
                            hashesFront := add(hashesFront, 0x20)
                        }
                        default {
                            // Otherwise, pop from `leafs`.
                            b := calldataload(leafsOffset)
                            leafsOffset := add(leafsOffset, 0x20)
                        }
                    }
                    // Advance to the next flag offset.
                    flagsOffset := add(flagsOffset, 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)
                    // prettier-ignore
                    if iszero(lt(hashesBack, end)) { break }
                }
                // Checks if the last value in the queue is same as the root.
                isValid := eq(mload(sub(hashesBack, 0x20)), root)
                break
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"BalanceEmpty","type":"error"},{"inputs":[],"name":"Blacklisted","type":"error"},{"inputs":[],"name":"BurnToMintDisabled","type":"error"},{"inputs":[],"name":"Erc20BalanceTooLow","type":"error"},{"inputs":[],"name":"ExcessiveEthSent","type":"error"},{"inputs":[],"name":"InsufficientEthSent","type":"error"},{"inputs":[],"name":"InvalidAmountOfTokens","type":"error"},{"inputs":[],"name":"InvalidReferral","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"ListMaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MaxBatchSizeExceeded","type":"error"},{"inputs":[],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MintEnded","type":"error"},{"inputs":[],"name":"MintNotYetStarted","type":"error"},{"inputs":[],"name":"MintingPaused","type":"error"},{"inputs":[],"name":"NotApprovedToTransfer","type":"error"},{"inputs":[],"name":"NotShareholder","type":"error"},{"inputs":[],"name":"NotTokenOwner","type":"error"},{"inputs":[],"name":"NumberOfMintsExceeded","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WalletUnauthorizedToMint","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"cid","type":"bytes32"}],"name":"Invited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"numMints","type":"uint256"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"affiliateSigner","type":"address"}],"name":"validateAffiliate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct Auth","name":"auth","type":"tuple"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]

6120ff61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100915760003560e01c80632a70e582116100655780632a70e5821461011157806340fe1ac7146101345780638e1ab866146101475780639b2e2ef31461016757600080fd5b8062973455146100965780630d7f2c6f146100ab5780630e6a2eda146100cb578063140fbc85146100f1575b600080fd5b6100a96100a4366004611c49565b61017a565b005b8180156100b757600080fd5b506100a96100c6366004611be5565b6106dd565b6100de6100d9366004611d64565b610946565b6040519081526020015b60405180910390f35b8180156100fd57600080fd5b506100a961010c366004611ad6565b610c51565b61012461011f366004611b20565b610e96565b60405190151581526020016100e8565b6100a9610142366004611a54565b610f3a565b81801561015357600080fd5b506100a9610162366004611db0565b610fe7565b6100a9610175366004611b82565b6114f2565b6000610184611879565b60208401519091506001600160a01b0316156102415760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806101e2575082600001516001600160a01b031683602001516001600160a01b0316145b806102025750806001600160a01b031683602001516001600160a01b0316145b156102205760405163119833d760e11b815260040160405180910390fd5b602083015160018901546102419190879087906001600160a01b0316610f3a565b6001890154600160c01b900463ffffffff16610270576040516375ab03ab60e11b815260040160405180910390fd5b6002890154600160e01b900460ff166102c65760028901546102a4908890600160401b90046001600160a01b031683610e96565b6102c15760405163d838648f60e01b815260040160405180910390fd5b610305565b60028901546102e7908890600160401b90046001600160a01b031683610e96565b15610305576040516309550c7760e01b815260040160405180910390fd5b6001890154600160801b900463ffffffff1642101561033757604051630e91d3a160e11b815260040160405180910390fd5b600189015463ffffffff600160801b82048116600160a01b9092041611801561037057506001890154600160a01b900463ffffffff1642115b1561038e5760405163124212e560e21b815260040160405180910390fd5b600189015463ffffffff600160e01b82048116600160c01b909204161015610418576040808401516001600160a01b038316600090815260208981528382208b3583529052918220546103e19190611f69565b60018b0154909150600160c01b900463ffffffff16811115610416576040516315fcbc9d60e01b815260040160405180910390fd5b505b600188810154908a0154600160a01b90910463ffffffff908116600160e01b90920416101561048e576000836040015184608001516104579190611f69565b60018b0154909150600160e01b900463ffffffff1681111561048c5760405163103f447360e31b815260040160405180910390fd5b505b60018801546040840151600160c01b90910463ffffffff1610156104c557604051637a7e96df60e01b815260040160405180910390fd5b600188015460408401516060850151600160a01b90920463ffffffff16916104ed9190611f69565b111561050c57604051638a164f6360e01b815260040160405180910390fd5b6002890154600160401b90046001600160a01b0316156106a8576002890154604051636eb1769f60e11b81526001600160a01b038381166004830152306024830152600160401b909204909116906001600160801b03841690829063dd62ed3e9060440160206040518083038186803b15801561058857600080fd5b505afa15801561059c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c09190611e18565b10156105df576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0383811660048301526001600160801b03851691908316906370a082319060240160206040518083038186803b15801561062c57600080fd5b505afa158015610640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106649190611e18565b10156106835760405163046abae760e31b815260040160405180910390fd5b34156106a2576040516301b2422760e61b815260040160405180910390fd5b506106d2565b816001600160801b03163410156106d25760405163f244866f60e01b815260040160405180910390fd5b505050505050505050565b60028701546001600160a01b03600160401b9091048116906000908516156107f95760018801546127109061071d90600160e01b900461ffff1685611fbb565b6107279190611f81565b6001600160a01b0380871660009081526020898152604080832093871683529290529081208054929350839290919061076a9084906001600160801b0316611f3e565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b208383876040516107f0939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906108268386612009565b90506108328183611f3e565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b03939093169290921790915515610939578360006001600160a01b0382166323b872dd610888611879565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201523060248201526001600160801b038a166044820152606401602060405180830381600087803b1580156108de57600080fd5b505af11580156108f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109169190611aba565b905080610936576040516312171d8360e31b815260040160405180910390fd5b50505b5050505050505050505050565b845460028601546000916001600160801b031690829063ffffffff161580159061097c575060018801546001600160801b031615155b15610aa757600188015460028901546000916001600160801b0381169163ffffffff908116916109b591600160801b9091041642612031565b6109bf9190611fa7565b6109c99190611fea565b8954909150600160801b90046001600160801b0316831115610a32578854610a0190600160801b90046001600160801b031684612031565b811115610a21578854600160801b90046001600160801b03169250610a95565b610a2b8184612031565b9250610a95565b8854600160801b90046001600160801b0316831015610a95578854610a68908490600160801b90046001600160801b0316612031565b811115610a88578854600160801b90046001600160801b03169250610a95565b610a928184611f69565b92505b610a9f8784611fea565b915050610b53565b600288015463ffffffff16158015610acb575060018801546001600160801b031615155b15610b46576001880154600090610aec9087906001600160801b0316611fea565b610af69084611f69565b90506002610b05600189612031565b60018b0154610b1e908a906001600160801b0316611fea565b610b289190611fea565b610b329190611fa7565b610b3c8883611fea565b610a9f9190611f69565b610b508683611fea565b90505b8315610b8457865461271090610b6d9061ffff1683611fea565b610b779190611fa7565b610b819082612031565b90505b600187015460005b81811015610c41576000896001018281548110610bb957634e487b7160e01b600052603260045260246000fd5b60009182526020909120015461ffff169050808910610c38576127108a6001018381548110610bf857634e487b7160e01b600052603260045260246000fd5b600091825260209091200154610c189062010000900461ffff1686611fea565b610c229190611fa7565b610c2c9085612031565b95505050505050610c48565b50600101610b8c565b5090925050505b95945050505050565b6000610c5b611879565b905060005b82811015610e8f576000848483818110610c8a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c9f9190611a1c565b6001600160a01b0384811660009081526020898152604080832093851683529290522080546001600160801b031981169091559091506001600160801b031680610cfc576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610d8f576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610d60576040519150601f19603f3d011682016040523d82523d6000602084013e610d65565b606091505b50508091505080610d89576040516312171d8360e31b815260040160405180910390fd5b50610e37565b60405163a9059cbb60e01b815282906000906001600160a01b0383169063a9059cbb90610dc29089908790600401611e30565b602060405180830381600087803b158015610ddc57600080fd5b505af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190611aba565b905080610e34576040516312171d8360e31b815260040160405180910390fd5b50505b836001600160a01b03167f02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f498383604051610e72929190611e30565b60405180910390a250508080610e8790612048565b915050610c60565b5050505050565b600060ff8435111580610edb57506040516001600160601b0319606085901b166020820152603401604051602081830303815290604052805190602001208460000135145b15610ee857506001610f33565b610f30610ef86020860186611ef6565b6040516001600160601b0319606087901b166020820152873590603401604051602081830303815290604052805190602001206118a0565b90505b9392505050565b6040516001600160601b0319606086901b166020820152600090610f9c90603401604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506000610fab8286866118e4565b9050826001600160a01b0316816001600160a01b031614610fdf57604051638baa579f60e01b815260040160405180910390fd5b505050505050565b6000610ff1611879565b905060005b828110156114e957600084848381811061102057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110359190611a1c565b90506000866001600160a01b0316846001600160a01b0316148061107557506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80611093575088546001600160a01b03858116600160401b90920416145b806110ad575060018901546001600160a01b038581169116145b156110e957506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b0316611102565b60405163650a61e160e01b815260040160405180910390fd5b6001600160801b038116611129576040516321cd723f60e21b815260040160405180910390fd5b60408051600480825260a0820190925260009160208201608080368337019050509050878160008151811061116e57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250507386b82972282dd22348374bc63fd21620f7ed847b816001815181106111c457634e487b7160e01b600052603260045260246000fd5b6001600160a01b0392831660209182029290920101528a548251600160401b909104909116908290600290811061120b57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260018b015482519116908290600390811061124c57634e487b7160e01b600052603260045260246000fd5b6001600160a01b039290921660209283029190910182015260408051600480825260a08201909252600092909190820160808036833750508c54825192935061ffff16918391506000906112b057634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b5482516201000090910490911690829060019081106112f157634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b548251640100000000909104909116908290600290811061133457634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b5482516601000000000000909104909116908290600390811061137957634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101526001600160a01b03841661141c576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906001600160801b038616906113e5908790899088908890600401611e52565b6000604051808303818588803b1580156113fe57600080fd5b505af1158015611412573d6000803e3d6000fd5b505050505061148f565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061145c908690889087908790600401611e52565b600060405180830381600087803b15801561147657600080fd5b505af115801561148a573d6000803e3d6000fd5b505050505b856001600160a01b03167f02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f4985856040516114ca929190611e30565b60405180910390a25050505080806114e190612048565b915050610ff6565b50505050505050565b6001850154600160a01b900460ff1661151e57604051631dc68aa160e11b815260040160405180910390fd5b6001850154600160c01b900467ffffffffffffffff1642101561155457604051630e91d3a160e11b815260040160405180910390fd5b600061155e611879565b905060005b848110156116435786546001600160a01b038084169116636352211e88888581811061159f57634e487b7160e01b600052603260045260246000fd5b905060200201356040518263ffffffff1660e01b81526004016115c491815260200190565b60206040518083038186803b1580156115dc57600080fd5b505afa1580156115f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116149190611a38565b6001600160a01b03161461163b576040516359dc379f60e01b815260040160405180910390fd5b600101611563565b50855460405163e985e9c560e01b81526001600160a01b0383811660048301523060248301529091169063e985e9c59060440160206040518083038186803b15801561168e57600080fd5b505afa1580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190611aba565b6116e3576040516302df483560e21b815260040160405180910390fd5b6001860154600090600160a81b900460ff161561171b57600187015461171490600160b01b900461ffff1686611fea565b9050611770565b600187015461173590600160b01b900461ffff1686612063565b1561175357604051630421c69d60e31b815260040160405180910390fd5b600187015461176d90600160b01b900461ffff1686611fa7565b90505b6001880154600160c01b900463ffffffff168111156117a257604051637a7e96df60e01b815260040160405180910390fd5b60018801546002880154600160a01b90910463ffffffff1667ffffffffffffffff9091161015611834576001600160a01b03821660009081526020848152604080832063313ab93760e11b8452909152812054611800908390611f69565b600289015490915067ffffffffffffffff16811115611832576040516315fcbc9d60e01b815260040160405180910390fd5b505b6001880154600160a01b900463ffffffff166118508286611f69565b111561186f57604051638a164f6360e01b815260040160405180910390fd5b5050505050505050565b600033736bc558a6dc48defa0e7022713c23d65ab26e4fa71461189b57503390565b503290565b600083156118dc578360051b8501855b803580851160051b948552602094851852604060002093018181106118d4576118d9565b6118b0565b50505b501492915050565b60006041821415610f33576040516040846040377f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a06060511161194a5784600052604084013560001a602052602060406080600060015afa5060006060523d6060035191505b6040529392505050565b803561195f816120a3565b919050565b60008083601f840112611975578182fd5b50813567ffffffffffffffff81111561198c578182fd5b6020830191508360208260051b85010111156119a757600080fd5b9250929050565b60008083601f8401126119bf578182fd5b50813567ffffffffffffffff8111156119d6578182fd5b6020830191508360208285010111156119a757600080fd5b6000604082840312156119ff578081fd5b50919050565b80356001600160801b038116811461195f57600080fd5b600060208284031215611a2d578081fd5b8135610f33816120a3565b600060208284031215611a49578081fd5b8151610f33816120a3565b60008060008060608587031215611a69578283fd5b8435611a74816120a3565b9350602085013567ffffffffffffffff811115611a8f578384fd5b611a9b878288016119ae565b9094509250506040850135611aaf816120a3565b939692955090935050565b600060208284031215611acb578081fd5b8151610f33816120bb565b600080600060408486031215611aea578283fd5b83359250602084013567ffffffffffffffff811115611b07578283fd5b611b1386828701611964565b9497909650939450505050565b600080600060608486031215611b34578283fd5b833567ffffffffffffffff811115611b4a578384fd5b611b56868287016119ee565b9350506020840135611b67816120a3565b91506040840135611b77816120a3565b809150509250925092565b60008060008060008060a08789031215611b9a578182fd5b8635955060208701359450604087013567ffffffffffffffff811115611bbe578283fd5b611bca89828a01611964565b979a9699509760608101359660809091013595509350505050565b600080600080600080600060e0888a031215611bff578485fd5b873596506020880135955060408801359450606088013593506080880135611c26816120a3565b925060a08801359150611c3b60c08901611a05565b905092959891949750929550565b600080600080600080600080888a03610160811215611c66578283fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115611c8b578485fd5b611c978d838e016119ee565b985060608c0135975060808c0135915080821115611cb3578485fd5b611cbf8d838e016119ae565b909750955085915060a0609f1984011215611cd8578485fd5b604051925060a0830191508282108183111715611d0357634e487b7160e01b85526041600452602485fd5b50604052611d1360a08b01611954565b8152611d2160c08b01611954565b602082015260e08a013560408201526101008a013560608201526101208a013560808201529150611d556101408a01611a05565b90509295985092959890939650565b600080600080600060a08688031215611d7b578283fd5b853594506020860135935060408601359250606086013591506080860135611da2816120bb565b809150509295509295909350565b600080600080600060808688031215611dc7578283fd5b85359450602086013593506040860135611de0816120a3565b9250606086013567ffffffffffffffff811115611dfb578182fd5b611e0788828901611964565b969995985093965092949392505050565b600060208284031215611e29578081fd5b5051919050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6000608082016001600160801b0387168352602060018060a01b03808816828601526080604086015282875180855260a0870191508389019450855b81811015611eac578551841683529484019491840191600101611e8e565b50508581036060870152865180825290830193509050818601845b82811015611ee757815161ffff1685529383019390830190600101611ec7565b50929998505050505050505050565b6000808335601e19843603018112611f0c578283fd5b83018035915067ffffffffffffffff821115611f26578283fd5b6020019150600581901b36038213156119a757600080fd5b60006001600160801b03808316818516808303821115611f6057611f60612077565b01949350505050565b60008219821115611f7c57611f7c612077565b500190565b60006001600160801b0380841680611f9b57611f9b61208d565b92169190910492915050565b600082611fb657611fb661208d565b500490565b60006001600160801b0380831681851681830481118215151615611fe157611fe1612077565b02949350505050565b600081600019048311821515161561200457612004612077565b500290565b60006001600160801b038381169083168181101561202957612029612077565b039392505050565b60008282101561204357612043612077565b500390565b600060001982141561205c5761205c612077565b5060010190565b6000826120725761207261208d565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03811681146120b857600080fd5b50565b80151581146120b857600080fdfea264697066735822122022f1a8166ed06ad32a6ff403cd9ef53a94fc33e4416e322123130e62f9dae9e564736f6c63430008040033

Deployed Bytecode

0x73eb6ef5c20870dd367f06daa723c7aac25bc8afee30146080604052600436106100915760003560e01c80632a70e582116100655780632a70e5821461011157806340fe1ac7146101345780638e1ab866146101475780639b2e2ef31461016757600080fd5b8062973455146100965780630d7f2c6f146100ab5780630e6a2eda146100cb578063140fbc85146100f1575b600080fd5b6100a96100a4366004611c49565b61017a565b005b8180156100b757600080fd5b506100a96100c6366004611be5565b6106dd565b6100de6100d9366004611d64565b610946565b6040519081526020015b60405180910390f35b8180156100fd57600080fd5b506100a961010c366004611ad6565b610c51565b61012461011f366004611b20565b610e96565b60405190151581526020016100e8565b6100a9610142366004611a54565b610f3a565b81801561015357600080fd5b506100a9610162366004611db0565b610fe7565b6100a9610175366004611b82565b6114f2565b6000610184611879565b60208401519091506001600160a01b0316156102415760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806101e2575082600001516001600160a01b031683602001516001600160a01b0316145b806102025750806001600160a01b031683602001516001600160a01b0316145b156102205760405163119833d760e11b815260040160405180910390fd5b602083015160018901546102419190879087906001600160a01b0316610f3a565b6001890154600160c01b900463ffffffff16610270576040516375ab03ab60e11b815260040160405180910390fd5b6002890154600160e01b900460ff166102c65760028901546102a4908890600160401b90046001600160a01b031683610e96565b6102c15760405163d838648f60e01b815260040160405180910390fd5b610305565b60028901546102e7908890600160401b90046001600160a01b031683610e96565b15610305576040516309550c7760e01b815260040160405180910390fd5b6001890154600160801b900463ffffffff1642101561033757604051630e91d3a160e11b815260040160405180910390fd5b600189015463ffffffff600160801b82048116600160a01b9092041611801561037057506001890154600160a01b900463ffffffff1642115b1561038e5760405163124212e560e21b815260040160405180910390fd5b600189015463ffffffff600160e01b82048116600160c01b909204161015610418576040808401516001600160a01b038316600090815260208981528382208b3583529052918220546103e19190611f69565b60018b0154909150600160c01b900463ffffffff16811115610416576040516315fcbc9d60e01b815260040160405180910390fd5b505b600188810154908a0154600160a01b90910463ffffffff908116600160e01b90920416101561048e576000836040015184608001516104579190611f69565b60018b0154909150600160e01b900463ffffffff1681111561048c5760405163103f447360e31b815260040160405180910390fd5b505b60018801546040840151600160c01b90910463ffffffff1610156104c557604051637a7e96df60e01b815260040160405180910390fd5b600188015460408401516060850151600160a01b90920463ffffffff16916104ed9190611f69565b111561050c57604051638a164f6360e01b815260040160405180910390fd5b6002890154600160401b90046001600160a01b0316156106a8576002890154604051636eb1769f60e11b81526001600160a01b038381166004830152306024830152600160401b909204909116906001600160801b03841690829063dd62ed3e9060440160206040518083038186803b15801561058857600080fd5b505afa15801561059c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c09190611e18565b10156105df576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0383811660048301526001600160801b03851691908316906370a082319060240160206040518083038186803b15801561062c57600080fd5b505afa158015610640573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106649190611e18565b10156106835760405163046abae760e31b815260040160405180910390fd5b34156106a2576040516301b2422760e61b815260040160405180910390fd5b506106d2565b816001600160801b03163410156106d25760405163f244866f60e01b815260040160405180910390fd5b505050505050505050565b60028701546001600160a01b03600160401b9091048116906000908516156107f95760018801546127109061071d90600160e01b900461ffff1685611fbb565b6107279190611f81565b6001600160a01b0380871660009081526020898152604080832093871683529290529081208054929350839290919061076a9084906001600160801b0316611f3e565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b208383876040516107f0939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906108268386612009565b90506108328183611f3e565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b03939093169290921790915515610939578360006001600160a01b0382166323b872dd610888611879565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201523060248201526001600160801b038a166044820152606401602060405180830381600087803b1580156108de57600080fd5b505af11580156108f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109169190611aba565b905080610936576040516312171d8360e31b815260040160405180910390fd5b50505b5050505050505050505050565b845460028601546000916001600160801b031690829063ffffffff161580159061097c575060018801546001600160801b031615155b15610aa757600188015460028901546000916001600160801b0381169163ffffffff908116916109b591600160801b9091041642612031565b6109bf9190611fa7565b6109c99190611fea565b8954909150600160801b90046001600160801b0316831115610a32578854610a0190600160801b90046001600160801b031684612031565b811115610a21578854600160801b90046001600160801b03169250610a95565b610a2b8184612031565b9250610a95565b8854600160801b90046001600160801b0316831015610a95578854610a68908490600160801b90046001600160801b0316612031565b811115610a88578854600160801b90046001600160801b03169250610a95565b610a928184611f69565b92505b610a9f8784611fea565b915050610b53565b600288015463ffffffff16158015610acb575060018801546001600160801b031615155b15610b46576001880154600090610aec9087906001600160801b0316611fea565b610af69084611f69565b90506002610b05600189612031565b60018b0154610b1e908a906001600160801b0316611fea565b610b289190611fea565b610b329190611fa7565b610b3c8883611fea565b610a9f9190611f69565b610b508683611fea565b90505b8315610b8457865461271090610b6d9061ffff1683611fea565b610b779190611fa7565b610b819082612031565b90505b600187015460005b81811015610c41576000896001018281548110610bb957634e487b7160e01b600052603260045260246000fd5b60009182526020909120015461ffff169050808910610c38576127108a6001018381548110610bf857634e487b7160e01b600052603260045260246000fd5b600091825260209091200154610c189062010000900461ffff1686611fea565b610c229190611fa7565b610c2c9085612031565b95505050505050610c48565b50600101610b8c565b5090925050505b95945050505050565b6000610c5b611879565b905060005b82811015610e8f576000848483818110610c8a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c9f9190611a1c565b6001600160a01b0384811660009081526020898152604080832093851683529290522080546001600160801b031981169091559091506001600160801b031680610cfc576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610d8f576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610d60576040519150601f19603f3d011682016040523d82523d6000602084013e610d65565b606091505b50508091505080610d89576040516312171d8360e31b815260040160405180910390fd5b50610e37565b60405163a9059cbb60e01b815282906000906001600160a01b0383169063a9059cbb90610dc29089908790600401611e30565b602060405180830381600087803b158015610ddc57600080fd5b505af1158015610df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e149190611aba565b905080610e34576040516312171d8360e31b815260040160405180910390fd5b50505b836001600160a01b03167f02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f498383604051610e72929190611e30565b60405180910390a250508080610e8790612048565b915050610c60565b5050505050565b600060ff8435111580610edb57506040516001600160601b0319606085901b166020820152603401604051602081830303815290604052805190602001208460000135145b15610ee857506001610f33565b610f30610ef86020860186611ef6565b6040516001600160601b0319606087901b166020820152873590603401604051602081830303815290604052805190602001206118a0565b90505b9392505050565b6040516001600160601b0319606086901b166020820152600090610f9c90603401604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506000610fab8286866118e4565b9050826001600160a01b0316816001600160a01b031614610fdf57604051638baa579f60e01b815260040160405180910390fd5b505050505050565b6000610ff1611879565b905060005b828110156114e957600084848381811061102057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906110359190611a1c565b90506000866001600160a01b0316846001600160a01b0316148061107557506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80611093575088546001600160a01b03858116600160401b90920416145b806110ad575060018901546001600160a01b038581169116145b156110e957506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b0316611102565b60405163650a61e160e01b815260040160405180910390fd5b6001600160801b038116611129576040516321cd723f60e21b815260040160405180910390fd5b60408051600480825260a0820190925260009160208201608080368337019050509050878160008151811061116e57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b0316815250507386b82972282dd22348374bc63fd21620f7ed847b816001815181106111c457634e487b7160e01b600052603260045260246000fd5b6001600160a01b0392831660209182029290920101528a548251600160401b909104909116908290600290811061120b57634e487b7160e01b600052603260045260246000fd5b6001600160a01b03928316602091820292909201015260018b015482519116908290600390811061124c57634e487b7160e01b600052603260045260246000fd5b6001600160a01b039290921660209283029190910182015260408051600480825260a08201909252600092909190820160808036833750508c54825192935061ffff16918391506000906112b057634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b5482516201000090910490911690829060019081106112f157634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b548251640100000000909104909116908290600290811061133457634e487b7160e01b600052603260045260246000fd5b61ffff92831660209182029290920101528b5482516601000000000000909104909116908290600390811061137957634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101526001600160a01b03841661141c576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906001600160801b038616906113e5908790899088908890600401611e52565b6000604051808303818588803b1580156113fe57600080fd5b505af1158015611412573d6000803e3d6000fd5b505050505061148f565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061145c908690889087908790600401611e52565b600060405180830381600087803b15801561147657600080fd5b505af115801561148a573d6000803e3d6000fd5b505050505b856001600160a01b03167f02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f4985856040516114ca929190611e30565b60405180910390a25050505080806114e190612048565b915050610ff6565b50505050505050565b6001850154600160a01b900460ff1661151e57604051631dc68aa160e11b815260040160405180910390fd5b6001850154600160c01b900467ffffffffffffffff1642101561155457604051630e91d3a160e11b815260040160405180910390fd5b600061155e611879565b905060005b848110156116435786546001600160a01b038084169116636352211e88888581811061159f57634e487b7160e01b600052603260045260246000fd5b905060200201356040518263ffffffff1660e01b81526004016115c491815260200190565b60206040518083038186803b1580156115dc57600080fd5b505afa1580156115f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116149190611a38565b6001600160a01b03161461163b576040516359dc379f60e01b815260040160405180910390fd5b600101611563565b50855460405163e985e9c560e01b81526001600160a01b0383811660048301523060248301529091169063e985e9c59060440160206040518083038186803b15801561168e57600080fd5b505afa1580156116a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c69190611aba565b6116e3576040516302df483560e21b815260040160405180910390fd5b6001860154600090600160a81b900460ff161561171b57600187015461171490600160b01b900461ffff1686611fea565b9050611770565b600187015461173590600160b01b900461ffff1686612063565b1561175357604051630421c69d60e31b815260040160405180910390fd5b600187015461176d90600160b01b900461ffff1686611fa7565b90505b6001880154600160c01b900463ffffffff168111156117a257604051637a7e96df60e01b815260040160405180910390fd5b60018801546002880154600160a01b90910463ffffffff1667ffffffffffffffff9091161015611834576001600160a01b03821660009081526020848152604080832063313ab93760e11b8452909152812054611800908390611f69565b600289015490915067ffffffffffffffff16811115611832576040516315fcbc9d60e01b815260040160405180910390fd5b505b6001880154600160a01b900463ffffffff166118508286611f69565b111561186f57604051638a164f6360e01b815260040160405180910390fd5b5050505050505050565b600033736bc558a6dc48defa0e7022713c23d65ab26e4fa71461189b57503390565b503290565b600083156118dc578360051b8501855b803580851160051b948552602094851852604060002093018181106118d4576118d9565b6118b0565b50505b501492915050565b60006041821415610f33576040516040846040377f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a06060511161194a5784600052604084013560001a602052602060406080600060015afa5060006060523d6060035191505b6040529392505050565b803561195f816120a3565b919050565b60008083601f840112611975578182fd5b50813567ffffffffffffffff81111561198c578182fd5b6020830191508360208260051b85010111156119a757600080fd5b9250929050565b60008083601f8401126119bf578182fd5b50813567ffffffffffffffff8111156119d6578182fd5b6020830191508360208285010111156119a757600080fd5b6000604082840312156119ff578081fd5b50919050565b80356001600160801b038116811461195f57600080fd5b600060208284031215611a2d578081fd5b8135610f33816120a3565b600060208284031215611a49578081fd5b8151610f33816120a3565b60008060008060608587031215611a69578283fd5b8435611a74816120a3565b9350602085013567ffffffffffffffff811115611a8f578384fd5b611a9b878288016119ae565b9094509250506040850135611aaf816120a3565b939692955090935050565b600060208284031215611acb578081fd5b8151610f33816120bb565b600080600060408486031215611aea578283fd5b83359250602084013567ffffffffffffffff811115611b07578283fd5b611b1386828701611964565b9497909650939450505050565b600080600060608486031215611b34578283fd5b833567ffffffffffffffff811115611b4a578384fd5b611b56868287016119ee565b9350506020840135611b67816120a3565b91506040840135611b77816120a3565b809150509250925092565b60008060008060008060a08789031215611b9a578182fd5b8635955060208701359450604087013567ffffffffffffffff811115611bbe578283fd5b611bca89828a01611964565b979a9699509760608101359660809091013595509350505050565b600080600080600080600060e0888a031215611bff578485fd5b873596506020880135955060408801359450606088013593506080880135611c26816120a3565b925060a08801359150611c3b60c08901611a05565b905092959891949750929550565b600080600080600080600080888a03610160811215611c66578283fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115611c8b578485fd5b611c978d838e016119ee565b985060608c0135975060808c0135915080821115611cb3578485fd5b611cbf8d838e016119ae565b909750955085915060a0609f1984011215611cd8578485fd5b604051925060a0830191508282108183111715611d0357634e487b7160e01b85526041600452602485fd5b50604052611d1360a08b01611954565b8152611d2160c08b01611954565b602082015260e08a013560408201526101008a013560608201526101208a013560808201529150611d556101408a01611a05565b90509295985092959890939650565b600080600080600060a08688031215611d7b578283fd5b853594506020860135935060408601359250606086013591506080860135611da2816120bb565b809150509295509295909350565b600080600080600060808688031215611dc7578283fd5b85359450602086013593506040860135611de0816120a3565b9250606086013567ffffffffffffffff811115611dfb578182fd5b611e0788828901611964565b969995985093965092949392505050565b600060208284031215611e29578081fd5b5051919050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6000608082016001600160801b0387168352602060018060a01b03808816828601526080604086015282875180855260a0870191508389019450855b81811015611eac578551841683529484019491840191600101611e8e565b50508581036060870152865180825290830193509050818601845b82811015611ee757815161ffff1685529383019390830190600101611ec7565b50929998505050505050505050565b6000808335601e19843603018112611f0c578283fd5b83018035915067ffffffffffffffff821115611f26578283fd5b6020019150600581901b36038213156119a757600080fd5b60006001600160801b03808316818516808303821115611f6057611f60612077565b01949350505050565b60008219821115611f7c57611f7c612077565b500190565b60006001600160801b0380841680611f9b57611f9b61208d565b92169190910492915050565b600082611fb657611fb661208d565b500490565b60006001600160801b0380831681851681830481118215151615611fe157611fe1612077565b02949350505050565b600081600019048311821515161561200457612004612077565b500290565b60006001600160801b038381169083168181101561202957612029612077565b039392505050565b60008282101561204357612043612077565b500390565b600060001982141561205c5761205c612077565b5060010190565b6000826120725761207261208d565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03811681146120b857600080fd5b50565b80151581146120b857600080fdfea264697066735822122022f1a8166ed06ad32a6ff403cd9ef53a94fc33e4416e322123130e62f9dae9e564736f6c63430008040033

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

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.