Contract 0x7A8f5B15CFbFf4eaAc055524EC139Ed75Ef6D40A 1

 

Contract Overview

Balance:
0 MATIC

MATIC Value:
$0.00

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xa06861cf4f5f5ff69fb8205bc1fda3055112134d8d302fa24ba26335c7d4858cGet Creator Annu...179874092021-08-14 21:24:4442 days 21 hrs ago0x757026efa43363770df21bb71e3f25ab82c7b68b IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000030068003
0xfa690f61ce25306a6938a21ea4206afb3c2260cd70e1f1c819d5f622b528ca78Get Creator Annu...179872702021-08-14 21:19:5842 days 22 hrs ago0x757026efa43363770df21bb71e3f25ab82c7b68b IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000030068003
0xf9037164939a6ae5d30449e1426d71377c780e803f2f525d5014f1898a5acdc9Set Creator Annu...179842942021-08-14 19:20:4943 days 2 mins ago0x6ef56119fa6b44830f3763a6d29d7bf6b2fadaa8 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.00024747403
0x8d160703699822496b7db96bdec317d5259d634cf04520e1b97c5b39aa01adf0Set Creator Annu...179841052021-08-14 19:13:0143 days 9 mins ago0x6ef56119fa6b44830f3763a6d29d7bf6b2fadaa8 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000385525
0x8e59d0e4186ba8d12c8fef509bc5cce67d3c9372f3d48439a2f14fef6395fde5Set Creator Annu...179839812021-08-14 19:07:2143 days 15 mins ago0x6ef56119fa6b44830f3763a6d29d7bf6b2fadaa8 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.0002324283
0x6159b1d66b25629ab93319b821b1578b199be8031df0294e1ce21cecb9671d47Enable Nft Contr...160357942021-06-23 0:07:5895 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000829875
0x5b04b811aba220fcbcdd3109ca31d19c7a413b4cb49616301aa4f148f5304bf7Enable Nft Contr...160357682021-06-23 0:07:0295 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000829875
0xa5d644ea5d390a30403b7cb0938287c57d0ec6f7eaed86a00b68a48fe191301dRegister Wallet ...160357402021-06-23 0:06:0695 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.00084081
0xe38f2275e4532d16ecf900e7cef1a0cba69c02188a65a28d29b7a3233da30918Register Basket ...160357232021-06-23 0:05:3295 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.000840045
0x9bce49588a17c9dfd75ecfc1c1d140334f0cdd5ce509d0c49b70f0c50ba6b4deRegister Wallet ...160357122021-06-23 0:05:1095 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.00084201
0x49e5b593a2525281b7c0f9a0327438d6059d6d7e0da1fc53190da497c0f98aa0Set Temp Lock Ex...160357022021-06-23 0:04:4695 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  0x7a8f5b15cfbff4eaac055524ec139ed75ef6d40a0 MATIC0.00073659
0xcc5c70da3e57cb97cf23b262a779f6fdf4aa010064bc0a364b9249ea7acb26c40x60806040160350222021-06-22 23:41:2295 days 19 hrs ago0xb8d175f16742395f530e0b3bc1d30bd06b78cda9 IN  Contract Creation0 MATIC0.048188205
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ChargedSettings

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 21 : ChargedSettings.sol
// SPDX-License-Identifier: MIT

// ChargedSettings.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity 0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

import "./interfaces/IChargedSettings.sol";

import "./lib/Bitwise.sol";
import "./lib/TokenInfo.sol";
import "./lib/RelayRecipient.sol";
import "./lib/BlackholePrevention.sol";

/**
 * @notice Charged Particles Settings Contract
 */
contract ChargedSettings is
  IChargedSettings,
  Ownable,
  RelayRecipient,
  BlackholePrevention
{
  using SafeMath for uint256;
  using TokenInfo for address;
  using Bitwise for uint32;

  uint256 constant internal MAX_ANNUITIES = 1e4;      // 10000  (100%)

  // NftSettings - actionPerms
  uint32 constant internal PERM_CHARGE_NFT        = 1;    // NFT Contracts that can have assets Deposited into them (Charged)
  uint32 constant internal PERM_BASKET_NFT        = 2;    // NFT Contracts that can have other NFTs Deposited into them
  uint32 constant internal PERM_TIMELOCK_ANY_NFT  = 4;    // NFT Contracts that can timelock any NFT on behalf of users (primarily used for Front-run Protection)
  uint32 constant internal PERM_TIMELOCK_OWN_NFT  = 8;    // NFT Contracts that can timelock their own NFTs on behalf of their users
  uint32 constant internal PERM_RESTRICTED_ASSETS = 16;   // NFT Contracts that have restricted deposits to specific assets

  // Current Settings for External NFT Token Contracts;
  //  - Any user can add any ERC721 or ERC1155 token as a Charged Particle without Limits,
  //    unless the Owner of the ERC721 or ERC1155 token contract registers the token
  //    and sets the Custom Settings for their token(s)
  struct NftSettings {
    uint32 actionPerms;

    string requiredWalletManager;
    string requiredBasketManager;

    // ERC20
    mapping (address => bool) allowedAssetTokens;
    mapping (address => uint256) depositMin;  // Asset Token Address => Min
    mapping (address => uint256) depositMax;  // Asset Token Address => Max

    // ERC721 / ERC1155
    mapping (address => uint256) maxNfts;     // NFT Token Address => Max
  }

  // Optional Configs for individual NFTs set by NFT Creator
  struct CreatorSettings {
    uint256 annuityPercent;
    address annuityRedirect;
  }

  mapping (address => uint256) internal _depositCap;
  uint256 internal _tempLockExpiryBlocks;

  // Wallet/Basket Managers (by Unique Manager ID)
  mapping (string => IWalletManager) internal _ftWalletManager;
  mapping (string => IBasketManager) internal _nftBasketManager;

  // Settings for individual NFTs set by NFT Creator (by Token UUID)
  mapping (uint256 => CreatorSettings) internal _creatorSettings;

  // Settings for External NFT Token Contracts (by Token Contract Address)
  mapping (address => NftSettings) internal _nftSettings;


  /***********************************|
  |               Public              |
  |__________________________________*/

  /// @notice Checks if an Account is the Owner of an NFT Contract
  ///    When Custom Contracts are registered, only the "owner" or operator of the Contract
  ///    is allowed to register them and define custom rules for how their tokens are "Charged".
  ///    Otherwise, any token can be "Charged" according to the default rules of Charged Particles.
  /// @param contractAddress  The Address to the External NFT Contract to check
  /// @param account          The Account to check if it is the Owner of the specified Contract
  /// @return True if the account is the Owner of the _contract
  function isContractOwner(address contractAddress, address account) external view override virtual returns (bool) {
    return contractAddress.isContractOwner(account);
  }

  function isWalletManagerEnabled(string calldata walletManagerId) external virtual override view returns (bool) {
    return _isWalletManagerEnabled(walletManagerId);
  }

  function getWalletManager(string calldata walletManagerId) external virtual override view returns (IWalletManager) {
    return _ftWalletManager[walletManagerId];
  }

  function isNftBasketEnabled(string calldata basketId) external virtual override view returns (bool) {
    return _isNftBasketEnabled(basketId);
  }

  function getBasketManager(string calldata basketId) external virtual override view returns (IBasketManager) {
    return _nftBasketManager[basketId];
  }


  /// @dev Gets the amount of creator annuities reserved for the creator for the specified NFT
  /// @param contractAddress The Address to the Contract of the NFT
  /// @param tokenId         The Token ID of the NFT
  /// @return creator The address of the creator
  /// @return annuityPct The percentage amount of annuities reserved for the creator
  function getCreatorAnnuities(
    address contractAddress,
    uint256 tokenId
  )
    external
    view
    override
    virtual
    returns (address creator, uint256 annuityPct)
  {
    uint256 tokenUuid = contractAddress.getTokenUUID(tokenId);
    creator = contractAddress.getTokenCreator(tokenId);
    annuityPct = _creatorSettings[tokenUuid].annuityPercent;
  }

  function getCreatorAnnuitiesRedirect(address contractAddress, uint256 tokenId)
    external
    view
    override
    virtual
    returns (address)
  {
    uint256 tokenUuid = contractAddress.getTokenUUID(tokenId);
    return _creatorSettings[tokenUuid].annuityRedirect;
  }

  function getTempLockExpiryBlocks() external view override virtual returns (uint256) {
    return _tempLockExpiryBlocks;
  }

  function getTimelockApprovals(address operator)
    external
    view
    override
    virtual
    returns (bool timelockAny, bool timelockOwn)
  {
    timelockAny = _nftSettings[operator].actionPerms.hasBit(PERM_TIMELOCK_ANY_NFT);
    timelockOwn = _nftSettings[operator].actionPerms.hasBit(PERM_TIMELOCK_OWN_NFT);
  }

  function getAssetRequirements(address contractAddress, address assetToken)
    external
    view
    override
    virtual
    returns (
      string memory requiredWalletManager,
      bool energizeEnabled,
      bool restrictedAssets,
      bool validAsset,
      uint256 depositCap,
      uint256 depositMin,
      uint256 depositMax
    )
  {
    requiredWalletManager = _nftSettings[contractAddress].requiredWalletManager;
    energizeEnabled = _nftSettings[contractAddress].actionPerms.hasBit(PERM_CHARGE_NFT);
    restrictedAssets = _nftSettings[contractAddress].actionPerms.hasBit(PERM_RESTRICTED_ASSETS);
    validAsset = _nftSettings[contractAddress].allowedAssetTokens[assetToken];
    depositCap = _depositCap[assetToken];
    depositMin = _nftSettings[contractAddress].depositMin[assetToken];
    depositMax = _nftSettings[contractAddress].depositMax[assetToken];
  }

  function getNftAssetRequirements(address contractAddress, address nftTokenAddress)
    external
    view
    override
    virtual
    returns (string memory requiredBasketManager, bool basketEnabled, uint256 maxNfts)
  {
    requiredBasketManager = _nftSettings[contractAddress].requiredBasketManager;
    basketEnabled = _nftSettings[contractAddress].actionPerms.hasBit(PERM_BASKET_NFT);
    maxNfts = _nftSettings[contractAddress].maxNfts[nftTokenAddress];
  }


  /***********************************|
  |         Only NFT Creator          |
  |__________________________________*/

  /// @notice Sets the Custom Configuration for Creators of Proton-based NFTs
  /// @param contractAddress  The Address to the Proton-based NFT to configure
  /// @param tokenId          The token ID of the Proton-based NFT to configure
  /// @param creator          The creator of the Proton-based NFT
  /// @param annuityPercent   The percentage of interest-annuities to reserve for the creator
  function setCreatorAnnuities(
    address contractAddress,
    uint256 tokenId,
    address creator,
    uint256 annuityPercent
  )
    external
    virtual
    override
  {
    require(contractAddress.isTokenContractOrCreator(tokenId, creator, _msgSender()), "CP:E-104");
    require(annuityPercent <= MAX_ANNUITIES, "CP:E-421");

    uint256 tokenUuid = contractAddress.getTokenUUID(tokenId);

    // Update Configs for External Token Creator
    _creatorSettings[tokenUuid].annuityPercent = annuityPercent;

    emit TokenCreatorConfigsSet(
      contractAddress,
      tokenId,
      creator,
      annuityPercent
    );
  }

  /// @notice Sets a Custom Receiver Address for the Creator Annuities
  /// @param contractAddress  The Address to the Proton-based NFT to configure
  /// @param tokenId          The token ID of the Proton-based NFT to configure
  /// @param creator          The creator of the Proton-based NFT
  /// @param receiver         The receiver of the Creator interest-annuities
  function setCreatorAnnuitiesRedirect(
    address contractAddress,
    uint256 tokenId,
    address creator,
    address receiver
  )
    external
    virtual
    override
  {
    require(contractAddress.isTokenContractOrCreator(tokenId, creator, _msgSender()), "CP:E-104");
    uint256 tokenUuid = contractAddress.getTokenUUID(tokenId);
    _creatorSettings[tokenUuid].annuityRedirect = receiver;
    emit TokenCreatorAnnuitiesRedirected(contractAddress, tokenId, receiver);
  }

  function setTrustedForwarder(address _trustedForwarder) external onlyOwner {
    trustedForwarder = _trustedForwarder;
  }


  /***********************************|
  |     Register Contract Settings    |
  |(For External Contract Integration)|
  |__________________________________*/

  /// @notice Sets a Required Wallet-Manager for External NFT Contracts (otherwise set to "none" to allow any Wallet-Manager)
  /// @param contractAddress    The Address to the External NFT Contract to configure
  /// @param walletManager      If set, will only allow deposits from this specific Wallet-Manager
  function setRequiredWalletManager(
    address contractAddress,
    string calldata walletManager
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    if (keccak256(bytes(walletManager)) == keccak256(bytes("none"))) {
      _nftSettings[contractAddress].requiredWalletManager = "";
    } else {
      _nftSettings[contractAddress].requiredWalletManager = walletManager;
    }

    emit RequiredWalletManagerSet(
      contractAddress,
      walletManager
    );
  }

  /// @notice Sets a Required Basket-Manager for External NFT Contracts (otherwise set to "none" to allow any Basket-Manager)
  /// @param contractAddress    The Address to the External Contract to configure
  /// @param basketManager      If set, will only allow deposits from this specific Basket-Manager
  function setRequiredBasketManager(
    address contractAddress,
    string calldata basketManager
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    if (keccak256(bytes(basketManager)) == keccak256(bytes("none"))) {
      _nftSettings[contractAddress].requiredBasketManager = "";
    } else {
      _nftSettings[contractAddress].requiredBasketManager = basketManager;
    }

    emit RequiredBasketManagerSet(
      contractAddress,
      basketManager
    );
  }

  /// @notice Enables or Disables Asset-Token Restrictions for External NFT Contracts
  /// @param contractAddress      The Address to the External NFT Contract to configure
  /// @param restrictionsEnabled  If set, will only allow deposits from Allowed Asset Tokens
  function setAssetTokenRestrictions(
    address contractAddress,
    bool restrictionsEnabled
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    if (restrictionsEnabled) {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.setBit(PERM_RESTRICTED_ASSETS);
    } else {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.clearBit(PERM_RESTRICTED_ASSETS);
    }

    emit AssetTokenRestrictionsSet(
      contractAddress,
      restrictionsEnabled
    );
  }

  /// @notice Enables or Disables Allowed Asset Tokens for External NFT Contracts
  /// @param contractAddress  The Address to the External NFT Contract to configure
  /// @param assetToken       The Address of the Asset Token to Allow or Disallow
  /// @param isAllowed        True if the Asset Token is allowed
  function setAllowedAssetToken(
    address contractAddress,
    address assetToken,
    bool isAllowed
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    _nftSettings[contractAddress].allowedAssetTokens[assetToken] = isAllowed;

    emit AllowedAssetTokenSet(
      contractAddress,
      assetToken,
      isAllowed
    );
  }

  /// @notice Sets the Custom Configuration for External Contracts
  /// @param contractAddress  The Address to the External Contract to configure
  /// @param assetToken       The address of the Asset Token to set Limits for
  /// @param depositMin       If set, will define the minimum amount of Asset tokens the NFT may hold, otherwise any amount
  /// @param depositMax       If set, will define the maximum amount of Asset tokens the NFT may hold, otherwise any amount
  function setAssetTokenLimits(
    address contractAddress,
    address assetToken,
    uint256 depositMin,
    uint256 depositMax
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    _nftSettings[contractAddress].depositMin[assetToken] = depositMin;
    _nftSettings[contractAddress].depositMax[assetToken] = depositMax;

    emit AssetTokenLimitsSet(
      contractAddress,
      assetToken,
      depositMin,
      depositMax
    );
  }

  /// @notice Sets the Max Number of NFTs that can be held by a Charged Particle NFT
  /// @param contractAddress  The Address to the External Contract to configure
  /// @param nftTokenAddress  The address of the NFT Token to set a Max for
  /// @param maxNfts          The maximum numbers of NFTs that can be held by a given NFT (0 = unlimited)
  function setMaxNfts(
    address contractAddress,
    address nftTokenAddress,
    uint256 maxNfts
  )
    external
    virtual
    override
    onlyValidExternalContract(contractAddress)
    onlyContractOwnerOrAdmin(contractAddress, msg.sender)
  {
    // Update Configs for External Token Contract
    _nftSettings[contractAddress].maxNfts[nftTokenAddress] = maxNfts;

    emit MaxNftsSet(
      contractAddress,
      nftTokenAddress,
      maxNfts
    );
  }


  /***********************************|
  |          Only Admin/DAO           |
  |__________________________________*/

  function setDepositCap(address assetToken, uint256 cap) external virtual onlyOwner {
    _depositCap[assetToken] = cap;
    emit DepositCapSet(assetToken, cap);
  }

  function setTempLockExpiryBlocks(uint256 numBlocks) external virtual onlyOwner {
    _tempLockExpiryBlocks = numBlocks;
    emit TempLockExpirySet(numBlocks);
  }

  /// @dev Register Contracts as wallet managers with a unique liquidity provider ID
  function registerWalletManager(string calldata walletManagerId, address walletManager) external virtual onlyOwner {
    // Validate wallet manager
    IWalletManager newWalletMgr = IWalletManager(walletManager);
    require(newWalletMgr.isPaused() != true, "CP:E-418");

    // Register LP ID
    _ftWalletManager[walletManagerId] = newWalletMgr;
    emit WalletManagerRegistered(walletManagerId, walletManager);
  }

  /// @dev Register Contracts as basket managers with a unique basket ID
  function registerBasketManager(string calldata basketId, address basketManager) external virtual onlyOwner {
    // Validate basket manager
    IBasketManager newBasketMgr = IBasketManager(basketManager);
    require(newBasketMgr.isPaused() != true, "CP:E-418");

    // Register Basket ID
    _nftBasketManager[basketId] = newBasketMgr;
    emit BasketManagerRegistered(basketId, basketManager);
  }

  function enableNftContracts(address[] calldata contracts) external override virtual onlyOwner {
    uint count = contracts.length;
    for (uint i = 0; i < count; i++) {
      address tokenContract = contracts[i];
      _setPermsForCharge(tokenContract, true);
      _setPermsForBasket(tokenContract, true);
      _setPermsForTimelockSelf(tokenContract, true);
    }
  }

  /// @dev Update the list of NFT contracts that can be Charged
  function setPermsForCharge(address contractAddress, bool state)
    external
    override
    virtual
    onlyOwner
  {
    _setPermsForCharge(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can hold other NFTs
  function setPermsForBasket(address contractAddress, bool state)
    external
    override
    virtual
    onlyOwner
  {
    _setPermsForBasket(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can Timelock any NFT for Front-run Protection
  function setPermsForTimelockAny(address contractAddress, bool state)
    external
    override
    virtual
    onlyOwner
  {
    _setPermsForTimelockAny(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can Timelock their own tokens
  function setPermsForTimelockSelf(address contractAddress, bool state)
    external
    override
    virtual
    onlyOwner
  {
    _setPermsForTimelockSelf(contractAddress, state);
  }


  /***********************************|
  |          Only Admin/DAO           |
  |      (blackhole prevention)       |
  |__________________________________*/

  function withdrawEther(address payable receiver, uint256 amount) external virtual onlyOwner {
    _withdrawEther(receiver, amount);
  }

  function withdrawErc20(address payable receiver, address tokenAddress, uint256 amount) external virtual onlyOwner {
    _withdrawERC20(receiver, tokenAddress, amount);
  }

  function withdrawERC721(address payable receiver, address tokenAddress, uint256 tokenId) external virtual onlyOwner {
    _withdrawERC721(receiver, tokenAddress, tokenId);
  }


  /***********************************|
  |         Private Functions         |
  |__________________________________*/

  /// @dev See {ChargedParticles-isWalletManagerEnabled}.
  function _isWalletManagerEnabled(string calldata walletManagerId) internal view virtual returns (bool) {
    return (address(_ftWalletManager[walletManagerId]) != address(0x0) && !_ftWalletManager[walletManagerId].isPaused());
  }

  /// @dev See {ChargedParticles-isNftBasketEnabled}.
  function _isNftBasketEnabled(string calldata basketId) internal view virtual returns (bool) {
    return (address(_nftBasketManager[basketId]) != address(0x0) && !_nftBasketManager[basketId].isPaused());
  }

  /// @dev Update the list of NFT contracts that can be Charged
  function _setPermsForCharge(address contractAddress, bool state) internal virtual {
    if (state) {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.setBit(PERM_CHARGE_NFT);
    } else {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.clearBit(PERM_CHARGE_NFT);
    }
    emit PermsSetForCharge(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can hold other NFTs
  function _setPermsForBasket(address contractAddress, bool state) internal virtual {
    if (state) {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.setBit(PERM_BASKET_NFT);
    } else {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.clearBit(PERM_BASKET_NFT);
    }
    emit PermsSetForBasket(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can Timelock any NFT for Front-run Protection
  function _setPermsForTimelockAny(address contractAddress, bool state) internal virtual {
    if (state) {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.setBit(PERM_TIMELOCK_ANY_NFT);
    } else {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.clearBit(PERM_TIMELOCK_ANY_NFT);
    }
    emit PermsSetForTimelockAny(contractAddress, state);
  }

  /// @dev Update the list of NFT contracts that can Timelock their own tokens
  function _setPermsForTimelockSelf(address contractAddress, bool state) internal virtual {
    if (state) {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.setBit(PERM_TIMELOCK_OWN_NFT);
    } else {
      _nftSettings[contractAddress].actionPerms = _nftSettings[contractAddress].actionPerms.clearBit(PERM_TIMELOCK_OWN_NFT);
    }
    emit PermsSetForTimelockSelf(contractAddress, state);
  }


  /***********************************|
  |          GSN/MetaTx Relay         |
  |__________________________________*/

  /// @dev See {BaseRelayRecipient-_msgSender}.
  function _msgSender()
    internal
    view
    virtual
    override(BaseRelayRecipient, Context)
    returns (address payable)
  {
    return BaseRelayRecipient._msgSender();
  }

  /// @dev See {BaseRelayRecipient-_msgData}.
  function _msgData()
    internal
    view
    virtual
    override(BaseRelayRecipient, Context)
    returns (bytes memory)
  {
    return BaseRelayRecipient._msgData();
  }


  /***********************************|
  |             Modifiers             |
  |__________________________________*/

  modifier onlyValidExternalContract(address contractAddress) {
    require(contractAddress.isContract(), "CP:E-420");
    _;
  }

  modifier onlyContractOwnerOrAdmin(address contractAddress, address sender) {
    require(sender == owner() || contractAddress.isContractOwner(sender), "CP:E-103");
    _;
  }
}

File 2 of 21 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 3 of 21 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 4 of 21 : IChargedSettings.sol
// SPDX-License-Identifier: MIT

// IChargedSettings.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity >=0.6.0;

import "./IWalletManager.sol";
import "./IBasketManager.sol";

/**
 * @notice Interface for Charged Settings
 */
interface IChargedSettings {

  /***********************************|
  |             Public API            |
  |__________________________________*/

  function isContractOwner(address contractAddress, address account) external view returns (bool);
  function getCreatorAnnuities(address contractAddress, uint256 tokenId) external view returns (address creator, uint256 annuityPct);
  function getCreatorAnnuitiesRedirect(address contractAddress, uint256 tokenId) external view returns (address);
  function getTempLockExpiryBlocks() external view returns (uint256);
  function getTimelockApprovals(address operator) external view returns (bool timelockAny, bool timelockOwn);
  function getAssetRequirements(address contractAddress, address assetToken) external view
    returns (string memory requiredWalletManager, bool energizeEnabled, bool restrictedAssets, bool validAsset, uint256 depositCap, uint256 depositMin, uint256 depositMax);
  function getNftAssetRequirements(address contractAddress, address nftTokenAddress) external view
    returns (string memory requiredBasketManager, bool basketEnabled, uint256 maxNfts);

  // ERC20
  function isWalletManagerEnabled(string calldata walletManagerId) external view returns (bool);
  function getWalletManager(string calldata walletManagerId) external view returns (IWalletManager);

  // ERC721
  function isNftBasketEnabled(string calldata basketId) external view returns (bool);
  function getBasketManager(string calldata basketId) external view returns (IBasketManager);

  /***********************************|
  |         Only NFT Creator          |
  |__________________________________*/

  function setCreatorAnnuities(address contractAddress, uint256 tokenId, address creator, uint256 annuityPercent) external;
  function setCreatorAnnuitiesRedirect(address contractAddress, uint256 tokenId, address creator, address receiver) external;


  /***********************************|
  |      Only NFT Contract Owner      |
  |__________________________________*/

  function setRequiredWalletManager(address contractAddress, string calldata walletManager) external;
  function setRequiredBasketManager(address contractAddress, string calldata basketManager) external;
  function setAssetTokenRestrictions(address contractAddress, bool restrictionsEnabled) external;
  function setAllowedAssetToken(address contractAddress, address assetToken, bool isAllowed) external;
  function setAssetTokenLimits(address contractAddress, address assetToken, uint256 depositMin, uint256 depositMax) external;
  function setMaxNfts(address contractAddress, address nftTokenAddress, uint256 maxNfts) external;

  /***********************************|
  |          Only Admin/DAO           |
  |__________________________________*/

  function enableNftContracts(address[] calldata contracts) external;
  function setPermsForCharge(address contractAddress, bool state) external;
  function setPermsForBasket(address contractAddress, bool state) external;
  function setPermsForTimelockAny(address contractAddress, bool state) external;
  function setPermsForTimelockSelf(address contractAddress, bool state) external;

  /***********************************|
  |          Particle Events          |
  |__________________________________*/

  event DepositCapSet(address assetToken, uint256 depositCap);
  event TempLockExpirySet(uint256 expiryBlocks);

  event WalletManagerRegistered(string indexed walletManagerId, address indexed walletManager);
  event BasketManagerRegistered(string indexed basketId, address indexed basketManager);

  event RequiredWalletManagerSet(address indexed contractAddress, string walletManager);
  event RequiredBasketManagerSet(address indexed contractAddress, string basketManager);
  event AssetTokenRestrictionsSet(address indexed contractAddress, bool restrictionsEnabled);
  event AllowedAssetTokenSet(address indexed contractAddress, address assetToken, bool isAllowed);
  event AssetTokenLimitsSet(address indexed contractAddress, address assetToken, uint256 assetDepositMin, uint256 assetDepositMax);
  event MaxNftsSet(address indexed contractAddress, address indexed nftTokenAddress, uint256 maxNfts);

  event TokenCreatorConfigsSet(address indexed contractAddress, uint256 indexed tokenId, address indexed creatorAddress, uint256 annuityPercent);
  event TokenCreatorAnnuitiesRedirected(address indexed contractAddress, uint256 indexed tokenId, address indexed redirectAddress);

  event PermsSetForCharge(address indexed contractAddress, bool state);
  event PermsSetForBasket(address indexed contractAddress, bool state);
  event PermsSetForTimelockAny(address indexed contractAddress, bool state);
  event PermsSetForTimelockSelf(address indexed contractAddress, bool state);
}

File 5 of 21 : Bitwise.sol
// SPDX-License-Identifier: MIT

// Bitwise.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity 0.6.12;

library Bitwise {
  function negate(uint32 a) internal pure returns (uint32) {
    return a ^ maxInt();
  }

  function shiftLeft(uint32 a, uint32 n) internal pure returns (uint32) {
    return a * uint32(2) ** n;
  }

  function shiftRight(uint32 a, uint32 n) internal pure returns (uint32) {
    return a / uint32(2) ** n;
  }

  function maxInt() internal pure returns (uint32) {
    return uint32(-1);
  }

  // Get bit value at position
  function hasBit(uint32 a, uint32 n) internal pure returns (bool) {
    return a & shiftLeft(0x01, n) != 0;
  }

  // Set bit value at position
  function setBit(uint32 a, uint32 n) internal pure returns (uint32) {
    return a | shiftLeft(0x01, n);
  }

  // Set the bit into state "false"
  function clearBit(uint32 a, uint32 n) internal pure returns (uint32) {
    uint32 mask = negate(shiftLeft(0x01, n));
    return a & mask;
  }
}

File 6 of 21 : TokenInfo.sol
// SPDX-License-Identifier: MIT

// TokenInfo.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity 0.6.12;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "../interfaces/IERC721Chargeable.sol";

library TokenInfo {
  function getTokenUUID(address contractAddress, uint256 tokenId) internal pure virtual returns (uint256) {
    return uint256(keccak256(abi.encodePacked(contractAddress, tokenId)));
  }

  function getTokenOwner(address contractAddress, uint256 tokenId) internal view virtual returns (address) {
    IERC721Chargeable tokenInterface = IERC721Chargeable(contractAddress);
    return tokenInterface.ownerOf(tokenId);
  }

  function getTokenCreator(address contractAddress, uint256 tokenId) internal view virtual returns (address) {
    IERC721Chargeable tokenInterface = IERC721Chargeable(contractAddress);
    return tokenInterface.creatorOf(tokenId);
  }

  /// @dev Checks if an account is the Owner of an External NFT contract
  /// @param contractAddress  The Address to the Contract of the NFT to check
  /// @param account          The Address of the Account to check
  /// @return True if the account owns the contract
  function isContractOwner(address contractAddress, address account) internal view virtual returns (bool) {
    address contractOwner = IERC721Chargeable(contractAddress).owner();
    return contractOwner != address(0x0) && contractOwner == account;
  }

  /// @dev Checks if an account is the Creator of a Proton-based NFT
  /// @param contractAddress  The Address to the Contract of the Proton-based NFT to check
  /// @param tokenId          The Token ID of the Proton-based NFT to check
  /// @param sender           The Address of the Account to check
  /// @return True if the account is the creator of the Proton-based NFT
  function isTokenCreator(address contractAddress, uint256 tokenId, address sender) internal view virtual returns (bool) {
    IERC721Chargeable tokenInterface = IERC721Chargeable(contractAddress);
    address tokenCreator = tokenInterface.creatorOf(tokenId);
    return (sender == tokenCreator);
  }

  /// @dev Checks if an account is the Creator of a Proton-based NFT or the Contract itself
  /// @param contractAddress  The Address to the Contract of the Proton-based NFT to check
  /// @param tokenId          The Token ID of the Proton-based NFT to check
  /// @param sender           The Address of the Account to check
  /// @return True if the account is the creator of the Proton-based NFT or the Contract itself
  function isTokenContractOrCreator(address contractAddress, uint256 tokenId, address creator, address sender) internal view virtual returns (bool) {
    IERC721Chargeable tokenInterface = IERC721Chargeable(contractAddress);
    address tokenCreator = tokenInterface.creatorOf(tokenId);
    if (sender == contractAddress && creator == tokenCreator) { return true; }
    return (sender == tokenCreator);
  }

  /// @dev Checks if an account is the Owner or Operator of an External NFT
  /// @param contractAddress  The Address to the Contract of the External NFT to check
  /// @param tokenId          The Token ID of the External NFT to check
  /// @param sender           The Address of the Account to check
  /// @return True if the account is the Owner or Operator of the External NFT
  function isErc721OwnerOrOperator(address contractAddress, uint256 tokenId, address sender) internal view virtual returns (bool) {
    IERC721Chargeable tokenInterface = IERC721Chargeable(contractAddress);
    address tokenOwner = tokenInterface.ownerOf(tokenId);
    return (sender == tokenOwner || tokenInterface.isApprovedForAll(tokenOwner, sender));
  }

  /**
    * @dev Returns true if `account` is a contract.
    * @dev Taken from OpenZeppelin library
    *
    * [IMPORTANT]
    * ====
    * It is unsafe to assume that an address for which this function returns
    * false is an externally-owned account (EOA) and not a contract.
    *
    * Among others, `isContract` will return false for the following
    * types of addresses:
    *
    *  - an externally-owned account
    *  - a contract in construction
    *  - an address where a contract will be created
    *  - an address where a contract lived, but was destroyed
    * ====
    */
  function isContract(address account) internal view returns (bool) {
    // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
    // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
    // for accounts without code, i.e. `keccak256('')`
    bytes32 codehash;
    bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
    // solhint-disable-next-line no-inline-assembly
    assembly { codehash := extcodehash(account) }
    return (codehash != accountHash && codehash != 0x0);
  }

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

    // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
    (bool success, ) = recipient.call{ value: amount }("");
    require(success, "TokenInfo: unable to send value, recipient may have reverted");
  }
}

File 7 of 21 : RelayRecipient.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

import "@opengsn/gsn/contracts/BaseRelayRecipient.sol";

contract RelayRecipient is BaseRelayRecipient {
  function versionRecipient() external override view returns (string memory) {
    return "1.0.0-beta.1/charged-particles.relay.recipient";
  }
}

File 8 of 21 : BlackholePrevention.sol
// SPDX-License-Identifier: MIT

// BlackholePrevention.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity >=0.6.0;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
 * @notice Prevents ETH or Tokens from getting stuck in a contract by allowing
 *  the Owner/DAO to pull them out on behalf of a user
 * This is only meant to contracts that are not expected to hold tokens, but do handle transferring them.
 */
contract BlackholePrevention {
  using Address for address payable;
  using SafeERC20 for IERC20;

  event WithdrawStuckEther(address indexed receiver, uint256 amount);
  event WithdrawStuckERC20(address indexed receiver, address indexed tokenAddress, uint256 amount);
  event WithdrawStuckERC721(address indexed receiver, address indexed tokenAddress, uint256 indexed tokenId);

  function _withdrawEther(address payable receiver, uint256 amount) internal virtual {
    require(receiver != address(0x0), "BHP:E-403");
    if (address(this).balance >= amount) {
      receiver.sendValue(amount);
      emit WithdrawStuckEther(receiver, amount);
    }
  }

  function _withdrawERC20(address payable receiver, address tokenAddress, uint256 amount) internal virtual {
    require(receiver != address(0x0), "BHP:E-403");
    if (IERC20(tokenAddress).balanceOf(address(this)) >= amount) {
      IERC20(tokenAddress).safeTransfer(receiver, amount);
      emit WithdrawStuckERC20(receiver, tokenAddress, amount);
    }
  }

  function _withdrawERC721(address payable receiver, address tokenAddress, uint256 tokenId) internal virtual {
    require(receiver != address(0x0), "BHP:E-403");
    if (IERC721(tokenAddress).ownerOf(tokenId) == address(this)) {
      IERC721(tokenAddress).transferFrom(address(this), receiver, tokenId);
      emit WithdrawStuckERC721(receiver, tokenAddress, tokenId);
    }
  }
}

File 9 of 21 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 10 of 21 : IWalletManager.sol
// SPDX-License-Identifier: MIT

// IWalletManager.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity >=0.6.0;

/**
 * @title Particle Wallet Manager interface
 * @dev The wallet-manager for underlying assets attached to Charged Particles
 * @dev Manages the link between NFTs and their respective Smart-Wallets
 */
interface IWalletManager {

  event ControllerSet(address indexed controller);
  event PausedStateSet(bool isPaused);
  event NewSmartWallet(address indexed contractAddress, uint256 indexed tokenId, address indexed smartWallet, address creator, uint256 annuityPct);
  event WalletEnergized(address indexed contractAddress, uint256 indexed tokenId, address indexed assetToken, uint256 assetAmount, uint256 yieldTokensAmount);
  event WalletDischarged(address indexed contractAddress, uint256 indexed tokenId, address indexed assetToken, uint256 creatorAmount, uint256 receiverAmount);
  event WalletDischargedForCreator(address indexed contractAddress, uint256 indexed tokenId, address indexed assetToken, address creator, uint256 receiverAmount);
  event WalletReleased(address indexed contractAddress, uint256 indexed tokenId, address indexed receiver, address assetToken, uint256 principalAmount, uint256 creatorAmount, uint256 receiverAmount);
  event WalletRewarded(address indexed contractAddress, uint256 indexed tokenId, address indexed receiver, address rewardsToken, uint256 rewardsAmount);

  function isPaused() external view returns (bool);

  function isReserveActive(address contractAddress, uint256 tokenId, address assetToken) external view returns (bool);
  function getReserveInterestToken(address contractAddress, uint256 tokenId, address assetToken) external view returns (address);

  function getTotal(address contractAddress, uint256 tokenId, address assetToken) external returns (uint256);
  function getPrincipal(address contractAddress, uint256 tokenId, address assetToken) external returns (uint256);
  function getInterest(address contractAddress, uint256 tokenId, address assetToken) external returns (uint256 creatorInterest, uint256 ownerInterest);
  function getRewards(address contractAddress, uint256 tokenId, address rewardToken) external returns (uint256);

  function energize(address contractAddress, uint256 tokenId, address assetToken, uint256 assetAmount) external returns (uint256 yieldTokensAmount);
  function discharge(address receiver, address contractAddress, uint256 tokenId, address assetToken, address creatorRedirect) external returns (uint256 creatorAmount, uint256 receiverAmount);
  function dischargeAmount(address receiver, address contractAddress, uint256 tokenId, address assetToken, uint256 assetAmount, address creatorRedirect) external returns (uint256 creatorAmount, uint256 receiverAmount);
  function dischargeAmountForCreator(address receiver, address contractAddress, uint256 tokenId, address creator, address assetToken, uint256 assetAmount) external returns (uint256 receiverAmount);
  function release(address receiver, address contractAddress, uint256 tokenId, address assetToken, address creatorRedirect) external returns (uint256 principalAmount, uint256 creatorAmount, uint256 receiverAmount);
  function releaseAmount(address receiver, address contractAddress, uint256 tokenId, address assetToken, uint256 assetAmount, address creatorRedirect) external returns (uint256 principalAmount, uint256 creatorAmount, uint256 receiverAmount);
  function withdrawRewards(address receiver, address contractAddress, uint256 tokenId, address rewardsToken, uint256 rewardsAmount) external returns (uint256 amount);
  function executeForAccount(address contractAddress, uint256 tokenId, address externalAddress, uint256 ethValue, bytes memory encodedParams) external returns (bytes memory);
  function getWalletAddressById(address contractAddress, uint256 tokenId, address creator, uint256 annuityPct) external returns (address);

  function withdrawEther(address contractAddress, uint256 tokenId, address payable receiver, uint256 amount) external;
  function withdrawERC20(address contractAddress, uint256 tokenId, address payable receiver, address tokenAddress, uint256 amount) external;
  function withdrawERC721(address contractAddress, uint256 tokenId, address payable receiver, address nftTokenAddress, uint256 nftTokenId) external;
}

File 11 of 21 : IBasketManager.sol
// SPDX-License-Identifier: MIT

// IBasketManager.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity >=0.6.0;

/**
 * @title Particle Basket Manager interface
 * @dev The basket-manager for underlying assets attached to Charged Particles
 * @dev Manages the link between NFTs and their respective Smart-Baskets
 */
interface IBasketManager {

  event ControllerSet(address indexed controller);
  event PausedStateSet(bool isPaused);
  event NewSmartBasket(address indexed contractAddress, uint256 indexed tokenId, address indexed smartBasket);
  event BasketAdd(address indexed contractAddress, uint256 indexed tokenId, address basketTokenAddress, uint256 basketTokenId);
  event BasketRemove(address indexed receiver, address indexed contractAddress, uint256 indexed tokenId, address basketTokenAddress, uint256 basketTokenId);

  function isPaused() external view returns (bool);

  function getTokenTotalCount(address contractAddress, uint256 tokenId) external view returns (uint256);
  function getTokenCountByType(address contractAddress, uint256 tokenId, address basketTokenAddress, uint256 basketTokenId) external returns (uint256);

  function addToBasket(address contractAddress, uint256 tokenId, address basketTokenAddress, uint256 basketTokenId) external returns (bool);
  function removeFromBasket(address receiver, address contractAddress, uint256 tokenId, address basketTokenAddress, uint256 basketTokenId) external returns (bool);
  function executeForAccount(address contractAddress, uint256 tokenId, address externalAddress, uint256 ethValue, bytes memory encodedParams) external returns (bytes memory);
  function getBasketAddressById(address contractAddress, uint256 tokenId) external returns (address);

  function withdrawEther(address contractAddress, uint256 tokenId, address payable receiver, uint256 amount) external;
  function withdrawERC20(address contractAddress, uint256 tokenId, address payable receiver, address tokenAddress, uint256 amount) external;
  function withdrawERC721(address contractAddress, uint256 tokenId, address payable receiver, address nftTokenAddress, uint256 nftTokenId) external;
}

File 12 of 21 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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);
}

File 13 of 21 : IERC721Chargeable.sol
// SPDX-License-Identifier: MIT

// IERC721Chargeable.sol -- Part of the Charged Particles Protocol
// Copyright (c) 2021 Firma Lux, Inc. <https://charged.fi>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

pragma solidity >=0.6.0;

import "@openzeppelin/contracts-upgradeable/introspection/IERC165Upgradeable.sol";

interface IERC721Chargeable is IERC165Upgradeable {
    function owner() external view returns (address);
    function creatorOf(uint256 tokenId) external view returns (address);
    function balanceOf(address tokenOwner) external view returns (uint256 balance);
    function ownerOf(uint256 tokenId) external view returns (address tokenOwner);
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function transferFrom(address from, address to, uint256 tokenId) external;
    function approve(address to, uint256 tokenId) external;
    function getApproved(uint256 tokenId) external view returns (address operator);
    function setApprovalForAll(address operator, bool _approved) external;
    function isApprovedForAll(address tokenOwner, address operator) external view returns (bool);
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

File 14 of 21 : IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 IERC165Upgradeable {
    /**
     * @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 15 of 21 : BaseRelayRecipient.sol
// SPDX-License-Identifier:MIT
// solhint-disable no-inline-assembly
pragma solidity ^0.6.2;

import "./interfaces/IRelayRecipient.sol";

/**
 * A base contract to be inherited by any contract that want to receive relayed transactions
 * A subclass must use "_msgSender()" instead of "msg.sender"
 */
abstract contract BaseRelayRecipient is IRelayRecipient {

    /*
     * Forwarder singleton we accept calls from
     */
    address public trustedForwarder;

    function isTrustedForwarder(address forwarder) public override view returns(bool) {
        return forwarder == trustedForwarder;
    }

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, return the original sender.
     * otherwise, return `msg.sender`.
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal override virtual view returns (address payable ret) {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            return msg.sender;
        }
    }

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise, return `msg.data`
     * should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
     * signing or hashing the
     */
    function _msgData() internal override virtual view returns (bytes memory ret) {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // we copy the msg.data , except the last 20 bytes (and update the total length)
            assembly {
                let ptr := mload(0x40)
                // copy only size-20 bytes
                let size := sub(calldatasize(),20)
                // structure RLP data as <offset> <length> <bytes>
                mstore(ptr, 0x20)
                mstore(add(ptr,32), size)
                calldatacopy(add(ptr,64), 0, size)
                return(ptr, add(size,64))
            }
        } else {
            return msg.data;
        }
    }
}

File 16 of 21 : IRelayRecipient.sol
// SPDX-License-Identifier:MIT
pragma solidity ^0.6.2;

/**
 * a contract must implement this interface in order to support relayed transaction.
 * It is better to inherit the BaseRelayRecipient as its implementation.
 */
abstract contract IRelayRecipient {

    /**
     * return if the forwarder is trusted to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, then the real sender is appended as the last 20 bytes
     * of the msg.data.
     * otherwise, return `msg.sender`
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal virtual view returns (address payable);

    /**
     * return the msg.data of this call.
     * if the call came through our trusted forwarder, then the real sender was appended as the last 20 bytes
     * of the msg.data - so this method will strip those 20 bytes off.
     * otherwise, return `msg.data`
     * should be used in the contract instead of msg.data, where the difference matters (e.g. when explicitly
     * signing or hashing the
     */
    function _msgData() internal virtual view returns (bytes memory);

    function versionRecipient() external virtual view returns (string memory);
}

File 17 of 21 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 18 of 21 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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);
}

File 19 of 21 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

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

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 20 of 21 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transfered 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`, 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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * 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 Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @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 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);

    /**
      * @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;
}

File 21 of 21 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.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);
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"address","name":"assetToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"AllowedAssetTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"address","name":"assetToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetDepositMin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetDepositMax","type":"uint256"}],"name":"AssetTokenLimitsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"restrictionsEnabled","type":"bool"}],"name":"AssetTokenRestrictionsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"basketId","type":"string"},{"indexed":true,"internalType":"address","name":"basketManager","type":"address"}],"name":"BasketManagerRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositCap","type":"uint256"}],"name":"DepositCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"address","name":"nftTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxNfts","type":"uint256"}],"name":"MaxNftsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"PermsSetForBasket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"PermsSetForCharge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"PermsSetForTimelockAny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"PermsSetForTimelockSelf","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"string","name":"basketManager","type":"string"}],"name":"RequiredBasketManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"string","name":"walletManager","type":"string"}],"name":"RequiredWalletManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiryBlocks","type":"uint256"}],"name":"TempLockExpirySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"redirectAddress","type":"address"}],"name":"TokenCreatorAnnuitiesRedirected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creatorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"annuityPercent","type":"uint256"}],"name":"TokenCreatorConfigsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"walletManagerId","type":"string"},{"indexed":true,"internalType":"address","name":"walletManager","type":"address"}],"name":"WalletManagerRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawStuckERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"WithdrawStuckERC721","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawStuckEther","type":"event"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"enableNftContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"assetToken","type":"address"}],"name":"getAssetRequirements","outputs":[{"internalType":"string","name":"requiredWalletManager","type":"string"},{"internalType":"bool","name":"energizeEnabled","type":"bool"},{"internalType":"bool","name":"restrictedAssets","type":"bool"},{"internalType":"bool","name":"validAsset","type":"bool"},{"internalType":"uint256","name":"depositCap","type":"uint256"},{"internalType":"uint256","name":"depositMin","type":"uint256"},{"internalType":"uint256","name":"depositMax","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"basketId","type":"string"}],"name":"getBasketManager","outputs":[{"internalType":"contract IBasketManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCreatorAnnuities","outputs":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"annuityPct","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCreatorAnnuitiesRedirect","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"nftTokenAddress","type":"address"}],"name":"getNftAssetRequirements","outputs":[{"internalType":"string","name":"requiredBasketManager","type":"string"},{"internalType":"bool","name":"basketEnabled","type":"bool"},{"internalType":"uint256","name":"maxNfts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTempLockExpiryBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"getTimelockApprovals","outputs":[{"internalType":"bool","name":"timelockAny","type":"bool"},{"internalType":"bool","name":"timelockOwn","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"walletManagerId","type":"string"}],"name":"getWalletManager","outputs":[{"internalType":"contract IWalletManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isContractOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"basketId","type":"string"}],"name":"isNftBasketEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"walletManagerId","type":"string"}],"name":"isWalletManagerEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"basketId","type":"string"},{"internalType":"address","name":"basketManager","type":"address"}],"name":"registerBasketManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"walletManagerId","type":"string"},{"internalType":"address","name":"walletManager","type":"address"}],"name":"registerWalletManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"assetToken","type":"address"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"setAllowedAssetToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"assetToken","type":"address"},{"internalType":"uint256","name":"depositMin","type":"uint256"},{"internalType":"uint256","name":"depositMax","type":"uint256"}],"name":"setAssetTokenLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"restrictionsEnabled","type":"bool"}],"name":"setAssetTokenRestrictions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"annuityPercent","type":"uint256"}],"name":"setCreatorAnnuities","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"setCreatorAnnuitiesRedirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetToken","type":"address"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"setDepositCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"nftTokenAddress","type":"address"},{"internalType":"uint256","name":"maxNfts","type":"uint256"}],"name":"setMaxNfts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setPermsForBasket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setPermsForCharge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setPermsForTimelockAny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setPermsForTimelockSelf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"basketManager","type":"string"}],"name":"setRequiredBasketManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"string","name":"walletManager","type":"string"}],"name":"setRequiredWalletManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numBlocks","type":"uint256"}],"name":"setTempLockExpiryBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_trustedForwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionRecipient","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdrawERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060006200001e6200006e565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350620000d7565b6000620000856200008b60201b620026bd1760201c565b90505b90565b600060183610801590620000a55750620000a533620000c3565b15620000bb575060131936013560601c62000088565b503362000088565b6001546001600160a01b0390811691161490565b6138a680620000e76000396000f3fe608060405234801561001057600080fd5b50600436106102325760003560e01c8063715018a611610130578063cf74fe61116100b8578063e8176ced1161007c578063e8176ced14610c2c578063ee49d0a714610c5a578063f0e824ec14610c88578063f2fde38b14610ca5578063f878369e14610ccb57610232565b8063cf74fe6114610ad4578063da74222814610aee578063ddc844dd14610b14578063e12439b814610b82578063e3c945b814610bf057610232565b80639bb1c927116100ff5780639bb1c927146108f7578063a0b78e9814610933578063b078808a146109e9578063b1332f1014610a57578063bb10a6ec14610a8557610232565b8063715018a6146108b35780637da0a877146108bb57806382508e0f146108c35780638da5cb5b146108ef57610232565b806333aedf0b116101be578063522f681511610182578063522f6815146107005780635369ff961461072c578063572b6c05146107625780635ae5bde91461079c57806370d9e4f01461087257610232565b806333aedf0b1461052757806334b7328d146105955780634025feb21461061f578063486ff0cd146106555780634a46b3ee146106d257610232565b80631aad0fb4116102055780631aad0fb41461034e5780631deb74541461037c5780632805baca146103f35780632e0bdde81461042b5780632e4b2d52146104a957610232565b806301ade20f1461023757806304f275a1146102b05780631593dee1146102de57806315aea5d714610314575b600080fd5b6102ae6004803603604081101561024d57600080fd5b810190602081018135600160201b81111561026757600080fd5b82018360208201111561027957600080fd5b803590602001918460018302840111600160201b8311171561029a57600080fd5b9193509150356001600160a01b0316610cf7565b005b6102ae600480360360408110156102c657600080fd5b506001600160a01b0381351690602001351515610e87565b6102ae600480360360608110156102f457600080fd5b506001600160a01b03813581169160208101359091169060400135610eed565b6102ae6004803603608081101561032a57600080fd5b506001600160a01b0381358116916020810135916040820135169060600135610f55565b6102ae6004803603604081101561036457600080fd5b506001600160a01b0381351690602001351515611067565b6102ae6004803603604081101561039257600080fd5b810190602081018135600160201b8111156103ac57600080fd5b8201836020820111156103be57600080fd5b803590602001918460018302840111600160201b831117156103df57600080fd5b9193509150356001600160a01b03166110c9565b6102ae6004803603606081101561040957600080fd5b506001600160a01b038135811691602081013590911690604001351515611259565b6102ae6004803603604081101561044157600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561046b57600080fd5b82018360208201111561047d57600080fd5b803590602001918460018302840111600160201b8311171561049e57600080fd5b509092509050611397565b6102ae600480360360408110156104bf57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156104e957600080fd5b8201836020820111156104fb57600080fd5b803590602001918460018302840111600160201b8311171561051c57600080fd5b509092509050611592565b6102ae6004803603602081101561053d57600080fd5b810190602081018135600160201b81111561055757600080fd5b82018360208201111561056957600080fd5b803590602001918460208302840111600160201b8311171561058a57600080fd5b50909250905061178d565b610603600480360360208110156105ab57600080fd5b810190602081018135600160201b8111156105c557600080fd5b8201836020820111156105d757600080fd5b803590602001918460018302840111600160201b831117156105f857600080fd5b509092509050611841565b604080516001600160a01b039092168252519081900360200190f35b6102ae6004803603606081101561063557600080fd5b506001600160a01b0381358116916020810135909116906040013561187b565b61065d6118de565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561069757818101518382015260200161067f565b50505050905090810190601f1680156106c45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102ae600480360360408110156106e857600080fd5b506001600160a01b03813516906020013515156118ff565b6102ae6004803603604081101561071657600080fd5b506001600160a01b038135169060200135611961565b6102ae6004803603606081101561074257600080fd5b506001600160a01b038135811691602081013590911690604001356119c3565b6107886004803603602081101561077857600080fd5b50356001600160a01b0316611aee565b604080519115158252519081900360200190f35b6107ca600480360360408110156107b257600080fd5b506001600160a01b0381358116916020013516611b02565b6040518080602001881515815260200187151581526020018615158152602001858152602001848152602001838152602001828103825289818151815260200191508051906020019080838360005b83811015610831578181015183820152602001610819565b50505050905090810190601f16801561085e5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b6108986004803603602081101561088857600080fd5b50356001600160a01b0316611c96565b60408051921515835290151560208301528051918290030190f35b6102ae611d00565b610603611da2565b610603600480360360408110156108d957600080fd5b506001600160a01b038135169060200135611db1565b610603611dea565b6102ae6004803603608081101561090d57600080fd5b506001600160a01b03813581169160208101359160408201358116916060013516611df9565b6109616004803603604081101561094957600080fd5b506001600160a01b0381358116916020013516611ebd565b60405180806020018415158152602001838152602001828103825285818151815260200191508051906020019080838360005b838110156109ac578181015183820152602001610994565b50505050905090810190601f1680156109d95780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b610603600480360360208110156109ff57600080fd5b810190602081018135600160201b811115610a1957600080fd5b820183602082011115610a2b57600080fd5b803590602001918460018302840111600160201b83111715610a4c57600080fd5b509092509050611fce565b6102ae60048036036040811015610a6d57600080fd5b506001600160a01b0381351690602001351515612008565b610ab160048036036040811015610a9b57600080fd5b506001600160a01b0381351690602001356121dc565b604080516001600160a01b03909316835260208301919091528051918290030190f35b610adc612223565b60408051918252519081900360200190f35b6102ae60048036036020811015610b0457600080fd5b50356001600160a01b0316612229565b61078860048036036020811015610b2a57600080fd5b810190602081018135600160201b811115610b4457600080fd5b820183602082011115610b5657600080fd5b803590602001918460018302840111600160201b83111715610b7757600080fd5b5090925090506122a3565b61078860048036036020811015610b9857600080fd5b810190602081018135600160201b811115610bb257600080fd5b820183602082011115610bc457600080fd5b803590602001918460018302840111600160201b83111715610be557600080fd5b5090925090506122b6565b6102ae60048036036080811015610c0657600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356122c2565b6102ae60048036036040811015610c4257600080fd5b506001600160a01b038135169060200135151561240a565b61078860048036036040811015610c7057600080fd5b506001600160a01b038135811691602001351661246c565b6102ae60048036036020811015610c9e57600080fd5b5035612481565b6102ae60048036036020811015610cbb57600080fd5b50356001600160a01b0316612514565b6102ae60048036036040811015610ce157600080fd5b506001600160a01b03813516906020013561260c565b610cff6126ef565b6000546001600160a01b03908116911614610d4f576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b6000819050806001600160a01b031663b187bd266040518163ffffffff1660e01b815260040160206040518083038186803b158015610d8d57600080fd5b505afa158015610da1573d6000803e3d6000fd5b505050506040513d6020811015610db757600080fd5b5051151560011415610dfb576040805162461bcd60e51b8152602060048201526008602482015267086a0748a5a6862760c31b604482015290519081900360640190fd5b80600585856040518083838082843791909101948552505060405192839003602001832080546001600160a01b039586166001600160a01b031990911617905550509083169085908590808383808284376040519201829003822094507f708577413578f3a2621424f169d974e2970197dc14bb86ae19dbf951dde9c66693506000925050a350505050565b610e8f6126ef565b6000546001600160a01b03908116911614610edf576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610ee982826126fe565b5050565b610ef56126ef565b6000546001600160a01b03908116911614610f45576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610f5083838361280d565b505050565b610f748383610f626126ef565b6001600160a01b038816929190612937565b610fb0576040805162461bcd60e51b815260206004820152600860248201526710d40e914b4c4c0d60c21b604482015290519081900360640190fd5b612710811115610ff2576040805162461bcd60e51b815260206004820152600860248201526743503a452d34323160c01b604482015290519081900360640190fd5b60006110076001600160a01b03861685612a07565b600081815260066020908152604091829020859055815185815291519293506001600160a01b03808716938893918a16927f1e4d934208ef860fdc8a276237551c8e9e99fb6a2b2767aa0d67cc2aef675a8f928290030190a45050505050565b61106f6126ef565b6000546001600160a01b039081169116146110bf576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610ee98282612a4b565b6110d16126ef565b6000546001600160a01b03908116911614611121576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b6000819050806001600160a01b031663b187bd266040518163ffffffff1660e01b815260040160206040518083038186803b15801561115f57600080fd5b505afa158015611173573d6000803e3d6000fd5b505050506040513d602081101561118957600080fd5b50511515600114156111cd576040805162461bcd60e51b8152602060048201526008602482015267086a0748a5a6862760c31b604482015290519081900360640190fd5b80600485856040518083838082843791909101948552505060405192839003602001832080546001600160a01b039586166001600160a01b031990911617905550509083169085908590808383808284376040519201829003822094507f034b0a7a58ed793cbc70fd231465924ab99016fd951b3eb399219e203e1f06cd93506000925050a350505050565b8261126c816001600160a01b0316612b5a565b6112a8576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b83336112b2611dea565b6001600160a01b0316816001600160a01b031614806112df57506112df6001600160a01b03831682612b93565b61131b576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b6001600160a01b038681166000818152600760209081526040808320948a168084526003909501825291829020805460ff1916891515908117909155825194855290840152805191927fd527a72e6766537312f1eb975e1f40f434f158008057c75aaaa34a22b970ed70929081900390910190a2505050505050565b826113aa816001600160a01b0316612b5a565b6113e6576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b83336113f0611dea565b6001600160a01b0316816001600160a01b0316148061141d575061141d6001600160a01b03831682612b93565b611459576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b60408051808201825260048152636e6f6e6560e01b602090910152517ff4915122cc2b3d2dae9e7d77a78c2eb0cef7b55de5c725eea56e2027332489e19086908690808383808284378083019250505092505050604051809103902014156114f85760408051602080820180845260008084526001600160a01b038b168152600790925292902090516114f29260019092019190613697565b50611520565b6001600160a01b038616600090815260076020526040902061151e906001018686613715565b505b856001600160a01b03167f61eb8c714b3b28bfd7808ae5ca8de4291f99ffa752eed03959744b3ea6170edd868660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2505050505050565b826115a5816001600160a01b0316612b5a565b6115e1576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b83336115eb611dea565b6001600160a01b0316816001600160a01b0316148061161857506116186001600160a01b03831682612b93565b611654576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b60408051808201825260048152636e6f6e6560e01b602090910152517ff4915122cc2b3d2dae9e7d77a78c2eb0cef7b55de5c725eea56e2027332489e19086908690808383808284378083019250505092505050604051809103902014156116f35760408051602080820180845260008084526001600160a01b038b168152600790925292902090516116ed9260029092019190613697565b5061171b565b6001600160a01b0386166000908152600760205260409020611719906002018686613715565b505b856001600160a01b03167ffc810bbaf45475e561a4319e56b456f12cd50940a48193f06eaf039f2c02fffe868660405180806020018281038252848482818152602001925080828437600083820152604051601f909101601f19169092018290039550909350505050a2505050505050565b6117956126ef565b6000546001600160a01b039081169116146117e5576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b8060005b8181101561183b5760008484838181106117ff57fe5b905060200201356001600160a01b0316905061181c8160016126fe565b611827816001612c2d565b611832816001612a4b565b506001016117e9565b50505050565b6000600483836040518083838082843791909101948552505060405192839003602001909220546001600160a01b03169250505092915050565b6118836126ef565b6000546001600160a01b039081169116146118d3576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610f50838383612d3c565b60606040518060600160405280602e8152602001613819602e913990505b90565b6119076126ef565b6000546001600160a01b03908116911614611957576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610ee98282612c2d565b6119696126ef565b6000546001600160a01b039081169116146119b9576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610ee98282612ec2565b826119d6816001600160a01b0316612b5a565b611a12576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b8333611a1c611dea565b6001600160a01b0316816001600160a01b03161480611a495750611a496001600160a01b03831682612b93565b611a85576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b6001600160a01b038087166000818152600760209081526040808320948a168084526006909501825291829020889055815188815291517f4b78edbe1cbf239c91e7f1ad3f75626752bfcc6d30abc9077dc08d328577029c9281900390910190a3505050505050565b6001546001600160a01b0390811691161490565b6060600080600080600080600760008a6001600160a01b03166001600160a01b031681526020019081526020016000206001018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015611bc95780601f10611b9e57610100808354040283529160200191611bc9565b820191906000526020600020905b815481529060010190602001808311611bac57829003601f168201915b5050506001600160a01b038c16600090815260076020526040902054929950611c009263ffffffff908116925060019150612f6516565b6001600160a01b038a16600090815260076020526040902054909650611c329063ffffffff90811690601090612f6516565b6001600160a01b03998a1660009081526007602090815260408083209b909c16825260038b0181528b822054600282528c83205460048d0183528d8420546005909d019092529b90912054989b979a919960ff909216989097919650945092505050565b6001600160a01b0381166000908152600760205260408120548190611cc79063ffffffff90811690600490612f6516565b6001600160a01b038416600090815260076020526040902054909250611cf99063ffffffff90811690600890612f6516565b9050915091565b611d086126ef565b6000546001600160a01b03908116911614611d58576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6001546001600160a01b031681565b600080611dc76001600160a01b03851684612a07565b6000908152600660205260409020600101546001600160a01b0316949350505050565b6000546001600160a01b031690565b611e068383610f626126ef565b611e42576040805162461bcd60e51b815260206004820152600860248201526710d40e914b4c4c0d60c21b604482015290519081900360640190fd5b6000611e576001600160a01b03861685612a07565b60008181526006602052604080822060010180546001600160a01b0319166001600160a01b03878116918217909255915193945090928792918916917f2299d7747b35c4e5433422bf0fb1dab252ea00efaa8a52c72fe97d47ad59fcc291a45050505050565b6001600160a01b03821660009081526007602090815260408083206002908101805483516001821615610100026000190190911692909204601f810185900485028301850190935282825260609493849390830182828015611f605780601f10611f3557610100808354040283529160200191611f60565b820191906000526020600020905b815481529060010190602001808311611f4357829003601f168201915b5050506001600160a01b038816600090815260076020526040902054929550611f979263ffffffff908116925060029150612f6516565b6001600160a01b03958616600090815260076020908152604080832097909816825260069096019095529490932054919491925050565b6000600583836040518083838082843791909101948552505060405192839003602001909220546001600160a01b03169250505092915050565b8161201b816001600160a01b0316612b5a565b612057576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b8233612061611dea565b6001600160a01b0316816001600160a01b0316148061208e575061208e6001600160a01b03831682612b93565b6120ca576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b8315612134576001600160a01b0385166000908152600760205260409020546120ff9063ffffffff90811690601090612f8616565b6001600160a01b0386166000908152600760205260409020805463ffffffff191663ffffffff92909216919091179055612194565b6001600160a01b0385166000908152600760205260409020546121639063ffffffff90811690601090612f9c16565b6001600160a01b0386166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790555b60408051851515815290516001600160a01b038716917f44f75c092e5ae1935f7968601737fcaaf6773731d301be89f180d742afc343c6919081900360200190a25050505050565b600080806121f36001600160a01b03861685612a07565b90506122086001600160a01b03861685612fbc565b60009182526006602052604090912054909590945092505050565b60035490565b6122316126ef565b6000546001600160a01b03908116911614612281576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006122af838361303a565b9392505050565b60006122af838361311a565b836122d5816001600160a01b0316612b5a565b612311576040805162461bcd60e51b8152602060048201526008602482015267043503a452d3432360c41b604482015290519081900360640190fd5b843361231b611dea565b6001600160a01b0316816001600160a01b0316148061234857506123486001600160a01b03831682612b93565b612384576040805162461bcd60e51b815260206004820152600860248201526743503a452d31303360c01b604482015290519081900360640190fd5b6001600160a01b038088166000818152600760209081526040808320948b168084526004860183528184208b90558084526005909501825291829020889055815193845283018890528281018790525190917f475309750c044c79112c130d7fa0ad604801463eafa8c2145460063e84f6d1b0919081900360600190a250505050505050565b6124126126ef565b6000546001600160a01b03908116911614612462576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b610ee982826131c6565b60006122af6001600160a01b03841683612b93565b6124896126ef565b6000546001600160a01b039081169116146124d9576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b60038190556040805182815290517fcc0abfe1dcb92824407c45c8bca5a491f18eab5d435afb057360d39887f7d5669181900360200190a150565b61251c6126ef565b6000546001600160a01b0390811691161461256c576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b6001600160a01b0381166125b15760405162461bcd60e51b81526004018080602001828103825260268152602001806137996026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6126146126ef565b6000546001600160a01b03908116911614612664576040805162461bcd60e51b815260206004820181905260248201526000805160206137f9833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600260209081526040918290208490558151928352820183905280517f5346dfddf35b6b3adb49f21161904a305a764ba435dfad799dfef4be256071409281900390910190a15050565b6000601836108015906126d457506126d433611aee565b156126e8575060131936013560601c6118fc565b50336118fc565b60006126f96126bd565b905090565b8015612768576001600160a01b0382166000908152600760205260409020546127339063ffffffff90811690600190612f8616565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790556127c8565b6001600160a01b0382166000908152600760205260409020546127979063ffffffff90811690600190612f9c16565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790555b60408051821515815290516001600160a01b038416917f9edbf34f19f27ae2f4f891336dcf0fc393961b70d0699b7698a75eadfa717119919081900360200190a25050565b6001600160a01b038316612854576040805162461bcd60e51b81526020600482015260096024820152684248503a452d34303360b81b604482015290519081900360640190fd5b80826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156128a257600080fd5b505afa1580156128b6573d6000803e3d6000fd5b505050506040513d60208110156128cc57600080fd5b505110610f50576128e76001600160a01b03831684836132d5565b816001600160a01b0316836001600160a01b03167f6c9d637297625e945b296ff73a71fcfbd0a9e062652b6491a921c4c60194176b836040518082815260200191505060405180910390a3505050565b6000808590506000816001600160a01b031663589a1743876040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561298357600080fd5b505afa158015612997573d6000803e3d6000fd5b505050506040513d60208110156129ad57600080fd5b505190506001600160a01b038481169088161480156129dd5750806001600160a01b0316856001600160a01b0316145b156129ed576001925050506129ff565b6001600160a01b038481169116149150505b949350505050565b6040805160609390931b6bffffffffffffffffffffffff19166020808501919091526034808501939093528151808503909301835260549093019052805191012090565b8015612ab5576001600160a01b038216600090815260076020526040902054612a809063ffffffff90811690600890612f8616565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff92909216919091179055612b15565b6001600160a01b038216600090815260076020526040902054612ae49063ffffffff90811690600890612f9c16565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790555b60408051821515815290516001600160a01b038416917fc821f11e884f33cce41b9695890d84b5592421ab7e473144e8e896d20a6f2518919081900360200190a25050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906129ff575050151592915050565b600080836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015612bcf57600080fd5b505afa158015612be3573d6000803e3d6000fd5b505050506040513d6020811015612bf957600080fd5b505190506001600160a01b038116158015906129ff5750826001600160a01b0316816001600160a01b031614949350505050565b8015612c97576001600160a01b038216600090815260076020526040902054612c629063ffffffff90811690600290612f8616565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff92909216919091179055612cf7565b6001600160a01b038216600090815260076020526040902054612cc69063ffffffff90811690600290612f9c16565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790555b60408051821515815290516001600160a01b038416917fb5a88ab1e0f82944f12e8890d045bd1edf9f74f51798a10d7bc2fad6022fd07b919081900360200190a25050565b6001600160a01b038316612d83576040805162461bcd60e51b81526020600482015260096024820152684248503a452d34303360b81b604482015290519081900360640190fd5b306001600160a01b0316826001600160a01b0316636352211e836040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015612dd157600080fd5b505afa158015612de5573d6000803e3d6000fd5b505050506040513d6020811015612dfb57600080fd5b50516001600160a01b03161415610f5057604080516323b872dd60e01b81523060048201526001600160a01b038581166024830152604482018490529151918416916323b872dd9160648082019260009290919082900301818387803b158015612e6457600080fd5b505af1158015612e78573d6000803e3d6000fd5b5050505080826001600160a01b0316846001600160a01b03167ffefe036cac4ee3a4aca074a81cbcc4376e1484693289078dbec149c890101d5b60405160405180910390a4505050565b6001600160a01b038216612f09576040805162461bcd60e51b81526020600482015260096024820152684248503a452d34303360b81b604482015290519081900360640190fd5b804710610ee957612f236001600160a01b03831682613327565b6040805182815290516001600160a01b038416917eddb683bb45cd5d0ad8a200c6fae7152b1c236ee90a4a37db692407f5cc38bd919081900360200190a25050565b6000612f7260018361340c565b831663ffffffff1660001415905092915050565b6000612f9360018361340c565b90921792915050565b600080612fb2612fad60018561340c565b613419565b9093169392505050565b600080839050806001600160a01b031663589a1743846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561300657600080fd5b505afa15801561301a573d6000803e3d6000fd5b505050506040513d602081101561303057600080fd5b5051949350505050565b6000806001600160a01b0316600484846040518083838082843791909101948552505060405192839003602001909220546001600160a01b0316929092148015925090506122af575060048383604051808383808284379190910194855250506040805160209481900385018120546358c3de9360e11b825291516001600160a01b039092169463b187bd26945060048083019450909291829003018186803b1580156130e657600080fd5b505afa1580156130fa573d6000803e3d6000fd5b505050506040513d602081101561311057600080fd5b5051159392505050565b6000806001600160a01b0316600584846040518083838082843791909101948552505060405192839003602001909220546001600160a01b0316929092148015925090506122af575060058383604051808383808284379190910194855250506040805160209481900385018120546358c3de9360e11b825291516001600160a01b039092169463b187bd26945060048083019450909291829003018186803b1580156130e657600080fd5b8015613230576001600160a01b0382166000908152600760205260409020546131fb9063ffffffff90811690600490612f8616565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff92909216919091179055613290565b6001600160a01b03821660009081526007602052604090205461325f9063ffffffff90811690600490612f9c16565b6001600160a01b0383166000908152600760205260409020805463ffffffff191663ffffffff929092169190911790555b60408051821515815290516001600160a01b038416917f837a06693ddf982670652b42b0f6ab865e320e35e218201c1171807865c5e5c6919081900360200190a25050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610f5090849061342b565b8047101561337c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d80600081146133c7576040519150601f19603f3d011682016040523d82523d6000602084013e6133cc565b606091505b5050905080610f505760405162461bcd60e51b815260040180806020018281038252603a8152602001806137bf603a913960400191505060405180910390fd5b63ffffffff1660020a0290565b60006134236134dc565b909118919050565b6060613480826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134e29092919063ffffffff16565b805190915015610f505780806020019051602081101561349f57600080fd5b5051610f505760405162461bcd60e51b815260040180806020018281038252602a815260200180613847602a913960400191505060405180910390fd5b60001990565b60606129ff848460008560606134f785612b5a565b613548576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106135875780518252601f199092019160209182019101613568565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146135e9576040519150601f19603f3d011682016040523d82523d6000602084013e6135ee565b606091505b509150915081156136025791506129ff9050565b8051156136125780518082602001fd5b8360405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561365c578181015183820152602001613644565b50505050905090810190601f1680156136895780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106136d857805160ff1916838001178555613705565b82800160010185558215613705579182015b828111156137055782518255916020019190600101906136ea565b50613711929150613783565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106137565782800160ff19823516178555613705565b82800160010185558215613705579182015b82811115613705578235825591602001919060010190613768565b5b80821115613711576000815560010161378456fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d617920686176652072657665727465644f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572312e302e302d626574612e312f636861726765642d7061727469636c65732e72656c61792e726563697069656e745361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220995814c45d4dc522d37ece3feec47cf31d2b557a3eb02fbec6d5fe67ae7a1c9b64736f6c634300060c0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.