ETH Price: $2,306.68 (-0.39%)
Gas: 2.5 Gwei

Contract

0x847A044aF5225f994C60f43e8cF74d20F756187C
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Path Decoder153276342022-08-12 14:58:59766 days ago1660316339IN
0x847A044a...0F756187C
0 ETH0.0008901930.62763846
Set Whitelist St...152142632022-07-25 22:02:20784 days ago1658786540IN
0x847A044a...0F756187C
0 ETH0.000508710.95476914
Set Path Decoder151899252022-07-22 3:10:52788 days ago1658459452IN
0x847A044a...0F756187C
0 ETH0.0003763812.94961399
Set Whitelist St...151822532022-07-20 22:44:50789 days ago1658357090IN
0x847A044a...0F756187C
0 ETH0.0009650520.78199025
Set Path Decoder151736822022-07-19 14:50:49790 days ago1658242249IN
0x847A044a...0F756187C
0 ETH0.0018221562.71841125
Set Whitelist St...151114532022-07-09 23:51:44800 days ago1657410704IN
0x847A044a...0F756187C
0 ETH0.0011222624.16755318
0x60806040151114502022-07-09 23:51:03800 days ago1657410663IN
 Create: AssetStore
0 ETH0.0883601822.03928305

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
151114502022-07-09 23:51:03800 days ago1657410663
0x847A044a...0F756187C
 Contract Creation0 ETH
151114502022-07-09 23:51:03800 days ago1657410663
0x847A044a...0F756187C
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AssetStore

Compiler Version
v0.8.6+commit.11564f7e

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 10 : AssetStore.sol
// SPDX-License-Identifier: MIT

/*
 * On-chain asset store, which allows multiple smart contracts to shara vector assets.
 *
 * All assets registered to this store will be treated as cc0 (public domain), 
 * CC-BY-SA(Attribution-ShareAlike) 2.0, Apache 2.0, MIT, or something similar 
 * (should be specified in the "group"). If the attribution is required, 
 * the creater's name should be either in the "group", "category" or "name".
 *
 * All registered assets will be available to other smart contracts for free, including
 * commecial services. Therefore, it is not allowed to register assets that require
 * any form of commercial licenses. 
 *
 * Once an asset is registed with group/category/name, it is NOT possible to update,
 * which guaranttees the availability in future.
 *
 * Please respect those people who paid gas fees to register those assets. 
 * Their wallet addresses are permanently stored as the "souldbound" attribute
 * of each asset (which is accessible via getAttributes). Using those addressed 
 * for air-drops and whitelisting is one way to appreciate their efforts. 
 * 
 * Created by Satoshi Nakajima (@snakajima)
 */

pragma solidity ^0.8.6;

import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { IAssetStoreRegistry, IAssetStore } from './interfaces/IAssetStore.sol';
import { IStringValidator } from './interfaces/IStringValidator.sol';
import "@openzeppelin/contracts/utils/Strings.sol";
import './libs/StringValidator.sol';
import './libs/StringSet.sol';
import './libs/SVGPathDecoder.sol';

// import "hardhat/console.sol";

/*
 * Abstract contract that implements the categolized asset storage system. 
 */
abstract contract AssetStoreCore is Ownable, IAssetStoreRegistry {
  using StringSet for StringSet.Set;
  using Strings for uint16;
  using Strings for uint256;
  
  struct Asset {
    uint32 groupId;    // index to groups + 1
    uint32 categoryId; // index to categories + 1
    string name;
    string minter;
    bytes metadata;
    address soulbound;
    uint256[] partsIds;
  }

  // Upgradable string validator
  IStringValidator public validator;

  // Upgradable path decoder
  IPathDecoder public decoder;

  // asset & part database
  mapping(uint256 => Asset) private assets;
  uint256 private nextAssetIndex = 1; // 0 indicates an error
  mapping(uint256 => Part) private parts;
  uint256 private nextPartIndex = 1; // 0 indicates an error

  // Groups and categories(for browsing)
  StringSet.Set internal groupSet;
  mapping(uint32 => StringSet.Set) internal categorySets;
  
  // Grouped and categorized assetIds (for browsing)
  struct AssetCatalog {
    mapping(uint32 => uint256) assetIds; 
    uint32 nextAssetIndex;
    mapping(string => uint256) assetNameToId;
  }
  mapping(uint32 => mapping(uint32 => AssetCatalog)) internal assetCatalogs;

  constructor() {
    validator = new StringValidator(); // default validator
    decoder = new SVGPathDecoder(); // default decoder
  }

  /*
   * Returns the groupId of the specified group, creating a new Id if necessary.
   * @notice gruopId == groupIndex + 1
   */
  function _getGroupId(string memory group) private returns(uint32) {
    (uint32 id, bool created) = groupSet.getOrCreateId(group, validator);
    if (created) {
      emit GroupAdded(group); 
    }
    return id;
  }

  /*
   * Returns the categoryId of the specified category in a group, creating a new Id if necessary.
   * The categoryId is unique only within that group. 
   * @notice categoryId == categoryIndex + 1
   */
  function _getCategoryId(string memory group, uint32 groupId, string memory category) private returns(uint32) {
    StringSet.Set storage categorySet =  categorySets[groupId];
    (uint32 id, bool created) = categorySet.getOrCreateId(category, validator);
    if (created) {
      emit CategoryAdded(group, category);
    }
    return id;
  }

  /*
   * Register a Part and returns its id, which is its index in parts[].
   */
  function _registerPart(Part memory _part) private returns(uint256) {
    parts[nextPartIndex++] = _part;
    return nextPartIndex-1;    
  }

  /*
   * We need to validate any strings embedded in SVG to prevent malicious injections. 
   * @notice: group and catalog are validated in Stringset.getId(). 
   *  The body is a binary format, which will be validated when we decode.
   */
  modifier validateAsset(AssetInfo memory _assetInfo) {
    uint size = _assetInfo.parts.length;
    uint i;
    for (i=0; i < size; i++) {
      Part memory part = _assetInfo.parts[i];
      require(validator.validate(bytes(part.color)), "Invalid AssetData Color");
    }
    require(validator.validate(bytes(_assetInfo.name)), "Invalid AssetData Name");
    _;
  }

  /*
   * Register an Asset and returns its id, which is its index in assets[].
   */
  function _registerAsset(AssetInfo memory _assetInfo) internal validateAsset(_assetInfo) returns(uint256) {
    uint32 groupId = _getGroupId(_assetInfo.group);
    uint32 categoryId = _getCategoryId(_assetInfo.group, groupId, _assetInfo.category);
    uint size = _assetInfo.parts.length;
    uint256[] memory partsIds = new uint256[](size);
    uint i;
    for (i=0; i<size; i++) {
      partsIds[i] = _registerPart(_assetInfo.parts[i]);
    }
    uint256 assetId = nextAssetIndex++;
    Asset storage asset = assets[assetId];
    asset.name = _assetInfo.name;
    asset.soulbound = _assetInfo.soulbound;
    uint minterLength = bytes(_assetInfo.minter).length; 
    if (minterLength > 0) {
      require(minterLength <= 32, "AssetSgore: _registerAsset, minter name is too long.");
      asset.minter = _assetInfo.minter; // @notice: no validation
    }
    if (_assetInfo.metadata.length > 0) {
      asset.metadata = _assetInfo.metadata;
    }
    asset.groupId = groupId;
    asset.categoryId = categoryId;
    asset.partsIds = partsIds;
    
    AssetCatalog storage assetCatalog = assetCatalogs[groupId][categoryId];
    require(assetCatalog.assetNameToId[_assetInfo.name] == 0, "Asset already exists with the same group, category and name");
    assetCatalog.assetIds[assetCatalog.nextAssetIndex++] = assetId;
    assetCatalog.assetNameToId[_assetInfo.name] = assetId;

    emit AssetRegistered(msg.sender, assetId);
    return assetId;
  }

  // Returns the number of registered assets
  function getAssetCount() external view returns(uint256) {
    return nextAssetIndex - 1;
  }

  modifier assetExists(uint256 _assetId) {
    require(_assetId > 0 && _assetId < nextAssetIndex, "AssetStore: assetId is out of range"); 
    _;
  }

  modifier partExists(uint256 _partId) {
    require(_partId > 0 && _partId < nextPartIndex, "partId is out of range");
    _;
  }

  // This allows us to keep the assets private. 
  function _getAsset(uint256 _assetId) internal view assetExists(_assetId) returns(Asset memory) {
    return assets[_assetId];
  }

  // This allows us to keep the parts private. 
  function _getPart(uint256 _partId) internal view partExists(_partId) returns(Part memory) {
    return parts[_partId];
  }
}

/*
 * Abstract contract that implements various adminstrative functions, such as
 * managing the whitelist, disable/enable assets and accessing the raw data.
 */
abstract contract AssetStoreAdmin is AssetStoreCore {
  // Upgradable admin (only by owner)
  address public admin;

  /*
   * Whitelist manages the list of contracts which can register assets
   * In future, we disable the whitelist allowing anybody to register assets.
   */
  mapping(address => bool) whitelist;
  bool disableWhitelist = false;

  /*
   * It allows us to disable indivial assets, just in case. 
   */
  mapping(uint256 => bool) disabled;

  constructor() {
    whitelist[msg.sender] = true;
    admin = owner();
  }

  modifier onlyAdmin() {
    require(owner() == _msgSender() || admin == _msgSender(), "AssetStoreAdmin: caller is not the admin");
    _;
  }

  function setAdmin(address _admin) external onlyOwner {
    admin = _admin;
  }  

  function setWhitelistStatus(address _address, bool _status) external onlyAdmin {
    whitelist[_address] = _status;
  }

  function setDisabled(uint256 _assetId, bool _status) external assetExists(_assetId) onlyAdmin {
    disabled[_assetId] = _status;
  }

  function setDisableWhitelist(bool _disable) external onlyAdmin {
    disableWhitelist = _disable;
  } 

  function setValidator(IStringValidator _validator) external onlyAdmin {
    validator = _validator;
  }

  function setPathDecoder(IPathDecoder _decoder) external onlyAdmin {
    decoder = _decoder;
  }

  // returns the raw asset data speicified by the assetId (1, ..., count)
  function getRawAsset(uint256 _assetId) external view onlyAdmin returns(Asset memory) {
    return _getAsset(_assetId);
  }

  // returns the raw part data specified by the assetId (1, ... count)
  function getRawPart(uint256 _partId) external view onlyAdmin returns(Part memory) {
    return _getPart(_partId);
  }
}

/*
 * Concreate contract that implements IAssetStoreRegistory
 * Even though this is a concreate contract, we will never deploy this contract directly. 
 */
contract AppStoreRegistory is AssetStoreAdmin {
  modifier onlyWhitelist {
    require(disableWhitelist || whitelist[msg.sender], "AssetStore: The sender must be in the white list.");
    _;
  }
   
  function registerAsset(AssetInfo memory _assetInfo) external override onlyWhitelist returns(uint256) {
    return _registerAsset(_assetInfo);
  }

  function registerAssets(AssetInfo[] memory _assetInfos) external override onlyWhitelist {
    uint i;
    for (i=0; i<_assetInfos.length; i++) {
      _registerAsset(_assetInfos[i]);
    }
  }
}

/*
 * Concreate contract that implements both IAssetStore and IAssetStoreRegistory
 * This is the contract we deploy to the blockchain.
 */
contract AssetStore is AppStoreRegistory, IAssetStore {
  using Strings for uint16;
  using Strings for uint256;
  using StringSet for StringSet.Set;

  modifier enabled(uint256 _assetId) {
    require(disabled[_assetId] != true, "AssetStore: this asset is diabled");
    _;    
  }

  // Returns the number of registered groups.
  function getGroupCount() external view override returns(uint32) {
    return groupSet.getCount();
  }

  // Returns the name of a group specified with groupIndex (groupId - 1). 
  function getGroupNameAtIndex(uint32 _groupIndex) external view override returns(string memory) {
    return groupSet.nameAtIndex(_groupIndex);
  }

  // Returns the number of categories in the specified group.
  function getCategoryCount(string memory _group) external view override returns(uint32) {
    return categorySets[groupSet.getId(_group)].getCount();
  }

  // Returns the name of category specified with group/categoryIndex pair.
  function getCategoryNameAtIndex(string memory _group, uint32 _categoryIndex) external view override returns(string memory) {
    return categorySets[groupSet.getId(_group)].nameAtIndex(_categoryIndex);
  }

  // Returns the number of asset in the specified group/category. 
  function getAssetCountInCategory(string memory _group, string memory _category) external view override returns(uint32) {
    uint32 groupId = groupSet.getId(_group);
    StringSet.Set storage categorySet = categorySets[groupId];
    return assetCatalogs[groupId][categorySet.getId(_category)].nextAssetIndex;
  }

  // Returns the assetId of the specified group/category/assetIndex. 
  function getAssetIdInCategory(string memory _group, string memory _category, uint32 _assetIndex) external view override returns(uint256) {
    uint32 groupId = groupSet.getId(_group);
    StringSet.Set storage categorySet = categorySets[groupId];
    AssetCatalog storage assetCatalog = assetCatalogs[groupId][categorySet.getId(_category)]; 
    require(_assetIndex < assetCatalog.nextAssetIndex, "The assetIndex is out of range");
    return assetCatalog.assetIds[_assetIndex];
  }

  // Returns the assetId of the specified group/category/name. 
  function getAssetIdWithName(string memory _group, string memory _category, string memory _name) external override view returns(uint256) {
    uint32 groupId = groupSet.getId(_group);
    StringSet.Set storage categorySet = categorySets[groupId];
    return assetCatalogs[groupId][categorySet.getId(_category)].assetNameToId[_name];
  }

  function _getDescription(Asset memory asset) internal view returns(bytes memory) {
    string memory group = groupSet.nameAtIndex(asset.groupId - 1);
    return abi.encodePacked(group, '/', categorySets[asset.groupId].nameAtIndex(asset.categoryId - 1), '/', asset.name);
  }

  /*
   * Generate an id for SVG based on the assetId.
   */
  function _tagForAsset(uint256 _assetId) internal pure returns(string memory) {
    return string(abi.encodePacked('asset', _assetId.toString()));
  }

  function _safeGenerateSVGPart(uint256 _assetId, string memory _tag) internal view returns(bytes memory) {
    Asset memory asset = _getAsset(_assetId);
    uint256[] memory indeces = asset.partsIds;
    bytes memory pack = abi.encodePacked(' <g id="', _tag, '" desc="', _getDescription(asset), '">\n');
    uint i;
    for (i=0; i<indeces.length; i++) {
      Part memory part = _getPart(indeces[i]);
      bytes memory color;
      if (bytes(part.color).length > 0) {
        color = abi.encodePacked(' fill="', part.color ,'"');
      }
      pack = abi.encodePacked(pack, '  <path d="', decoder.decodePath(part.body), '"', color,' />\n');
    }
    pack = abi.encodePacked(pack, ' </g>\n');
    return pack;
  }

  // returns a SVG part with the specified asset
  function generateSVGPart(uint256 _assetId, string memory _tag) external override view enabled(_assetId) returns(string memory) {
    return string(_safeGenerateSVGPart(_assetId, _tag));
  }

  // returns a full SVG with the specified asset
  function generateSVG(uint256 _assetId) external override view enabled(_assetId) returns(string memory) {
    bytes memory pack = abi.encodePacked(
      '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">\n', 
      _safeGenerateSVGPart(_assetId, _tagForAsset(_assetId)), 
      '</svg>');
    return string(pack);
  }

  // returns the attributes of the specified asset
  function getAttributes(uint256 _assetId) external view override returns(AssetAttributes memory) {
    Asset memory asset = _getAsset(_assetId);
    AssetAttributes memory attr;
    attr.name = asset.name;
    attr.tag = _tagForAsset(_assetId);
    attr.soulbound = asset.soulbound;
    attr.minter = asset.minter;
    attr.metadata = asset.metadata;
    attr.group = groupSet.nameAtIndex(asset.groupId - 1);
    attr.category = categorySets[asset.groupId].nameAtIndex(asset.categoryId - 1);
    attr.width = 1024;
    attr.height = 1024;
    return attr;
  }

  function getStringValidator() external override view returns(IStringValidator) {
    return validator;
  }
}

File 2 of 10 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/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.
 */
abstract 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() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual 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 {
        _transferOwnership(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");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 10 : IAssetStore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;

import { IStringValidator } from './IStringValidator.sol';

// IAssetStore is the inteface for consumers of the AsseStore.
interface IAssetStore {
  // Browsing
  function getGroupCount() external view returns(uint32);
  function getGroupNameAtIndex(uint32 _groupIndex) external view returns(string memory);
  function getCategoryCount(string memory _group) external view returns(uint32);
  function getCategoryNameAtIndex(string memory _group, uint32 _categoryIndex) external view returns(string memory);
  function getAssetCountInCategory(string memory _group, string memory _category) external view returns(uint32);
  function getAssetIdInCategory(string memory _group, string memory _category, uint32 _assetIndex) external view returns(uint256);
  function getAssetIdWithName(string memory _group, string memory _category, string memory _name) external view returns(uint256);

  // Fetching
  struct AssetAttributes {
    string group;
    string category;
    string name;
    string tag; // the id in SVG
    string minter; // the name of the minter (who paid the gas fee)
    address soulbound; // wallet address of the minter
    bytes metadata; // group/category specific metadata
    uint16 width;
    uint16 height;
  }

  function generateSVG(uint256 _assetId) external view returns(string memory);
  function generateSVGPart(uint256 _assetId, string memory _tag) external view returns(string memory);
  function getAttributes(uint256 _assetId) external view returns(AssetAttributes memory);
  function getStringValidator() external view returns(IStringValidator);
}

// IAssetStoreRegistry is the interface for contracts who registers assets to the AssetStore.
interface IAssetStoreRegistry {
  struct Part {
    bytes body;
    string color;
  }

  struct AssetInfo {
    string group;
    string category;
    string name;
    string minter; // the name of the minter, who is paying the gas fee
    address soulbound; // wallet address of the minter
    bytes metadata; // group/category specific metadata (optional)
    Part[] parts;
  }

  event AssetRegistered(address from, uint256 assetId);
  event GroupAdded(string group);
  event CategoryAdded(string group, string category);

  function registerAsset(AssetInfo memory _assetInfo) external returns(uint256);
  function registerAssets(AssetInfo[] memory _assetInfos) external;
}

File 4 of 10 : IStringValidator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;

interface IStringValidator {
  function validate(bytes memory str) external pure returns (bool);
  function sanitizeJason(string memory _str) external pure returns(bytes memory);
}

File 5 of 10 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 6 of 10 : StringValidator.sol
// SPDX-License-Identifier: MIT
import { IStringValidator } from '../interfaces/IStringValidator.sol';

pragma solidity ^0.8.6;


contract StringValidator is IStringValidator {
  function validate(bytes memory str) external pure override returns (bool) {
    for(uint i; i < str.length; i++){
      bytes1 char = str[i];
        if(!(
         (char >= 0x30 && char <= 0x39) || //0-9
         (char >= 0x41 && char <= 0x5A) || //A-Z
         (char >= 0x61 && char <= 0x7A) || //a-z
         (char == 0x20) || //SP
         (char == 0x23) || // #
         (char == 0x28) || // (
         (char == 0x29) || // )
         (char == 0x2C) || //,
         (char == 0x2D) || //-
         (char == 0x2E) // .
        )) {
          return false;
      }
    }
    return true;
  }

  function sanitizeJason(string memory _str) external override pure returns(bytes memory) {
    bytes memory src = bytes(_str);
    bytes memory res;
    uint i;
    for (i=0; i<src.length; i++) {
      uint8 b = uint8(src[i]);
      // Skip control codes, escape backslash and double-quote
      if (b >= 0x20) {
        if  (b == 0x5c || b == 0x22) {
          res = abi.encodePacked(res, bytes1(0x5c));
        }
        res = abi.encodePacked(res, b);
      }
    }
    return res;
  }  
}

File 7 of 10 : StringSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;

import { IStringValidator } from '../interfaces/IStringValidator.sol';

/*
 * StringSet stores a set of names (or either group or catalog in AssetStore). 
 */
library StringSet {
  struct Set {
    mapping(uint32 => string) names;
    uint32 nextIndex;
    mapping(string => uint32) ids; // index+1
  }

  function getOrCreateId(Set storage _set, string memory _name, IStringValidator _validator) internal returns(uint32, bool) {
    uint32 id = _set.ids[_name];
    if (id > 0) {
      return (id, false);
    }

    require(_validator.validate(bytes(_name)), "StringSet.getId: Invalid String");
    _set.names[_set.nextIndex++] = _name;
    id = _set.nextIndex; // idex + 1
    _set.ids[_name] = id; 
    return (id, true);
  }

  function getId(Set storage _set, string memory _name) internal view returns (uint32) {
    uint32 id = _set.ids[_name];
    require(id > 0, "StringSet: the specified name does not exist");
    return id;
  }

  /*
   * Retuns the number of items in the set. 
   */
  function getCount(Set storage _set) internal view returns (uint32) {
    return _set.nextIndex;
  }

  /*
   * Safe method to access the name with its index
   */
  function nameAtIndex(Set storage _set, uint32 _index) internal view returns(string memory) {
    require(_index < _set.nextIndex, "StringSet.nameAtIndex: The index is out of range");
    return _set.names[_index];
  }
}

File 8 of 10 : SVGPathDecoder.sol
// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts/utils/Strings.sol";
import "../interfaces/IPathDecoder.sol";

pragma solidity ^0.8.6;

contract SVGPathDecoder is IPathDecoder {
  using Strings for uint16;
  /**
  * Decode the compressed binary deta and reconstruct SVG path. 
  * The binaryformat is 12-bit middle endian, where the low 4-bit of the middle byte is
  * the high 4-bit of the even item ("ijkl"), and the high 4-bit of the middle byte is the high
  * 4-bit of the odd item ("IJKL"). 
  *   abcdefgh ijklIJKL ABCDEFG
  *
  * If we want to upgrade this decoder, it is possible to use the high 4-bit of the first
  * element for versioning, because it is guaraneed to be zero for the current version.
  */
  function decodePath(bytes memory body) external pure override returns (bytes memory) {
    bytes memory ret;
    uint16 i;
    uint16 length = (uint16(body.length) * 2)/ 3;
    for (i = 0; i < length; i++) {
      // unpack 12-bit middle endian
      uint16 offset = i / 2 * 3;
      uint8 low;
      uint8 high;
      if (i % 2 == 0) {
        low = uint8(body[offset]);
        high = uint8(body[offset + 1]) % 0x10; // low 4 bits of middle byte
      } else {
        low = uint8(body[offset + 2]);
        high = uint8(body[offset + 1]) / 0x10; // high 4 bits of middle byte
      }
      if (high == 0) {
        // SVG command: Accept only [A-Za-z] and ignore others 
        if ((low >=65 && low<=90) || (low >= 97 && low <= 122)) {
          ret = abi.encodePacked(ret, low);
        }
      } else {
        // SVG value: undo (value + 1024) + 0x100 
        uint16 value = uint16(high) * 0x100 + uint16(low) - 0x100;
        if (value >= 1024) {
          ret = abi.encodePacked(ret, (value - 1024).toString(), " ");
        } else {
          ret = abi.encodePacked(ret, "-", (1024 - value).toString(), " ");
        }
      }
    }
    return ret;
  }
}

File 9 of 10 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

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

pragma solidity ^0.8.6;

interface IPathDecoder {
  function decodePath(bytes memory body) external pure returns (bytes memory);
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"AssetRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"group","type":"string"},{"indexed":false,"internalType":"string","name":"category","type":"string"}],"name":"CategoryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"group","type":"string"}],"name":"GroupAdded","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"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decoder","outputs":[{"internalType":"contract IPathDecoder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"generateSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"string","name":"_tag","type":"string"}],"name":"generateSVGPart","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"},{"internalType":"string","name":"_category","type":"string"}],"name":"getAssetCountInCategory","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"},{"internalType":"string","name":"_category","type":"string"},{"internalType":"uint32","name":"_assetIndex","type":"uint32"}],"name":"getAssetIdInCategory","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"},{"internalType":"string","name":"_category","type":"string"},{"internalType":"string","name":"_name","type":"string"}],"name":"getAssetIdWithName","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"getAttributes","outputs":[{"components":[{"internalType":"string","name":"group","type":"string"},{"internalType":"string","name":"category","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"tag","type":"string"},{"internalType":"string","name":"minter","type":"string"},{"internalType":"address","name":"soulbound","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"uint16","name":"width","type":"uint16"},{"internalType":"uint16","name":"height","type":"uint16"}],"internalType":"struct IAssetStore.AssetAttributes","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"}],"name":"getCategoryCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_group","type":"string"},{"internalType":"uint32","name":"_categoryIndex","type":"uint32"}],"name":"getCategoryNameAtIndex","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGroupCount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_groupIndex","type":"uint32"}],"name":"getGroupNameAtIndex","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"}],"name":"getRawAsset","outputs":[{"components":[{"internalType":"uint32","name":"groupId","type":"uint32"},{"internalType":"uint32","name":"categoryId","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"minter","type":"string"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"address","name":"soulbound","type":"address"},{"internalType":"uint256[]","name":"partsIds","type":"uint256[]"}],"internalType":"struct AssetStoreCore.Asset","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_partId","type":"uint256"}],"name":"getRawPart","outputs":[{"components":[{"internalType":"bytes","name":"body","type":"bytes"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct IAssetStoreRegistry.Part","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStringValidator","outputs":[{"internalType":"contract IStringValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"group","type":"string"},{"internalType":"string","name":"category","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"minter","type":"string"},{"internalType":"address","name":"soulbound","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"components":[{"internalType":"bytes","name":"body","type":"bytes"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct IAssetStoreRegistry.Part[]","name":"parts","type":"tuple[]"}],"internalType":"struct IAssetStoreRegistry.AssetInfo","name":"_assetInfo","type":"tuple"}],"name":"registerAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"group","type":"string"},{"internalType":"string","name":"category","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"minter","type":"string"},{"internalType":"address","name":"soulbound","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"components":[{"internalType":"bytes","name":"body","type":"bytes"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct IAssetStoreRegistry.Part[]","name":"parts","type":"tuple[]"}],"internalType":"struct IAssetStoreRegistry.AssetInfo[]","name":"_assetInfos","type":"tuple[]"}],"name":"registerAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_disable","type":"bool"}],"name":"setDisableWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"setDisabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPathDecoder","name":"_decoder","type":"address"}],"name":"setPathDecoder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStringValidator","name":"_validator","type":"address"}],"name":"setValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"setWhitelistStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validator","outputs":[{"internalType":"contract IStringValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

608060405260016004819055600655600e805460ff191690553480156200002557600080fd5b50620000313362000107565b6040516200003f9062000157565b604051809103906000f0801580156200005c573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b03929092169190911790556040516200008b9062000165565b604051809103906000f080158015620000a8573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b03928316179055336000908152600d60205260408120805460ff191660011790555416600c80546001600160a01b0319166001600160a01b039290921691909117905562000173565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61068880620036ac83390190565b61082e8062003d3483390190565b61352980620001836000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80636dcee4ca116100f9578063a57cfb2411610097578063eedf630911610071578063eedf6309146103d7578063ef476642146103f7578063f2fde38b1461040a578063f851a4401461041d57600080fd5b8063a57cfb2414610393578063b688a0e2146103a4578063d4f056d4146103c457600080fd5b80637805544c116100d35780637805544c146103545780638da5cb5b146103675780639cb3300514610378578063a0aead4d1461038b57600080fd5b80636dcee4ca14610326578063704b6c0214610339578063715018a61461034c57600080fd5b80634378a6e311610166578063587d62c211610140578063587d62c2146102da5780635b7eea86146102ed5780635c73924c146103005780636613845c1461031357600080fd5b80634378a6e314610286578063468823e2146102a6578063515f28cb146102c757600080fd5b80631327d3d8116101a25780631327d3d81461021557806315ea29be1461022857806334320bf11461023b5780633a5381b51461025b57600080fd5b806306545a93146101c95780630727ca4c146101ed5780630c42428414610202575b600080fd5b60085463ffffffff165b60405163ffffffff90911681526020015b60405180910390f35b6102006101fb366004612932565b610435565b005b610200610210366004612841565b6104cd565b610200610223366004612824565b610578565b610200610236366004612c14565b61061a565b61024e610249366004612c39565b610725565b6040516101e49190613068565b60015461026e906001600160a01b031681565b6040516001600160a01b0390911681526020016101e4565b610299610294366004612bfb565b6107aa565b6040516101e491906130a0565b6102b96102b4366004612b04565b610927565b6040519081526020016101e4565b6101d36102d5366004612a18565b6109ff565b6102006102e836600461287a565b610a66565b6102b96102fb366004612bc6565b610b3d565b61024e61030e366004612c76565b610be3565b610200610321366004612824565b610bf0565b61024e610334366004612bfb565b610c92565b610200610347366004612824565b610d43565b610200610dbf565b61024e610362366004612b78565b610e25565b6000546001600160a01b031661026e565b60025461026e906001600160a01b031681565b6102b9610e69565b6001546001600160a01b031661026e565b6103b76103b2366004612bfb565b610e7a565b6040516101e49190613256565b6101d36103d23660046129e3565b610f17565b6103ea6103e5366004612bfb565b610f51565b6040516101e4919061319c565b6102b9610405366004612a7c565b61102a565b610200610418366004612824565b6110b0565b600c5461026e906001600160a01b031681565b905090565b6000546001600160a01b03163314806104585750600c546001600160a01b031633145b6104ba5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084015b60405180910390fd5b600e805460ff1916911515919091179055565b6000546001600160a01b03163314806104f05750600c546001600160a01b031633145b61054d5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6000546001600160a01b031633148061059b5750600c546001600160a01b031633145b6105f85760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b8160008111801561062c575060045481105b6106845760405162461bcd60e51b815260206004820152602360248201527f417373657453746f72653a2061737365744964206973206f7574206f662072616044820152626e676560e81b60648201526084016104b1565b6000546001600160a01b03163314806106a75750600c546001600160a01b031633145b6107045760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b506000918252600f6020526040909120805460ff1916911515919091179055565b6000828152600f6020526040902054606090839060ff161515600114156107985760405162461bcd60e51b815260206004820152602160248201527f417373657453746f72653a207468697320617373657420697320646961626c656044820152601960fa1b60648201526084016104b1565b6107a28484611192565b949350505050565b61080a604051806101200160405280606081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160608152602001600061ffff168152602001600061ffff1681525090565b60006108158361133f565b9050610877604051806101200160405280606081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160608152602001600061ffff168152602001600061ffff1681525090565b6040808301519082015261088a84611645565b60608083019190915260a0808401516001600160a01b03169083015282015160808083019190915282015160c082015281516108d4906108cc9060019061339b565b600790611676565b8152602082015161090b906108eb9060019061339b565b835163ffffffff9081166000908152600a60205260409020919061167616565b602082015261040060e082018190526101008201529392505050565b6000806109356007866117a2565b63ffffffff8082166000908152600a60209081526040808320600b9092528220939450929091829061096b9085908a906117a216565b63ffffffff9081168252602082019290925260400160002060018101549092508116908616106109dd5760405162461bcd60e51b815260206004820152601e60248201527f546865206173736574496e646578206973206f7574206f662072616e6765000060448201526064016104b1565b63ffffffff851660009081526020919091526040902054925050509392505050565b600080610a0d6007856117a2565b63ffffffff8082166000908152600a60209081526040808320600b90925282209394509291610a4090849088906117a216565b63ffffffff90811682526020820192909252604001600020600101541695945050505050565b600e5460ff1680610a865750336000908152600d602052604090205460ff165b610af85760405162461bcd60e51b815260206004820152603160248201527f417373657453746f72653a205468652073656e646572206d757374206265206960448201527f6e20746865207768697465206c6973742e00000000000000000000000000000060648201526084016104b1565b60005b8151811015610b3957610b26828281518110610b1957610b196134a4565b6020026020010151611842565b5080610b3181613425565b915050610afb565b5050565b600e5460009060ff1680610b605750336000908152600d602052604090205460ff165b610bd25760405162461bcd60e51b815260206004820152603160248201527f417373657453746f72653a205468652073656e646572206d757374206265206960448201527f6e20746865207768697465206c6973742e00000000000000000000000000000060648201526084016104b1565b610bdb82611842565b90505b919050565b6060610bdb600783611676565b6000546001600160a01b0316331480610c135750600c546001600160a01b031633145b610c705760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600f6020526040902054606090829060ff16151560011415610d055760405162461bcd60e51b815260206004820152602160248201527f417373657453746f72653a207468697320617373657420697320646961626c656044820152601960fa1b60648201526084016104b1565b6000610d1984610d1486611645565b611192565b604051602001610d299190612eb5565b60408051601f198184030181529190529250505b50919050565b6000546001600160a01b03163314610d9d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610e195760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b610e236000611dfe565b565b6060610e6282600a6000610e3a6007886117a2565b63ffffffff1663ffffffff16815260200190815260200160002061167690919063ffffffff16565b9392505050565b600060016004546104309190613384565b60408051808201909152606080825260208201526000546001600160a01b0316331480610eb15750600c546001600160a01b031633145b610f0e5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b610bdb82611e4e565b6000610bdb600a82610f2a6007866117a2565b63ffffffff1663ffffffff1681526020019081526020016000206001015463ffffffff1690565b6040805160e08101825260008082526020820181905260609282018390528282018390526080820183905260a082015260c0810191909152336001600160a01b0316610fa56000546001600160a01b031690565b6001600160a01b03161480610fc45750600c546001600160a01b031633145b6110215760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b610bdb8261133f565b6000806110386007866117a2565b63ffffffff8082166000908152600a60209081526040808320600b9092528220939450929161106b90849089906117a216565b63ffffffff1663ffffffff168152602001908152602001600020600201846040516110969190612dde565b908152602001604051809103902054925050509392505050565b6000546001600160a01b0316331461110a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b6001600160a01b0381166111865760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104b1565b61118f81611dfe565b50565b6060600061119f8461133f565b60c08101519091506000846111b384611ffa565b6040516020016111c4929190612fbd565b604051602081830303815290604052905060005b82518110156113135760006112058483815181106111f8576111f86134a4565b6020026020010151611e4e565b905060606000826020015151111561123c5760208083015160405161122a9201612f6d565b60405160208183030381529060405290505b60025482516040517fc25ddce000000000000000000000000000000000000000000000000000000000815286926001600160a01b03169163c25ddce0916112869190600401613068565b60006040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112da919081019061296c565b826040516020016112ed93929190612cf8565b60405160208183030381529060405293505050808061130b90613425565b9150506111d8565b816040516020016113249190612d9d565b60408051808303601f19018152919052979650505050505050565b6040805160e08101825260008082526020820181905260609282018390528282018390526080820183905260a082015260c081019190915281600081118015611389575060045481105b6113e15760405162461bcd60e51b815260206004820152602360248201527f417373657453746f72653a2061737365744964206973206f7574206f662072616044820152626e676560e81b60648201526084016104b1565b600083815260036020908152604091829020825160e081018452815463ffffffff80821683526401000000009091041692810192909252600181018054929391929184019161142f906133f0565b80601f016020809104026020016040519081016040528092919081815260200182805461145b906133f0565b80156114a85780601f1061147d576101008083540402835291602001916114a8565b820191906000526020600020905b81548152906001019060200180831161148b57829003601f168201915b505050505081526020016002820180546114c1906133f0565b80601f01602080910402602001604051908101604052809291908181526020018280546114ed906133f0565b801561153a5780601f1061150f5761010080835404028352916020019161153a565b820191906000526020600020905b81548152906001019060200180831161151d57829003601f168201915b50505050508152602001600382018054611553906133f0565b80601f016020809104026020016040519081016040528092919081815260200182805461157f906133f0565b80156115cc5780601f106115a1576101008083540402835291602001916115cc565b820191906000526020600020905b8154815290600101906020018083116115af57829003601f168201915b505050918352505060048201546001600160a01b0316602080830191909152600583018054604080518285028101850182528281529401939283018282801561163457602002820191906000526020600020905b815481526020019060010190808311611620575b505050505081525050915050919050565b606061165082612077565b6040516020016116609190612e70565b6040516020818303038152906040529050919050565b600182015460609063ffffffff908116908316106116fc5760405162461bcd60e51b815260206004820152603060248201527f537472696e675365742e6e616d654174496e6465783a2054686520696e64657860448201527f206973206f7574206f662072616e67650000000000000000000000000000000060648201526084016104b1565b63ffffffff82166000908152602084905260409020805461171c906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611748906133f0565b80156117955780601f1061176a57610100808354040283529160200191611795565b820191906000526020600020905b81548152906001019060200180831161177857829003601f168201915b5050505050905092915050565b60008083600201836040516117b79190612dde565b9081526040519081900360200190205463ffffffff16905080610e625760405162461bcd60e51b815260206004820152602c60248201527f537472696e675365743a2074686520737065636966696564206e616d6520646f60448201527f6573206e6f74206578697374000000000000000000000000000000000000000060648201526084016104b1565b60c0810151516000908290825b818110156119605760008360c00151828151811061186f5761186f6134a4565b6020908102919091018101516001549181015160405163c16e50ef60e01b81529193506001600160a01b039092169163c16e50ef916118b19190600401613068565b60206040518083038186803b1580156118c957600080fd5b505afa1580156118dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611901919061294f565b61194d5760405162461bcd60e51b815260206004820152601760248201527f496e76616c69642041737365744461746120436f6c6f7200000000000000000060448201526064016104b1565b508061195881613425565b91505061184f565b600154604080850151905163c16e50ef60e01b81526001600160a01b039092169163c16e50ef9161199391600401613068565b60206040518083038186803b1580156119ab57600080fd5b505afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e3919061294f565b611a2f5760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420417373657444617461204e616d650000000000000000000060448201526064016104b1565b6000611a3e86600001516121a9565b90506000611a558760000151838960200151612213565b60c08801515190915060008167ffffffffffffffff811115611a7957611a796134ba565b604051908082528060200260200182016040528015611aa2578160200160208202803683370190505b50905060005b82811015611b0557611ad68a60c001518281518110611ac957611ac96134a4565b602002602001015161229c565b828281518110611ae857611ae86134a4565b602090810291909101015280611afd81613425565b915050611aa8565b6004805460009182611b1683613425565b90915550600081815260036020908152604091829020918e015180519394509192611b4792600185019201906124db565b5060808c01516004820180546001600160a01b0319166001600160a01b0390921691909117905560608c0151518015611c0e576020811115611bf15760405162461bcd60e51b815260206004820152603460248201527f417373657453676f72653a205f726567697374657241737365742c206d696e7460448201527f6572206e616d6520697320746f6f206c6f6e672e00000000000000000000000060648201526084016104b1565b60608d01518051611c0c9160028501916020909101906124db565b505b60a08d01515115611c365760a08d01518051611c349160038501916020909101906124db565b505b815463ffffffff8881166401000000000267ffffffffffffffff19909216908a16171782558451611c70906005840190602088019061255f565b5063ffffffff8089166000908152600b60209081526040808320938b1683529290528190208e820151915190916002830191611cac9190612dde565b908152602001604051809103902054600014611d305760405162461bcd60e51b815260206004820152603b60248201527f417373657420616c72656164792065786973747320776974682074686520736160448201527f6d652067726f75702c2063617465676f727920616e64206e616d65000000000060648201526084016104b1565b6001810180548591839160009163ffffffff9091169082611d5083613440565b91906101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff1663ffffffff1681526020019081526020016000208190555083816002018f60400151604051611da39190612dde565b9081526040805160209281900383018120939093553383529082018690527ffd64e3f1068245597a589d8b057edbd3d3c312207d5c6d0d770825f68604ff1a910160405180910390a150919c9b505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080518082019091526060808252602082015281600081118015611e74575060065481105b611ec05760405162461bcd60e51b815260206004820152601660248201527f706172744964206973206f7574206f662072616e67650000000000000000000060448201526064016104b1565b600083815260056020526040908190208151808301909252805482908290611ee7906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611f13906133f0565b8015611f605780601f10611f3557610100808354040283529160200191611f60565b820191906000526020600020905b815481529060010190602001808311611f4357829003601f168201915b50505050508152602001600182018054611f79906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611fa5906133f0565b80156116345780601f10611fc757610100808354040283529160200191611634565b820191906000526020600020905b815481529060010190602001808311611fd55750505091909252509195945050505050565b60606000612012600184600001516108cc919061339b565b90508061204960018560200151612029919061339b565b855163ffffffff9081166000908152600a60205260409020919061167616565b846040015160405160200161206093929190612dfa565b604051602081830303815290604052915050919050565b6060816120b757505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156120e157806120cb81613425565b91506120da9050600a83613370565b91506120bb565b60008167ffffffffffffffff8111156120fc576120fc6134ba565b6040519080825280601f01601f191660200182016040528015612126576020820181803683370190505b5090505b84156107a25761213b600183613384565b9150612148600a86613464565b612153906030613358565b60f81b818381518110612168576121686134a4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506121a2600a86613370565b945061212a565b600154600090819081906121ca9060079086906001600160a01b031661230b565b91509150801561220c577ff38f46310740c7f6f3e724364a429e671b125298f7a65e69fc18ff94a1e2d047846040516122039190613068565b60405180910390a15b5092915050565b63ffffffff8083166000908152600a60205260408120600154919290918391829161224e91859188916001600160a01b039091169061230b16565b915091508015612292577fcbc1b8c1fb300e15a9e99dc508aecdff1352f0fad4a5e4b7832d41e369635c03878660405161228992919061307b565b60405180910390a15b5095945050505050565b60008160056000600660008154809291906122b690613425565b9091555081526020808201929092526040016000208251805191926122e0928492909101906124db565b5060208281015180516122f992600185019201906124db565b5050600654610bdb9150600190613384565b600080600085600201856040516123229190612dde565b9081526040519081900360200190205463ffffffff169050801561234b579150600090506124d3565b60405163c16e50ef60e01b81526001600160a01b0385169063c16e50ef90612377908890600401613068565b60206040518083038186803b15801561238f57600080fd5b505afa1580156123a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c7919061294f565b6124135760405162461bcd60e51b815260206004820152601f60248201527f537472696e675365742e67657449643a20496e76616c696420537472696e670060448201526064016104b1565b6001860180548691889160009163ffffffff909116908261243383613440565b91906101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff1663ffffffff168152602001908152602001600020908051906020019061247e9291906124db565b5050600185015460405163ffffffff90911690819060028801906124a3908890612dde565b908152604051908190036020019020805463ffffffff9290921663ffffffff199092169190911790559150600190505b935093915050565b8280546124e7906133f0565b90600052602060002090601f016020900481019282612509576000855561254f565b82601f1061252257805160ff191683800117855561254f565b8280016001018555821561254f579182015b8281111561254f578251825591602001919060010190612534565b5061255b929150612599565b5090565b82805482825590600052602060002090810192821561254f579160200282018281111561254f578251825591602001919060010190612534565b5b8082111561255b576000815560010161259a565b8035610bde816134d0565b600082601f8301126125ca57600080fd5b813560206125df6125da8361330c565b6132db565b80838252828201915082860187848660051b89010111156125ff57600080fd5b60005b8581101561269e57813567ffffffffffffffff8082111561262257600080fd5b908901906040828c03601f190181131561263b57600080fd5b61264361328f565b888401358381111561265457600080fd5b6126628e8b838801016126ab565b82525090830135908282111561267757600080fd5b6126858d8a848701016126ab565b818a015287525050509284019290840190600101612602565b5090979650505050505050565b600082601f8301126126bc57600080fd5b81356126ca6125da82613330565b8181528460208386010111156126df57600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561270e57600080fd5b6127166132b8565b9050813567ffffffffffffffff8082111561273057600080fd5b61273c858386016126ab565b8352602084013591508082111561275257600080fd5b61275e858386016126ab565b6020840152604084013591508082111561277757600080fd5b612783858386016126ab565b6040840152606084013591508082111561279c57600080fd5b6127a8858386016126ab565b60608401526127b9608085016125ae565b608084015260a08401359150808211156127d257600080fd5b6127de858386016126ab565b60a084015260c08401359150808211156127f757600080fd5b50612804848285016125b9565b60c08301525092915050565b803563ffffffff81168114610bde57600080fd5b60006020828403121561283657600080fd5b8135610e62816134d0565b6000806040838503121561285457600080fd5b823561285f816134d0565b9150602083013561286f816134e5565b809150509250929050565b6000602080838503121561288d57600080fd5b823567ffffffffffffffff808211156128a557600080fd5b818501915085601f8301126128b957600080fd5b81356128c76125da8261330c565b80828252858201915085850189878560051b88010111156128e757600080fd5b6000805b8581101561292257823587811115612901578283fd5b61290f8d8b838c01016126fc565b86525093880193918801916001016128eb565b50919a9950505050505050505050565b60006020828403121561294457600080fd5b8135610e62816134e5565b60006020828403121561296157600080fd5b8151610e62816134e5565b60006020828403121561297e57600080fd5b815167ffffffffffffffff81111561299557600080fd5b8201601f810184136129a657600080fd5b80516129b46125da82613330565b8181528560208385010111156129c957600080fd5b6129da8260208301602086016133c0565b95945050505050565b6000602082840312156129f557600080fd5b813567ffffffffffffffff811115612a0c57600080fd5b6107a2848285016126ab565b60008060408385031215612a2b57600080fd5b823567ffffffffffffffff80821115612a4357600080fd5b612a4f868387016126ab565b93506020850135915080821115612a6557600080fd5b50612a72858286016126ab565b9150509250929050565b600080600060608486031215612a9157600080fd5b833567ffffffffffffffff80821115612aa957600080fd5b612ab5878388016126ab565b94506020860135915080821115612acb57600080fd5b612ad7878388016126ab565b93506040860135915080821115612aed57600080fd5b50612afa868287016126ab565b9150509250925092565b600080600060608486031215612b1957600080fd5b833567ffffffffffffffff80821115612b3157600080fd5b612b3d878388016126ab565b94506020860135915080821115612b5357600080fd5b50612b60868287016126ab565b925050612b6f60408501612810565b90509250925092565b60008060408385031215612b8b57600080fd5b823567ffffffffffffffff811115612ba257600080fd5b612bae858286016126ab565b925050612bbd60208401612810565b90509250929050565b600060208284031215612bd857600080fd5b813567ffffffffffffffff811115612bef57600080fd5b6107a2848285016126fc565b600060208284031215612c0d57600080fd5b5035919050565b60008060408385031215612c2757600080fd5b82359150602083013561286f816134e5565b60008060408385031215612c4c57600080fd5b82359150602083013567ffffffffffffffff811115612c6a57600080fd5b612a72858286016126ab565b600060208284031215612c8857600080fd5b610e6282612810565b600081518084526020808501945080840160005b83811015612cc157815187529582019590820190600101612ca5565b509495945050505050565b60008151808452612ce48160208601602086016133c0565b601f01601f19169290920160200192915050565b60008451612d0a8184602089016133c0565b7f20203c7061746820643d220000000000000000000000000000000000000000009083019081528451612d4481600b8401602089016133c0565b601160f91b600b92909101918201528351612d6681600c8401602088016133c0565b7f202f3e0a00000000000000000000000000000000000000000000000000000000600c929091019182015260100195945050505050565b60008251612daf8184602087016133c0565b7f203c2f673e0a0000000000000000000000000000000000000000000000000000920191825250600601919050565b60008251612df08184602087016133c0565b9190910192915050565b60008451612e0c8184602089016133c0565b80830190507f2f000000000000000000000000000000000000000000000000000000000000008082528551612e48816001850160208a016133c0565b60019201918201528351612e638160028401602088016133c0565b0160020195945050505050565b7f6173736574000000000000000000000000000000000000000000000000000000815260008251612ea88160058501602087016133c0565b9190910160050192915050565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667223e60208201527f0a00000000000000000000000000000000000000000000000000000000000000604082015260008251612f398160418501602087016133c0565b7f3c2f7376673e00000000000000000000000000000000000000000000000000006041939091019283015250604701919050565b7f2066696c6c3d2200000000000000000000000000000000000000000000000000815260008251612fa58160078501602087016133c0565b601160f91b6007939091019283015250600801919050565b7f203c672069643d22000000000000000000000000000000000000000000000000815260008351612ff58160088501602088016133c0565b7f2220646573633d2200000000000000000000000000000000000000000000000060089184019182015283516130328160108401602088016133c0565b7f223e0a000000000000000000000000000000000000000000000000000000000060109290910191820152601301949350505050565b602081526000610e626020830184612ccc565b60408152600061308e6040830185612ccc565b82810360208401526129da8185612ccc565b60208152600082516101208060208501526130bf610140850183612ccc565b91506020850151601f19808685030160408701526130dd8483612ccc565b935060408701519150808685030160608701526130fa8483612ccc565b935060608701519150808685030160808701526131178483612ccc565b935060808701519150808685030160a08701526131348483612ccc565b935060a0870151915061315260c08701836001600160a01b03169052565b60c08701519150808685030160e08701525061316e8382612ccc565b92505060e08501516101006131888187018361ffff169052565b9095015161ffff1693019290925250919050565b6020815263ffffffff8251166020820152600060208301516131c6604084018263ffffffff169052565b50604083015160e060608401526131e1610100840182612ccc565b90506060840151601f19808584030160808601526131ff8383612ccc565b925060808601519150808584030160a086015261321c8383612ccc565b925060a0860151915061323a60c08601836001600160a01b03169052565b60c08601519150808584030160e0860152506129da8282612c91565b6020815260008251604060208401526132726060840182612ccc565b90506020840151601f198483030160408501526129da8282612ccc565b6040805190810167ffffffffffffffff811182821017156132b2576132b26134ba565b60405290565b60405160e0810167ffffffffffffffff811182821017156132b2576132b26134ba565b604051601f8201601f1916810167ffffffffffffffff81118282101715613304576133046134ba565b604052919050565b600067ffffffffffffffff821115613326576133266134ba565b5060051b60200190565b600067ffffffffffffffff82111561334a5761334a6134ba565b50601f01601f191660200190565b6000821982111561336b5761336b613478565b500190565b60008261337f5761337f61348e565b500490565b60008282101561339657613396613478565b500390565b600063ffffffff838116908316818110156133b8576133b8613478565b039392505050565b60005b838110156133db5781810151838201526020016133c3565b838111156133ea576000848401525b50505050565b600181811c9082168061340457607f821691505b60208210811415610d3d57634e487b7160e01b600052602260045260246000fd5b600060001982141561343957613439613478565b5060010190565b600063ffffffff8083168181141561345a5761345a613478565b6001019392505050565b6000826134735761347361348e565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461118f57600080fd5b801515811461118f57600080fdfea2646970667358221220be1ca473099cbe293ec88f3339943d2b6f257924bbba0b2a39631f475b628c7064736f6c63430008060033608060405234801561001057600080fd5b50610668806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063841b9d971461003b578063c16e50ef14610064575b600080fd5b61004e6100493660046104c8565b610087565b60405161005b919061057a565b60405180910390f35b6100776100723660046104c8565b61015c565b604051901515815260200161005b565b6060818160005b82518110156101545760008382815181106100ab576100ab610606565b0160209081015160f81c91508110610141578060ff16605c14806100d257508060ff166022145b1561011c5760405161010a9084907f5c0000000000000000000000000000000000000000000000000000000000000090602001610519565b60405160208183030381529060405292505b828160405160200161012f929190610548565b60405160208183030381529060405292505b508061014c816105dd565b91505061008e565b509392505050565b6000805b825181101561044957600083828151811061017d5761017d610606565b01602001516001600160f81b03191690507f300000000000000000000000000000000000000000000000000000000000000081108015906101e857507f39000000000000000000000000000000000000000000000000000000000000006001600160f81b0319821611155b8061025257507f41000000000000000000000000000000000000000000000000000000000000006001600160f81b031982161080159061025257507f5a000000000000000000000000000000000000000000000000000000000000006001600160f81b0319821611155b806102bc57507f61000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216108015906102bc57507f7a000000000000000000000000000000000000000000000000000000000000006001600160f81b0319821611155b806102f057507f20000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b8061032457507f23000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b8061035857507f28000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b8061038c57507f29000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b806103c057507f2c000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b806103f457507f2d000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b8061042857507f2e000000000000000000000000000000000000000000000000000000000000006001600160f81b03198216145b610436575060009392505050565b5080610441816105dd565b915050610160565b50600192915050565b600067ffffffffffffffff8084111561046d5761046d61061c565b604051601f8501601f19908116603f011681019082821181831017156104955761049561061c565b816040528093508581528686860111156104ae57600080fd5b858560208301376000602087830101525050509392505050565b6000602082840312156104da57600080fd5b813567ffffffffffffffff8111156104f157600080fd5b8201601f8101841361050257600080fd5b61051184823560208401610452565b949350505050565b6000835161052b8184602088016105ad565b6001600160f81b0319939093169190920190815260010192915050565b6000835161055a8184602088016105ad565b60f89390931b6001600160f81b0319169190920190815260010192915050565b60208152600082518060208401526105998160408501602087016105ad565b601f01601f19169190910160400192915050565b60005b838110156105c85781810151838201526020016105b0565b838111156105d7576000848401525b50505050565b60006000198214156105ff57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122028de3ea356ff2473cb06ced2b60ec6bff0870d580e0dff7bd56ed390bb5b3af964736f6c63430008060033608060405234801561001057600080fd5b5061080e806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c25ddce014610030575b600080fd5b61004361003e3660046103f4565b610059565b6040516100509190610590565b60405180910390f35b60608060008060038551600261006f9190610658565b6100799190610601565b9050600091505b8061ffff168261ffff1610156102b157600061009d600284610601565b6100a8906003610658565b90506000806100b8600286610729565b61ffff1661011b57878361ffff16815181106100d6576100d66107ac565b016020015160f81c91506010886100ee8560016105c3565b61ffff1681518110610102576101026107ac565b0160200151610114919060f81c61075e565b905061017c565b876101278460026105c3565b61ffff168151811061013b5761013b6107ac565b016020015160f81c91506010886101538560016105c3565b61ffff1681518110610167576101676107ac565b0160200151610179919060f81c610636565b90505b60ff81166101e95760418260ff161015801561019c5750605a8260ff1611155b806101ba575060618260ff16101580156101ba5750607a8260ff1611155b156101e45785826040516020016101d2929190610546565b60405160208183030381529060405295505b61029b565b60006101008360ff168360ff166101006102039190610658565b61020d91906105c3565b6102179190610682565b90506104008161ffff1610610266578661023f61023661040084610682565b61ffff166102ba565b6040516020016102509291906104a5565b6040516020818303038152906040529650610299565b8661027661023683610400610682565b6040516020016102879291906104e0565b60405160208183030381529060405296505b505b50505081806102a9906106ec565b925050610080565b50909392505050565b6060816102fa57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610324578061030e8161070e565b915061031d9050600a83610622565b91506102fe565b60008167ffffffffffffffff81111561033f5761033f6107c2565b6040519080825280601f01601f191660200182016040528015610369576020820181803683370190505b5090505b84156103ec5761037e6001836106a5565b915061038b600a8661074a565b6103969060306105e9565b60f81b8183815181106103ab576103ab6107ac565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506103e5600a86610622565b945061036d565b949350505050565b60006020828403121561040657600080fd5b813567ffffffffffffffff8082111561041e57600080fd5b818401915084601f83011261043257600080fd5b813581811115610444576104446107c2565b604051601f8201601f19908116603f0116810190838211818310171561046c5761046c6107c2565b8160405282815287602084870101111561048557600080fd5b826020860160208301376000928101602001929092525095945050505050565b600083516104b78184602088016106bc565b8351908301906104cb8183602088016106bc565b600160fd1b9101908152600101949350505050565b600083516104f28184602088016106bc565b7f2d00000000000000000000000000000000000000000000000000000000000000908301908152835161052c8160018401602088016106bc565b600160fd1b60019290910191820152600201949350505050565b600083516105588184602088016106bc565b60f89390931b7fff00000000000000000000000000000000000000000000000000000000000000169190920190815260010192915050565b60208152600082518060208401526105af8160408501602087016106bc565b601f01601f19169190910160400192915050565b600061ffff8083168185168083038211156105e0576105e0610780565b01949350505050565b600082198211156105fc576105fc610780565b500190565b600061ffff8084168061061657610616610796565b92169190910492915050565b60008261063157610631610796565b500490565b600060ff83168061064957610649610796565b8060ff84160491505092915050565b600061ffff8083168185168183048111821515161561067957610679610780565b02949350505050565b600061ffff8381169083168181101561069d5761069d610780565b039392505050565b6000828210156106b7576106b7610780565b500390565b60005b838110156106d75781810151838201526020016106bf565b838111156106e6576000848401525b50505050565b600061ffff8083168181141561070457610704610780565b6001019392505050565b600060001982141561072257610722610780565b5060010190565b600061ffff8084168061073e5761073e610796565b92169190910692915050565b60008261075957610759610796565b500690565b600060ff83168061077157610771610796565b8060ff84160691505092915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea2646970667358221220038bd1c52f0e6583e742e3cf819d576aface40be80a5533beb30205cc733e91864736f6c63430008060033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80636dcee4ca116100f9578063a57cfb2411610097578063eedf630911610071578063eedf6309146103d7578063ef476642146103f7578063f2fde38b1461040a578063f851a4401461041d57600080fd5b8063a57cfb2414610393578063b688a0e2146103a4578063d4f056d4146103c457600080fd5b80637805544c116100d35780637805544c146103545780638da5cb5b146103675780639cb3300514610378578063a0aead4d1461038b57600080fd5b80636dcee4ca14610326578063704b6c0214610339578063715018a61461034c57600080fd5b80634378a6e311610166578063587d62c211610140578063587d62c2146102da5780635b7eea86146102ed5780635c73924c146103005780636613845c1461031357600080fd5b80634378a6e314610286578063468823e2146102a6578063515f28cb146102c757600080fd5b80631327d3d8116101a25780631327d3d81461021557806315ea29be1461022857806334320bf11461023b5780633a5381b51461025b57600080fd5b806306545a93146101c95780630727ca4c146101ed5780630c42428414610202575b600080fd5b60085463ffffffff165b60405163ffffffff90911681526020015b60405180910390f35b6102006101fb366004612932565b610435565b005b610200610210366004612841565b6104cd565b610200610223366004612824565b610578565b610200610236366004612c14565b61061a565b61024e610249366004612c39565b610725565b6040516101e49190613068565b60015461026e906001600160a01b031681565b6040516001600160a01b0390911681526020016101e4565b610299610294366004612bfb565b6107aa565b6040516101e491906130a0565b6102b96102b4366004612b04565b610927565b6040519081526020016101e4565b6101d36102d5366004612a18565b6109ff565b6102006102e836600461287a565b610a66565b6102b96102fb366004612bc6565b610b3d565b61024e61030e366004612c76565b610be3565b610200610321366004612824565b610bf0565b61024e610334366004612bfb565b610c92565b610200610347366004612824565b610d43565b610200610dbf565b61024e610362366004612b78565b610e25565b6000546001600160a01b031661026e565b60025461026e906001600160a01b031681565b6102b9610e69565b6001546001600160a01b031661026e565b6103b76103b2366004612bfb565b610e7a565b6040516101e49190613256565b6101d36103d23660046129e3565b610f17565b6103ea6103e5366004612bfb565b610f51565b6040516101e4919061319c565b6102b9610405366004612a7c565b61102a565b610200610418366004612824565b6110b0565b600c5461026e906001600160a01b031681565b905090565b6000546001600160a01b03163314806104585750600c546001600160a01b031633145b6104ba5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084015b60405180910390fd5b600e805460ff1916911515919091179055565b6000546001600160a01b03163314806104f05750600c546001600160a01b031633145b61054d5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6000546001600160a01b031633148061059b5750600c546001600160a01b031633145b6105f85760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b8160008111801561062c575060045481105b6106845760405162461bcd60e51b815260206004820152602360248201527f417373657453746f72653a2061737365744964206973206f7574206f662072616044820152626e676560e81b60648201526084016104b1565b6000546001600160a01b03163314806106a75750600c546001600160a01b031633145b6107045760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b506000918252600f6020526040909120805460ff1916911515919091179055565b6000828152600f6020526040902054606090839060ff161515600114156107985760405162461bcd60e51b815260206004820152602160248201527f417373657453746f72653a207468697320617373657420697320646961626c656044820152601960fa1b60648201526084016104b1565b6107a28484611192565b949350505050565b61080a604051806101200160405280606081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160608152602001600061ffff168152602001600061ffff1681525090565b60006108158361133f565b9050610877604051806101200160405280606081526020016060815260200160608152602001606081526020016060815260200160006001600160a01b0316815260200160608152602001600061ffff168152602001600061ffff1681525090565b6040808301519082015261088a84611645565b60608083019190915260a0808401516001600160a01b03169083015282015160808083019190915282015160c082015281516108d4906108cc9060019061339b565b600790611676565b8152602082015161090b906108eb9060019061339b565b835163ffffffff9081166000908152600a60205260409020919061167616565b602082015261040060e082018190526101008201529392505050565b6000806109356007866117a2565b63ffffffff8082166000908152600a60209081526040808320600b9092528220939450929091829061096b9085908a906117a216565b63ffffffff9081168252602082019290925260400160002060018101549092508116908616106109dd5760405162461bcd60e51b815260206004820152601e60248201527f546865206173736574496e646578206973206f7574206f662072616e6765000060448201526064016104b1565b63ffffffff851660009081526020919091526040902054925050509392505050565b600080610a0d6007856117a2565b63ffffffff8082166000908152600a60209081526040808320600b90925282209394509291610a4090849088906117a216565b63ffffffff90811682526020820192909252604001600020600101541695945050505050565b600e5460ff1680610a865750336000908152600d602052604090205460ff165b610af85760405162461bcd60e51b815260206004820152603160248201527f417373657453746f72653a205468652073656e646572206d757374206265206960448201527f6e20746865207768697465206c6973742e00000000000000000000000000000060648201526084016104b1565b60005b8151811015610b3957610b26828281518110610b1957610b196134a4565b6020026020010151611842565b5080610b3181613425565b915050610afb565b5050565b600e5460009060ff1680610b605750336000908152600d602052604090205460ff165b610bd25760405162461bcd60e51b815260206004820152603160248201527f417373657453746f72653a205468652073656e646572206d757374206265206960448201527f6e20746865207768697465206c6973742e00000000000000000000000000000060648201526084016104b1565b610bdb82611842565b90505b919050565b6060610bdb600783611676565b6000546001600160a01b0316331480610c135750600c546001600160a01b031633145b610c705760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600f6020526040902054606090829060ff16151560011415610d055760405162461bcd60e51b815260206004820152602160248201527f417373657453746f72653a207468697320617373657420697320646961626c656044820152601960fa1b60648201526084016104b1565b6000610d1984610d1486611645565b611192565b604051602001610d299190612eb5565b60408051601f198184030181529190529250505b50919050565b6000546001600160a01b03163314610d9d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610e195760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b610e236000611dfe565b565b6060610e6282600a6000610e3a6007886117a2565b63ffffffff1663ffffffff16815260200190815260200160002061167690919063ffffffff16565b9392505050565b600060016004546104309190613384565b60408051808201909152606080825260208201526000546001600160a01b0316331480610eb15750600c546001600160a01b031633145b610f0e5760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b610bdb82611e4e565b6000610bdb600a82610f2a6007866117a2565b63ffffffff1663ffffffff1681526020019081526020016000206001015463ffffffff1690565b6040805160e08101825260008082526020820181905260609282018390528282018390526080820183905260a082015260c0810191909152336001600160a01b0316610fa56000546001600160a01b031690565b6001600160a01b03161480610fc45750600c546001600160a01b031633145b6110215760405162461bcd60e51b815260206004820152602860248201527f417373657453746f726541646d696e3a2063616c6c6572206973206e6f74207460448201526734329030b236b4b760c11b60648201526084016104b1565b610bdb8261133f565b6000806110386007866117a2565b63ffffffff8082166000908152600a60209081526040808320600b9092528220939450929161106b90849089906117a216565b63ffffffff1663ffffffff168152602001908152602001600020600201846040516110969190612dde565b908152602001604051809103902054925050509392505050565b6000546001600160a01b0316331461110a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104b1565b6001600160a01b0381166111865760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104b1565b61118f81611dfe565b50565b6060600061119f8461133f565b60c08101519091506000846111b384611ffa565b6040516020016111c4929190612fbd565b604051602081830303815290604052905060005b82518110156113135760006112058483815181106111f8576111f86134a4565b6020026020010151611e4e565b905060606000826020015151111561123c5760208083015160405161122a9201612f6d565b60405160208183030381529060405290505b60025482516040517fc25ddce000000000000000000000000000000000000000000000000000000000815286926001600160a01b03169163c25ddce0916112869190600401613068565b60006040518083038186803b15801561129e57600080fd5b505afa1580156112b2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112da919081019061296c565b826040516020016112ed93929190612cf8565b60405160208183030381529060405293505050808061130b90613425565b9150506111d8565b816040516020016113249190612d9d565b60408051808303601f19018152919052979650505050505050565b6040805160e08101825260008082526020820181905260609282018390528282018390526080820183905260a082015260c081019190915281600081118015611389575060045481105b6113e15760405162461bcd60e51b815260206004820152602360248201527f417373657453746f72653a2061737365744964206973206f7574206f662072616044820152626e676560e81b60648201526084016104b1565b600083815260036020908152604091829020825160e081018452815463ffffffff80821683526401000000009091041692810192909252600181018054929391929184019161142f906133f0565b80601f016020809104026020016040519081016040528092919081815260200182805461145b906133f0565b80156114a85780601f1061147d576101008083540402835291602001916114a8565b820191906000526020600020905b81548152906001019060200180831161148b57829003601f168201915b505050505081526020016002820180546114c1906133f0565b80601f01602080910402602001604051908101604052809291908181526020018280546114ed906133f0565b801561153a5780601f1061150f5761010080835404028352916020019161153a565b820191906000526020600020905b81548152906001019060200180831161151d57829003601f168201915b50505050508152602001600382018054611553906133f0565b80601f016020809104026020016040519081016040528092919081815260200182805461157f906133f0565b80156115cc5780601f106115a1576101008083540402835291602001916115cc565b820191906000526020600020905b8154815290600101906020018083116115af57829003601f168201915b505050918352505060048201546001600160a01b0316602080830191909152600583018054604080518285028101850182528281529401939283018282801561163457602002820191906000526020600020905b815481526020019060010190808311611620575b505050505081525050915050919050565b606061165082612077565b6040516020016116609190612e70565b6040516020818303038152906040529050919050565b600182015460609063ffffffff908116908316106116fc5760405162461bcd60e51b815260206004820152603060248201527f537472696e675365742e6e616d654174496e6465783a2054686520696e64657860448201527f206973206f7574206f662072616e67650000000000000000000000000000000060648201526084016104b1565b63ffffffff82166000908152602084905260409020805461171c906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611748906133f0565b80156117955780601f1061176a57610100808354040283529160200191611795565b820191906000526020600020905b81548152906001019060200180831161177857829003601f168201915b5050505050905092915050565b60008083600201836040516117b79190612dde565b9081526040519081900360200190205463ffffffff16905080610e625760405162461bcd60e51b815260206004820152602c60248201527f537472696e675365743a2074686520737065636966696564206e616d6520646f60448201527f6573206e6f74206578697374000000000000000000000000000000000000000060648201526084016104b1565b60c0810151516000908290825b818110156119605760008360c00151828151811061186f5761186f6134a4565b6020908102919091018101516001549181015160405163c16e50ef60e01b81529193506001600160a01b039092169163c16e50ef916118b19190600401613068565b60206040518083038186803b1580156118c957600080fd5b505afa1580156118dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611901919061294f565b61194d5760405162461bcd60e51b815260206004820152601760248201527f496e76616c69642041737365744461746120436f6c6f7200000000000000000060448201526064016104b1565b508061195881613425565b91505061184f565b600154604080850151905163c16e50ef60e01b81526001600160a01b039092169163c16e50ef9161199391600401613068565b60206040518083038186803b1580156119ab57600080fd5b505afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e3919061294f565b611a2f5760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420417373657444617461204e616d650000000000000000000060448201526064016104b1565b6000611a3e86600001516121a9565b90506000611a558760000151838960200151612213565b60c08801515190915060008167ffffffffffffffff811115611a7957611a796134ba565b604051908082528060200260200182016040528015611aa2578160200160208202803683370190505b50905060005b82811015611b0557611ad68a60c001518281518110611ac957611ac96134a4565b602002602001015161229c565b828281518110611ae857611ae86134a4565b602090810291909101015280611afd81613425565b915050611aa8565b6004805460009182611b1683613425565b90915550600081815260036020908152604091829020918e015180519394509192611b4792600185019201906124db565b5060808c01516004820180546001600160a01b0319166001600160a01b0390921691909117905560608c0151518015611c0e576020811115611bf15760405162461bcd60e51b815260206004820152603460248201527f417373657453676f72653a205f726567697374657241737365742c206d696e7460448201527f6572206e616d6520697320746f6f206c6f6e672e00000000000000000000000060648201526084016104b1565b60608d01518051611c0c9160028501916020909101906124db565b505b60a08d01515115611c365760a08d01518051611c349160038501916020909101906124db565b505b815463ffffffff8881166401000000000267ffffffffffffffff19909216908a16171782558451611c70906005840190602088019061255f565b5063ffffffff8089166000908152600b60209081526040808320938b1683529290528190208e820151915190916002830191611cac9190612dde565b908152602001604051809103902054600014611d305760405162461bcd60e51b815260206004820152603b60248201527f417373657420616c72656164792065786973747320776974682074686520736160448201527f6d652067726f75702c2063617465676f727920616e64206e616d65000000000060648201526084016104b1565b6001810180548591839160009163ffffffff9091169082611d5083613440565b91906101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff1663ffffffff1681526020019081526020016000208190555083816002018f60400151604051611da39190612dde565b9081526040805160209281900383018120939093553383529082018690527ffd64e3f1068245597a589d8b057edbd3d3c312207d5c6d0d770825f68604ff1a910160405180910390a150919c9b505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080518082019091526060808252602082015281600081118015611e74575060065481105b611ec05760405162461bcd60e51b815260206004820152601660248201527f706172744964206973206f7574206f662072616e67650000000000000000000060448201526064016104b1565b600083815260056020526040908190208151808301909252805482908290611ee7906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611f13906133f0565b8015611f605780601f10611f3557610100808354040283529160200191611f60565b820191906000526020600020905b815481529060010190602001808311611f4357829003601f168201915b50505050508152602001600182018054611f79906133f0565b80601f0160208091040260200160405190810160405280929190818152602001828054611fa5906133f0565b80156116345780601f10611fc757610100808354040283529160200191611634565b820191906000526020600020905b815481529060010190602001808311611fd55750505091909252509195945050505050565b60606000612012600184600001516108cc919061339b565b90508061204960018560200151612029919061339b565b855163ffffffff9081166000908152600a60205260409020919061167616565b846040015160405160200161206093929190612dfa565b604051602081830303815290604052915050919050565b6060816120b757505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156120e157806120cb81613425565b91506120da9050600a83613370565b91506120bb565b60008167ffffffffffffffff8111156120fc576120fc6134ba565b6040519080825280601f01601f191660200182016040528015612126576020820181803683370190505b5090505b84156107a25761213b600183613384565b9150612148600a86613464565b612153906030613358565b60f81b818381518110612168576121686134a4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506121a2600a86613370565b945061212a565b600154600090819081906121ca9060079086906001600160a01b031661230b565b91509150801561220c577ff38f46310740c7f6f3e724364a429e671b125298f7a65e69fc18ff94a1e2d047846040516122039190613068565b60405180910390a15b5092915050565b63ffffffff8083166000908152600a60205260408120600154919290918391829161224e91859188916001600160a01b039091169061230b16565b915091508015612292577fcbc1b8c1fb300e15a9e99dc508aecdff1352f0fad4a5e4b7832d41e369635c03878660405161228992919061307b565b60405180910390a15b5095945050505050565b60008160056000600660008154809291906122b690613425565b9091555081526020808201929092526040016000208251805191926122e0928492909101906124db565b5060208281015180516122f992600185019201906124db565b5050600654610bdb9150600190613384565b600080600085600201856040516123229190612dde565b9081526040519081900360200190205463ffffffff169050801561234b579150600090506124d3565b60405163c16e50ef60e01b81526001600160a01b0385169063c16e50ef90612377908890600401613068565b60206040518083038186803b15801561238f57600080fd5b505afa1580156123a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c7919061294f565b6124135760405162461bcd60e51b815260206004820152601f60248201527f537472696e675365742e67657449643a20496e76616c696420537472696e670060448201526064016104b1565b6001860180548691889160009163ffffffff909116908261243383613440565b91906101000a81548163ffffffff021916908363ffffffff16021790555063ffffffff1663ffffffff168152602001908152602001600020908051906020019061247e9291906124db565b5050600185015460405163ffffffff90911690819060028801906124a3908890612dde565b908152604051908190036020019020805463ffffffff9290921663ffffffff199092169190911790559150600190505b935093915050565b8280546124e7906133f0565b90600052602060002090601f016020900481019282612509576000855561254f565b82601f1061252257805160ff191683800117855561254f565b8280016001018555821561254f579182015b8281111561254f578251825591602001919060010190612534565b5061255b929150612599565b5090565b82805482825590600052602060002090810192821561254f579160200282018281111561254f578251825591602001919060010190612534565b5b8082111561255b576000815560010161259a565b8035610bde816134d0565b600082601f8301126125ca57600080fd5b813560206125df6125da8361330c565b6132db565b80838252828201915082860187848660051b89010111156125ff57600080fd5b60005b8581101561269e57813567ffffffffffffffff8082111561262257600080fd5b908901906040828c03601f190181131561263b57600080fd5b61264361328f565b888401358381111561265457600080fd5b6126628e8b838801016126ab565b82525090830135908282111561267757600080fd5b6126858d8a848701016126ab565b818a015287525050509284019290840190600101612602565b5090979650505050505050565b600082601f8301126126bc57600080fd5b81356126ca6125da82613330565b8181528460208386010111156126df57600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561270e57600080fd5b6127166132b8565b9050813567ffffffffffffffff8082111561273057600080fd5b61273c858386016126ab565b8352602084013591508082111561275257600080fd5b61275e858386016126ab565b6020840152604084013591508082111561277757600080fd5b612783858386016126ab565b6040840152606084013591508082111561279c57600080fd5b6127a8858386016126ab565b60608401526127b9608085016125ae565b608084015260a08401359150808211156127d257600080fd5b6127de858386016126ab565b60a084015260c08401359150808211156127f757600080fd5b50612804848285016125b9565b60c08301525092915050565b803563ffffffff81168114610bde57600080fd5b60006020828403121561283657600080fd5b8135610e62816134d0565b6000806040838503121561285457600080fd5b823561285f816134d0565b9150602083013561286f816134e5565b809150509250929050565b6000602080838503121561288d57600080fd5b823567ffffffffffffffff808211156128a557600080fd5b818501915085601f8301126128b957600080fd5b81356128c76125da8261330c565b80828252858201915085850189878560051b88010111156128e757600080fd5b6000805b8581101561292257823587811115612901578283fd5b61290f8d8b838c01016126fc565b86525093880193918801916001016128eb565b50919a9950505050505050505050565b60006020828403121561294457600080fd5b8135610e62816134e5565b60006020828403121561296157600080fd5b8151610e62816134e5565b60006020828403121561297e57600080fd5b815167ffffffffffffffff81111561299557600080fd5b8201601f810184136129a657600080fd5b80516129b46125da82613330565b8181528560208385010111156129c957600080fd5b6129da8260208301602086016133c0565b95945050505050565b6000602082840312156129f557600080fd5b813567ffffffffffffffff811115612a0c57600080fd5b6107a2848285016126ab565b60008060408385031215612a2b57600080fd5b823567ffffffffffffffff80821115612a4357600080fd5b612a4f868387016126ab565b93506020850135915080821115612a6557600080fd5b50612a72858286016126ab565b9150509250929050565b600080600060608486031215612a9157600080fd5b833567ffffffffffffffff80821115612aa957600080fd5b612ab5878388016126ab565b94506020860135915080821115612acb57600080fd5b612ad7878388016126ab565b93506040860135915080821115612aed57600080fd5b50612afa868287016126ab565b9150509250925092565b600080600060608486031215612b1957600080fd5b833567ffffffffffffffff80821115612b3157600080fd5b612b3d878388016126ab565b94506020860135915080821115612b5357600080fd5b50612b60868287016126ab565b925050612b6f60408501612810565b90509250925092565b60008060408385031215612b8b57600080fd5b823567ffffffffffffffff811115612ba257600080fd5b612bae858286016126ab565b925050612bbd60208401612810565b90509250929050565b600060208284031215612bd857600080fd5b813567ffffffffffffffff811115612bef57600080fd5b6107a2848285016126fc565b600060208284031215612c0d57600080fd5b5035919050565b60008060408385031215612c2757600080fd5b82359150602083013561286f816134e5565b60008060408385031215612c4c57600080fd5b82359150602083013567ffffffffffffffff811115612c6a57600080fd5b612a72858286016126ab565b600060208284031215612c8857600080fd5b610e6282612810565b600081518084526020808501945080840160005b83811015612cc157815187529582019590820190600101612ca5565b509495945050505050565b60008151808452612ce48160208601602086016133c0565b601f01601f19169290920160200192915050565b60008451612d0a8184602089016133c0565b7f20203c7061746820643d220000000000000000000000000000000000000000009083019081528451612d4481600b8401602089016133c0565b601160f91b600b92909101918201528351612d6681600c8401602088016133c0565b7f202f3e0a00000000000000000000000000000000000000000000000000000000600c929091019182015260100195945050505050565b60008251612daf8184602087016133c0565b7f203c2f673e0a0000000000000000000000000000000000000000000000000000920191825250600601919050565b60008251612df08184602087016133c0565b9190910192915050565b60008451612e0c8184602089016133c0565b80830190507f2f000000000000000000000000000000000000000000000000000000000000008082528551612e48816001850160208a016133c0565b60019201918201528351612e638160028401602088016133c0565b0160020195945050505050565b7f6173736574000000000000000000000000000000000000000000000000000000815260008251612ea88160058501602087016133c0565b9190910160050192915050565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667223e60208201527f0a00000000000000000000000000000000000000000000000000000000000000604082015260008251612f398160418501602087016133c0565b7f3c2f7376673e00000000000000000000000000000000000000000000000000006041939091019283015250604701919050565b7f2066696c6c3d2200000000000000000000000000000000000000000000000000815260008251612fa58160078501602087016133c0565b601160f91b6007939091019283015250600801919050565b7f203c672069643d22000000000000000000000000000000000000000000000000815260008351612ff58160088501602088016133c0565b7f2220646573633d2200000000000000000000000000000000000000000000000060089184019182015283516130328160108401602088016133c0565b7f223e0a000000000000000000000000000000000000000000000000000000000060109290910191820152601301949350505050565b602081526000610e626020830184612ccc565b60408152600061308e6040830185612ccc565b82810360208401526129da8185612ccc565b60208152600082516101208060208501526130bf610140850183612ccc565b91506020850151601f19808685030160408701526130dd8483612ccc565b935060408701519150808685030160608701526130fa8483612ccc565b935060608701519150808685030160808701526131178483612ccc565b935060808701519150808685030160a08701526131348483612ccc565b935060a0870151915061315260c08701836001600160a01b03169052565b60c08701519150808685030160e08701525061316e8382612ccc565b92505060e08501516101006131888187018361ffff169052565b9095015161ffff1693019290925250919050565b6020815263ffffffff8251166020820152600060208301516131c6604084018263ffffffff169052565b50604083015160e060608401526131e1610100840182612ccc565b90506060840151601f19808584030160808601526131ff8383612ccc565b925060808601519150808584030160a086015261321c8383612ccc565b925060a0860151915061323a60c08601836001600160a01b03169052565b60c08601519150808584030160e0860152506129da8282612c91565b6020815260008251604060208401526132726060840182612ccc565b90506020840151601f198483030160408501526129da8282612ccc565b6040805190810167ffffffffffffffff811182821017156132b2576132b26134ba565b60405290565b60405160e0810167ffffffffffffffff811182821017156132b2576132b26134ba565b604051601f8201601f1916810167ffffffffffffffff81118282101715613304576133046134ba565b604052919050565b600067ffffffffffffffff821115613326576133266134ba565b5060051b60200190565b600067ffffffffffffffff82111561334a5761334a6134ba565b50601f01601f191660200190565b6000821982111561336b5761336b613478565b500190565b60008261337f5761337f61348e565b500490565b60008282101561339657613396613478565b500390565b600063ffffffff838116908316818110156133b8576133b8613478565b039392505050565b60005b838110156133db5781810151838201526020016133c3565b838111156133ea576000848401525b50505050565b600181811c9082168061340457607f821691505b60208210811415610d3d57634e487b7160e01b600052602260045260246000fd5b600060001982141561343957613439613478565b5060010190565b600063ffffffff8083168181141561345a5761345a613478565b6001019392505050565b6000826134735761347361348e565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461118f57600080fd5b801515811461118f57600080fdfea2646970667358221220be1ca473099cbe293ec88f3339943d2b6f257924bbba0b2a39631f475b628c7064736f6c63430008060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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