Goerli Testnet

Contract

0x7CE90c714Dbc48538Ec2838E5e6483155D506AAb

Overview

ETH Balance

Token Holdings

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Value
Save Post78683532022-10-31 22:38:00514 days ago1667255880IN
0x7CE90c71...55D506AAb
0 ETH0.000032891.00031256
Set Max Post Len...78523272022-10-29 0:21:36517 days ago1667002896IN
0x7CE90c71...55D506AAb
0 ETH0.000061932.0000009
Set Max Post Len...78438042022-10-27 14:19:12518 days ago1666880352IN
0x7CE90c71...55D506AAb
0 ETH0.0021299468.78323708
Set Max Post Len...78436502022-10-27 13:43:48518 days ago1666878228IN
0x7CE90c71...55D506AAb
0 ETH0.0027111787.55320464
Set Reply All Ad...78316912022-10-25 13:00:12520 days ago1666702812IN
0x7CE90c71...55D506AAb
0 ETH0.0012569225.97650284
Save Post78316252022-10-25 12:44:36520 days ago1666701876IN
0x7CE90c71...55D506AAb
0 ETH0.0060916832.99010758
0x60a0604077704702022-10-14 22:46:24531 days ago1665787584IN
 Create: SCPostStorage
0 ETH0.000002830.0018847

Latest 25 internal transactions (View All)

Advanced mode:
Parent Txn Hash Block From To Value
84054692023-01-30 21:19:12423 days ago1675113552
0x7CE90c71...55D506AAb
0 ETH
84054692023-01-30 21:19:12423 days ago1675113552
0x7CE90c71...55D506AAb
0 ETH
84054692023-01-30 21:19:12423 days ago1675113552
0x7CE90c71...55D506AAb
0 ETH
84054692023-01-30 21:19:12423 days ago1675113552
0x7CE90c71...55D506AAb
0 ETH
84054692023-01-30 21:19:12423 days ago1675113552
0x7CE90c71...55D506AAb
0 ETH
84054632023-01-30 21:18:00423 days ago1675113480
0x7CE90c71...55D506AAb
0 ETH
84054632023-01-30 21:18:00423 days ago1675113480
0x7CE90c71...55D506AAb
0 ETH
84054632023-01-30 21:18:00423 days ago1675113480
0x7CE90c71...55D506AAb
0 ETH
84054632023-01-30 21:18:00423 days ago1675113480
0x7CE90c71...55D506AAb
0 ETH
84054632023-01-30 21:18:00423 days ago1675113480
0x7CE90c71...55D506AAb
0 ETH
83867542023-01-27 17:17:12426 days ago1674839832
0x7CE90c71...55D506AAb
0 ETH
83867542023-01-27 17:17:12426 days ago1674839832
0x7CE90c71...55D506AAb
0 ETH
83867542023-01-27 17:17:12426 days ago1674839832
0x7CE90c71...55D506AAb
0 ETH
83867542023-01-27 17:17:12426 days ago1674839832
0x7CE90c71...55D506AAb
0 ETH
83867542023-01-27 17:17:12426 days ago1674839832
0x7CE90c71...55D506AAb
0 ETH
83864132023-01-27 15:55:36426 days ago1674834936
0x7CE90c71...55D506AAb
0 ETH
83864132023-01-27 15:55:36426 days ago1674834936
0x7CE90c71...55D506AAb
0 ETH
83864132023-01-27 15:55:36426 days ago1674834936
0x7CE90c71...55D506AAb
0 ETH
83864132023-01-27 15:55:36426 days ago1674834936
0x7CE90c71...55D506AAb
0 ETH
83864132023-01-27 15:55:36426 days ago1674834936
0x7CE90c71...55D506AAb
0 ETH
82992222023-01-12 14:58:36441 days ago1673535516
0x7CE90c71...55D506AAb
0 ETH
82992222023-01-12 14:58:36441 days ago1673535516
0x7CE90c71...55D506AAb
0 ETH
82992222023-01-12 14:58:36441 days ago1673535516
0x7CE90c71...55D506AAb
0 ETH
82992222023-01-12 14:58:36441 days ago1673535516
0x7CE90c71...55D506AAb
0 ETH
82992222023-01-12 14:58:36441 days ago1673535516
0x7CE90c71...55D506AAb
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SCPostStorage

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 14 : SCPostStorage.sol
//                                                                        ,-,
//                            *                      .                   /.(              .
//                                       \|/                             \ {
//    .                 _    .  ,   .    -*-       .                      `-`
//     ,'-.         *  / \_ *  / \_      /|\         *   /\'__        *.                 *
//    (____".         /    \  /    \,     __      .    _/  /  \  * .               .
//               .   /\/\  /\/ :' __ \_  /  \       _^/  ^/    `—./\    /\   .
//   *       _      /    \/  \  _/  \-‘\/  ` \ /\  /.' ^_   \_   .’\\  /_/\           ,'-.
//          /_\   /\  .-   `. \/     \ /.     /  \ ;.  _/ \ -. `_/   \/.   \   _     (____".    *
//     .   /   \ /  `-.__ ^   / .-'.--\      -    \/  _ `--./ .-'  `-/.     \ / \             .
//        /     /.       `.  / /       `.   /   `  .-'      '-._ `._         /.  \
// ~._,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'
// ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~
// ~~    ~~~~    ~~~~     ~~~~   ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~
//     ~~     ~~      ~~      ~~      ~~      ~~      ~~      ~~       ~~     ~~      ~~      ~~
//                          ๐
//                                                                              _
//                                                  ₒ                         ><_>
//                                  _______     __      _______
//          .-'                    |   _  "\   |" \    /" _   "|                               ๐
//     '--./ /     _.---.          (. |_)  :)  ||  |  (: ( \___)
//     '-,  (__..-`       \        |:     \/   |:  |   \/ \
//        \          .     |       (|  _  \\   |.  |   //  \ ___
//         `,.__.   ,__.--/        |: |_)  :)  |\  |   (:   _(  _|
//           '._/_.'___.-`         (_______/   |__\|    \_______)                 ๐
//
//                  __   __  ___   __    __         __       ___         _______
//                 |"  |/  \|  "| /" |  | "\       /""\     |"  |       /"     "|
//      ๐          |'  /    \:  |(:  (__)  :)     /    \    ||  |      (: ______)
//                 |: /'        | \/      \/     /' /\  \   |:  |   ₒ   \/    |
//                  \//  /\'    | //  __  \\    //  __'  \   \  |___    // ___)_
//                  /   /  \\   |(:  (  )  :)  /   /  \\  \ ( \_|:  \  (:      "|
//                 |___/    \___| \__|  |__/  (___/    \___) \_______)  \_______)
//                                                                                     ₒ৹
//                          ___             __       _______     ________
//         _               |"  |     ₒ     /""\     |   _  "\   /"       )
//       ><_>              ||  |          /    \    (. |_)  :) (:   \___/
//                         |:  |         /' /\  \   |:     \/   \___  \
//                          \  |___     //  __'  \  (|  _  \\    __/  \\          \_____)\_____
//                         ( \_|:  \   /   /  \\  \ |: |_)  :)  /" \   :)         /--v____ __`<
//                          \_______) (___/    \___)(_______/  (_______/                  )/
//                                                                                        '
//
//            ๐                          .    '    ,                                           ₒ
//                         ₒ               _______
//                                 ____  .`_|___|_`.  ____
//                                        \ \   / /                        ₒ৹
//                                          \ ' /                         ๐
//   ₒ                                        \/
//                                   ₒ     /      \       )                                 (
//           (   ₒ৹               (                      (                                  )
//            )                   )               _      )                )                (
//           (        )          (       (      ><_>    (       (        (                  )
//     )      )      (     (      )       )              )       )        )         )      (
//    (      (        )     )    (       (              (       (        (         (        )
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/interfaces/IERC721Metadata.sol";
import "@opengsn/contracts/src/ERC2771Recipient.sol";
import "@big-whale-labs/versioned-contract/contracts/Versioned.sol";
import "./models/Post.sol";
import "./interfaces/ILedger.sol";
import "./libraries/Strings.sol";

uint256 constant symbolSuffixLength = 2; // "-d" in the end of the derivative symbol

/**
 * @title SealCred Post storage
 * @dev Allows owners of derivatives to add posts
 */
contract SCPostStorage is Ownable, ERC2771Recipient, Versioned {
  using Counters for Counters.Counter;
  using strings for *;

  // State
  address public immutable ledgerAddress;
  Post[] public posts;
  uint256 public maxPostLength;
  uint256 public infixLength;
  Counters.Counter public currentPostId;
  address public replyAllAddress;

  // Events
  event PostSaved(
    uint256 id,
    string post,
    address indexed derivativeAddress,
    address indexed sender,
    uint256 timestamp,
    uint256 threadId,
    bytes32 replyToId
  );

  constructor(
    address _ledgerAddress,
    uint256 _maxPostLength,
    uint256 _infixLength,
    address _forwarder,
    string memory _version,
    address _replyAllAddress
  ) Versioned(_version) {
    ledgerAddress = _ledgerAddress;
    maxPostLength = _maxPostLength;
    infixLength = _infixLength;
    _setTrustedForwarder(_forwarder);
    version = _version;
    replyAllAddress = _replyAllAddress;
  }

  /**
   * @dev Modifies max post length
   */
  function setMaxPostLength(uint256 _maxPostLength) external onlyOwner {
    maxPostLength = _maxPostLength;
  }

  /**
   * @dev Modifies infix length
   */
  function setInfixLength(uint256 _infixLength) external onlyOwner {
    infixLength = _infixLength;
  }

  /**
   * @dev Modifies reply all address
   */
  function setReplyAllAddress(address _replyAllAddress) external onlyOwner {
    replyAllAddress = _replyAllAddress;
  }

  /**
   * @dev Returns posts
   */
  function getPosts(uint256 _skip, uint256 _limit)
    external
    view
    returns (Post[] memory)
  {
    if (_skip > posts.length) {
      return new Post[](0);
    }
    if (posts.length == 0) {
      return new Post[](0);
    }
    uint256 length = _skip + _limit > posts.length - 1
      ? posts.length - _skip
      : _limit;
    Post[] memory allPosts = new Post[](length);
    for (uint256 i = 0; i < length; i++) {
      Post storage post = posts[_skip + i];
      allPosts[i] = post;
    }
    return allPosts;
  }

  /**
   * @dev Returns thread
   */
  function getThread(uint256 _threadId) external view returns (Post[] memory) {
    uint256 postsLength = posts.length;
    Post[] memory _posts = new Post[](postsLength);
    for (uint256 i = 0; i < postsLength; ) {
      Post storage currentPost = posts[i];
      if (currentPost.threadId == _threadId) {
        _posts[i] = currentPost;
      }
      unchecked {
        ++i;
      }
    }

    return _posts;
  }

  /**
   * @dev Adds a post to the storage
   */
  function savePost(
    string memory post,
    string memory original,
    uint256 threadId,
    bytes32 replyToId
  ) external {
    // Get the derivative
    address derivativeAddress = ILedger(ledgerAddress).getDerivative(original);
    // Check preconditions
    require(derivativeAddress != address(0), "Derivative contract not found");
    require(
      IERC721(derivativeAddress).balanceOf(_msgSender()) > 0,
      "You do not own this derivative"
    );
    require(
      maxPostLength >=
        post.toSlice().len() +
          infixLength +
          bytes(IERC721Metadata(derivativeAddress).symbol()).length -
          symbolSuffixLength,
      "Post exceeds max post length"
    );
    require(threadId <= currentPostId.current(), "Thread not found");
    // Check abitily to post
    if (threadId > 0) {
      require(replyToId.length > 0, "replyToId must be provided with threadId");
      Post memory threadPost = posts[threadId - 1];
      require(
        threadPost.sender == _msgSender() ||
          threadPost.sender == replyAllAddress,
        "You can only reply to your own thread or to the thread of replyAllAddress"
      );
    }
    // Increment the current post id
    currentPostId.increment();
    // Post the post
    uint256 id = currentPostId.current();
    Post memory newPost = Post(
      id,
      post,
      derivativeAddress,
      _msgSender(),
      block.timestamp,
      threadId,
      replyToId
    );
    posts.push(newPost);
    // Emit the psot event
    emit PostSaved(
      id,
      post,
      derivativeAddress,
      _msgSender(),
      block.timestamp,
      threadId,
      replyToId
    );
  }

  function _msgSender()
    internal
    view
    override(Context, ERC2771Recipient)
    returns (address sender)
  {
    sender = ERC2771Recipient._msgSender();
  }

  function _msgData()
    internal
    view
    override(Context, ERC2771Recipient)
    returns (bytes calldata ret)
  {
    return ERC2771Recipient._msgData();
  }
}

File 2 of 14 : Post.sol
//                                                                        ,-,
//                            *                      .                   /.(              .
//                                       \|/                             \ {
//    .                 _    .  ,   .    -*-       .                      `-`
//     ,'-.         *  / \_ *  / \_      /|\         *   /\'__        *.                 *
//    (____".         /    \  /    \,     __      .    _/  /  \  * .               .
//               .   /\/\  /\/ :' __ \_  /  \       _^/  ^/    `—./\    /\   .
//   *       _      /    \/  \  _/  \-‘\/  ` \ /\  /.' ^_   \_   .’\\  /_/\           ,'-.
//          /_\   /\  .-   `. \/     \ /.     /  \ ;.  _/ \ -. `_/   \/.   \   _     (____".    *
//     .   /   \ /  `-.__ ^   / .-'.--\      -    \/  _ `--./ .-'  `-/.     \ / \             .
//        /     /.       `.  / /       `.   /   `  .-'      '-._ `._         /.  \
// ~._,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'
// ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~
// ~~    ~~~~    ~~~~     ~~~~   ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~
//     ~~     ~~      ~~      ~~      ~~      ~~      ~~      ~~       ~~     ~~      ~~      ~~
//                          ๐
//                                                                              _
//                                                  ₒ                         ><_>
//                                  _______     __      _______
//          .-'                    |   _  "\   |" \    /" _   "|                               ๐
//     '--./ /     _.---.          (. |_)  :)  ||  |  (: ( \___)
//     '-,  (__..-`       \        |:     \/   |:  |   \/ \
//        \          .     |       (|  _  \\   |.  |   //  \ ___
//         `,.__.   ,__.--/        |: |_)  :)  |\  |   (:   _(  _|
//           '._/_.'___.-`         (_______/   |__\|    \_______)                 ๐
//
//                  __   __  ___   __    __         __       ___         _______
//                 |"  |/  \|  "| /" |  | "\       /""\     |"  |       /"     "|
//      ๐          |'  /    \:  |(:  (__)  :)     /    \    ||  |      (: ______)
//                 |: /'        | \/      \/     /' /\  \   |:  |   ₒ   \/    |
//                  \//  /\'    | //  __  \\    //  __'  \   \  |___    // ___)_
//                  /   /  \\   |(:  (  )  :)  /   /  \\  \ ( \_|:  \  (:      "|
//                 |___/    \___| \__|  |__/  (___/    \___) \_______)  \_______)
//                                                                                     ₒ৹
//                          ___             __       _______     ________
//         _               |"  |     ₒ     /""\     |   _  "\   /"       )
//       ><_>              ||  |          /    \    (. |_)  :) (:   \___/
//                         |:  |         /' /\  \   |:     \/   \___  \
//                          \  |___     //  __'  \  (|  _  \\    __/  \\          \_____)\_____
//                         ( \_|:  \   /   /  \\  \ |: |_)  :)  /" \   :)         /--v____ __`<
//                          \_______) (___/    \___)(_______/  (_______/                  )/
//                                                                                        '
//
//            ๐                          .    '    ,                                           ₒ
//                         ₒ               _______
//                                 ____  .`_|___|_`.  ____
//                                        \ \   / /                        ₒ৹
//                                          \ ' /                         ๐
//   ₒ                                        \/
//                                   ₒ     /      \       )                                 (
//           (   ₒ৹               (                      (                                  )
//            )                   )               _      )                )                (
//           (        )          (       (      ><_>    (       (        (                  )
//     )      )      (     (      )       )              )       )        )         )      (
//    (      (        )     )    (       (              (       (        (         (        )
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

struct Post {
  uint256 id;
  string post;
  address derivativeAddress;
  address sender;
  uint256 timestamp;
  uint256 threadId; // must be another post's ID
  bytes32 replyToId; // external client post ID to reply to
}

File 3 of 14 : ILedger.sol
//                                                                        ,-,
//                            *                      .                   /.(              .
//                                       \|/                             \ {
//    .                 _    .  ,   .    -*-       .                      `-`
//     ,'-.         *  / \_ *  / \_      /|\         *   /\'__        *.                 *
//    (____".         /    \  /    \,     __      .    _/  /  \  * .               .
//               .   /\/\  /\/ :' __ \_  /  \       _^/  ^/    `—./\    /\   .
//   *       _      /    \/  \  _/  \-‘\/  ` \ /\  /.' ^_   \_   .’\\  /_/\           ,'-.
//          /_\   /\  .-   `. \/     \ /.     /  \ ;.  _/ \ -. `_/   \/.   \   _     (____".    *
//     .   /   \ /  `-.__ ^   / .-'.--\      -    \/  _ `--./ .-'  `-/.     \ / \             .
//        /     /.       `.  / /       `.   /   `  .-'      '-._ `._         /.  \
// ~._,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'
// ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~
// ~~    ~~~~    ~~~~     ~~~~   ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~
//     ~~     ~~      ~~      ~~      ~~      ~~      ~~      ~~       ~~     ~~      ~~      ~~
//                          ๐
//                                                                              _
//                                                  ₒ                         ><_>
//                                  _______     __      _______
//          .-'                    |   _  "\   |" \    /" _   "|                               ๐
//     '--./ /     _.---.          (. |_)  :)  ||  |  (: ( \___)
//     '-,  (__..-`       \        |:     \/   |:  |   \/ \
//        \          .     |       (|  _  \\   |.  |   //  \ ___
//         `,.__.   ,__.--/        |: |_)  :)  |\  |   (:   _(  _|
//           '._/_.'___.-`         (_______/   |__\|    \_______)                 ๐
//
//                  __   __  ___   __    __         __       ___         _______
//                 |"  |/  \|  "| /" |  | "\       /""\     |"  |       /"     "|
//      ๐          |'  /    \:  |(:  (__)  :)     /    \    ||  |      (: ______)
//                 |: /'        | \/      \/     /' /\  \   |:  |   ₒ   \/    |
//                  \//  /\'    | //  __  \\    //  __'  \   \  |___    // ___)_
//                  /   /  \\   |(:  (  )  :)  /   /  \\  \ ( \_|:  \  (:      "|
//                 |___/    \___| \__|  |__/  (___/    \___) \_______)  \_______)
//                                                                                     ₒ৹
//                          ___             __       _______     ________
//         _               |"  |     ₒ     /""\     |   _  "\   /"       )
//       ><_>              ||  |          /    \    (. |_)  :) (:   \___/
//                         |:  |         /' /\  \   |:     \/   \___  \
//                          \  |___     //  __'  \  (|  _  \\    __/  \\          \_____)\_____
//                         ( \_|:  \   /   /  \\  \ |: |_)  :)  /" \   :)         /--v____ __`<
//                          \_______) (___/    \___)(_______/  (_______/                  )/
//                                                                                        '
//
//            ๐                          .    '    ,                                           ₒ
//                         ₒ               _______
//                                 ____  .`_|___|_`.  ____
//                                        \ \   / /                        ₒ৹
//                                          \ ' /                         ๐
//   ₒ                                        \/
//                                   ₒ     /      \       )                                 (
//           (   ₒ৹               (                      (                                  )
//            )                   )               _      )                )                (
//           (        )          (       (      ><_>    (       (        (                  )
//     )      )      (     (      )       )              )       )        )         )      (
//    (      (        )     )    (       (              (       (        (         (        )
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface ILedger {
  function getDerivative(string memory original)
    external
    view
    returns (address);
}

File 4 of 14 : Strings.sol
// SPDX-License-Identifier: Apache-2.0
/*
 * @title String & slice utility library for Solidity contracts.
 * @author Nick Johnson <[email protected]>
 * @source https://github.com/Arachnid/solidity-stringutils
 *
 * @dev Functionality in this library is largely implemented using an
 *      abstraction called a 'slice'. A slice represents a part of a string -
 *      anything from the entire string to a single character, or even no
 *      characters at all (a 0-length slice). Since a slice only has to specify
 *      an offset and a length, copying and manipulating slices is a lot less
 *      expensive than copying and manipulating the strings they reference.
 *
 *      To further reduce gas costs, most functions on slice that need to return
 *      a slice modify the original one instead of allocating a new one; for
 *      instance, `s.split(".")` will return the text up to the first '.',
 *      modifying s to only contain the remainder of the string after the '.'.
 *      In situations where you do not want to modify the original slice, you
 *      can make a copy first with `.copy()`, for example:
 *      `s.copy().split(".")`. Try and avoid using this idiom in loops; since
 *      Solidity has no memory management, it will result in allocating many
 *      short-lived slices that are later discarded.
 *
 *      Functions that return two slices come in two versions: a non-allocating
 *      version that takes the second slice as an argument, modifying it in
 *      place, and an allocating version that allocates and returns the second
 *      slice; see `nextRune` for example.
 *
 *      Functions that have to copy string data will return strings rather than
 *      slices; these can be cast back to slices for further processing if
 *      required.
 *
 *      For convenience, some functions are provided with non-modifying
 *      variants that create a new slice and return both; for instance,
 *      `s.splitNew('.')` leaves s unmodified, and returns two values
 *      corresponding to the left and right parts of the string.
 */

pragma solidity ^0.8.17;

library strings {
  struct slice {
    uint256 _len;
    uint256 _ptr;
  }

  function memcpy(
    uint256 dest,
    uint256 src,
    uint256 _len
  ) private pure {
    // Copy word-length chunks while possible
    for (; _len >= 32; _len -= 32) {
      assembly {
        mstore(dest, mload(src))
      }
      dest += 32;
      src += 32;
    }

    // Copy remaining bytes
    uint256 mask = type(uint256).max;
    if (_len > 0) {
      mask = 256**(32 - _len) - 1;
    }
    assembly {
      let srcpart := and(mload(src), not(mask))
      let destpart := and(mload(dest), mask)
      mstore(dest, or(destpart, srcpart))
    }
  }

  /*
   * @dev Returns a slice containing the entire string.
   * @param self The string to make a slice from.
   * @return A newly allocated slice containing the entire string.
   */
  function toSlice(string memory self) internal pure returns (slice memory) {
    uint256 ptr;
    assembly {
      ptr := add(self, 0x20)
    }
    return slice(bytes(self).length, ptr);
  }

  /*
   * @dev Returns the length of a null-terminated bytes32 string.
   * @param self The value to find the length of.
   * @return The length of the string, from 0 to 32.
   */
  function len(bytes32 self) internal pure returns (uint256) {
    uint256 ret;
    if (self == 0) return 0;
    if (uint256(self) & type(uint128).max == 0) {
      ret += 16;
      self = bytes32(uint256(self) / 0x100000000000000000000000000000000);
    }
    if (uint256(self) & type(uint64).max == 0) {
      ret += 8;
      self = bytes32(uint256(self) / 0x10000000000000000);
    }
    if (uint256(self) & type(uint32).max == 0) {
      ret += 4;
      self = bytes32(uint256(self) / 0x100000000);
    }
    if (uint256(self) & type(uint16).max == 0) {
      ret += 2;
      self = bytes32(uint256(self) / 0x10000);
    }
    if (uint256(self) & type(uint8).max == 0) {
      ret += 1;
    }
    return 32 - ret;
  }

  /*
   * @dev Returns a slice containing the entire bytes32, interpreted as a
   *      null-terminated utf-8 string.
   * @param self The bytes32 value to convert to a slice.
   * @return A new slice containing the value of the input argument up to the
   *         first null.
   */
  function toSliceB32(bytes32 self) internal pure returns (slice memory ret) {
    // Allocate space for `self` in memory, copy it there, and point ret at it
    assembly {
      let ptr := mload(0x40)
      mstore(0x40, add(ptr, 0x20))
      mstore(ptr, self)
      mstore(add(ret, 0x20), ptr)
    }
    ret._len = len(self);
  }

  /*
   * @dev Returns a new slice containing the same data as the current slice.
   * @param self The slice to copy.
   * @return A new slice containing the same data as `self`.
   */
  function copy(slice memory self) internal pure returns (slice memory) {
    return slice(self._len, self._ptr);
  }

  /*
   * @dev Copies a slice to a new string.
   * @param self The slice to copy.
   * @return A newly allocated string containing the slice's text.
   */
  function toString(slice memory self) internal pure returns (string memory) {
    string memory ret = new string(self._len);
    uint256 retptr;
    assembly {
      retptr := add(ret, 32)
    }

    memcpy(retptr, self._ptr, self._len);
    return ret;
  }

  /*
   * @dev Returns the length in runes of the slice. Note that this operation
   *      takes time proportional to the length of the slice; avoid using it
   *      in loops, and call `slice.empty()` if you only need to know whether
   *      the slice is empty or not.
   * @param self The slice to operate on.
   * @return The length of the slice in runes.
   */
  function len(slice memory self) internal pure returns (uint256 l) {
    // Starting at ptr-31 means the LSB will be the byte we care about
    uint256 ptr = self._ptr - 31;
    uint256 end = ptr + self._len;
    for (l = 0; ptr < end; l++) {
      uint8 b;
      assembly {
        b := and(mload(ptr), 0xFF)
      }
      if (b < 0x80) {
        ptr += 1;
      } else if (b < 0xE0) {
        ptr += 2;
      } else if (b < 0xF0) {
        ptr += 3;
      } else if (b < 0xF8) {
        ptr += 4;
      } else if (b < 0xFC) {
        ptr += 5;
      } else {
        ptr += 6;
      }
    }
  }

  /*
   * @dev Returns true if the slice is empty (has a length of 0).
   * @param self The slice to operate on.
   * @return True if the slice is empty, False otherwise.
   */
  function empty(slice memory self) internal pure returns (bool) {
    return self._len == 0;
  }

  /*
   * @dev Returns a positive number if `other` comes lexicographically after
   *      `self`, a negative number if it comes before, or zero if the
   *      contents of the two slices are equal. Comparison is done per-rune,
   *      on unicode codepoints.
   * @param self The first slice to compare.
   * @param other The second slice to compare.
   * @return The result of the comparison.
   */
  function compare(slice memory self, slice memory other)
    internal
    pure
    returns (int256)
  {
    uint256 shortest = self._len;
    if (other._len < self._len) shortest = other._len;

    uint256 selfptr = self._ptr;
    uint256 otherptr = other._ptr;
    for (uint256 idx = 0; idx < shortest; idx += 32) {
      uint256 a;
      uint256 b;
      assembly {
        a := mload(selfptr)
        b := mload(otherptr)
      }
      if (a != b) {
        // Mask out irrelevant bytes and check again
        uint256 mask = type(uint256).max; // 0xffff...
        if (shortest < 32) {
          mask = ~(2**(8 * (32 - shortest + idx)) - 1);
        }
        unchecked {
          uint256 diff = (a & mask) - (b & mask);
          if (diff != 0) return int256(diff);
        }
      }
      selfptr += 32;
      otherptr += 32;
    }
    return int256(self._len) - int256(other._len);
  }

  /*
   * @dev Returns true if the two slices contain the same text.
   * @param self The first slice to compare.
   * @param self The second slice to compare.
   * @return True if the slices are equal, false otherwise.
   */
  function equals(slice memory self, slice memory other)
    internal
    pure
    returns (bool)
  {
    return compare(self, other) == 0;
  }

  /*
   * @dev Extracts the first rune in the slice into `rune`, advancing the
   *      slice to point to the next rune and returning `self`.
   * @param self The slice to operate on.
   * @param rune The slice that will contain the first rune.
   * @return `rune`.
   */
  function nextRune(slice memory self, slice memory rune)
    internal
    pure
    returns (slice memory)
  {
    rune._ptr = self._ptr;

    if (self._len == 0) {
      rune._len = 0;
      return rune;
    }

    uint256 l;
    uint256 b;
    // Load the first byte of the rune into the LSBs of b
    assembly {
      b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF)
    }
    if (b < 0x80) {
      l = 1;
    } else if (b < 0xE0) {
      l = 2;
    } else if (b < 0xF0) {
      l = 3;
    } else {
      l = 4;
    }

    // Check for truncated codepoints
    if (l > self._len) {
      rune._len = self._len;
      self._ptr += self._len;
      self._len = 0;
      return rune;
    }

    self._ptr += l;
    self._len -= l;
    rune._len = l;
    return rune;
  }

  /*
   * @dev Returns the first rune in the slice, advancing the slice to point
   *      to the next rune.
   * @param self The slice to operate on.
   * @return A slice containing only the first rune from `self`.
   */
  function nextRune(slice memory self)
    internal
    pure
    returns (slice memory ret)
  {
    nextRune(self, ret);
  }

  /*
   * @dev Returns the number of the first codepoint in the slice.
   * @param self The slice to operate on.
   * @return The number of the first codepoint in the slice.
   */
  function ord(slice memory self) internal pure returns (uint256 ret) {
    if (self._len == 0) {
      return 0;
    }

    uint256 word;
    uint256 length;
    uint256 divisor = 2**248;

    // Load the rune into the MSBs of b
    assembly {
      word := mload(mload(add(self, 32)))
    }
    uint256 b = word / divisor;
    if (b < 0x80) {
      ret = b;
      length = 1;
    } else if (b < 0xE0) {
      ret = b & 0x1F;
      length = 2;
    } else if (b < 0xF0) {
      ret = b & 0x0F;
      length = 3;
    } else {
      ret = b & 0x07;
      length = 4;
    }

    // Check for truncated codepoints
    if (length > self._len) {
      return 0;
    }

    for (uint256 i = 1; i < length; i++) {
      divisor = divisor / 256;
      b = (word / divisor) & 0xFF;
      if (b & 0xC0 != 0x80) {
        // Invalid UTF-8 sequence
        return 0;
      }
      ret = (ret * 64) | (b & 0x3F);
    }

    return ret;
  }

  /*
   * @dev Returns the keccak-256 hash of the slice.
   * @param self The slice to hash.
   * @return The hash of the slice.
   */
  function keccak(slice memory self) internal pure returns (bytes32 ret) {
    assembly {
      ret := keccak256(mload(add(self, 32)), mload(self))
    }
  }

  /*
   * @dev Returns true if `self` starts with `needle`.
   * @param self The slice to operate on.
   * @param needle The slice to search for.
   * @return True if the slice starts with the provided text, false otherwise.
   */
  function startsWith(slice memory self, slice memory needle)
    internal
    pure
    returns (bool)
  {
    if (self._len < needle._len) {
      return false;
    }

    if (self._ptr == needle._ptr) {
      return true;
    }

    bool equal;
    assembly {
      let length := mload(needle)
      let selfptr := mload(add(self, 0x20))
      let needleptr := mload(add(needle, 0x20))
      equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
    }
    return equal;
  }

  /*
   * @dev If `self` starts with `needle`, `needle` is removed from the
   *      beginning of `self`. Otherwise, `self` is unmodified.
   * @param self The slice to operate on.
   * @param needle The slice to search for.
   * @return `self`
   */
  function beyond(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory)
  {
    if (self._len < needle._len) {
      return self;
    }

    bool equal = true;
    if (self._ptr != needle._ptr) {
      assembly {
        let length := mload(needle)
        let selfptr := mload(add(self, 0x20))
        let needleptr := mload(add(needle, 0x20))
        equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
      }
    }

    if (equal) {
      self._len -= needle._len;
      self._ptr += needle._len;
    }

    return self;
  }

  /*
   * @dev Returns true if the slice ends with `needle`.
   * @param self The slice to operate on.
   * @param needle The slice to search for.
   * @return True if the slice starts with the provided text, false otherwise.
   */
  function endsWith(slice memory self, slice memory needle)
    internal
    pure
    returns (bool)
  {
    if (self._len < needle._len) {
      return false;
    }

    uint256 selfptr = self._ptr + self._len - needle._len;

    if (selfptr == needle._ptr) {
      return true;
    }

    bool equal;
    assembly {
      let length := mload(needle)
      let needleptr := mload(add(needle, 0x20))
      equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
    }

    return equal;
  }

  /*
   * @dev If `self` ends with `needle`, `needle` is removed from the
   *      end of `self`. Otherwise, `self` is unmodified.
   * @param self The slice to operate on.
   * @param needle The slice to search for.
   * @return `self`
   */
  function until(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory)
  {
    if (self._len < needle._len) {
      return self;
    }

    uint256 selfptr = self._ptr + self._len - needle._len;
    bool equal = true;
    if (selfptr != needle._ptr) {
      assembly {
        let length := mload(needle)
        let needleptr := mload(add(needle, 0x20))
        equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
      }
    }

    if (equal) {
      self._len -= needle._len;
    }

    return self;
  }

  // Returns the memory address of the first byte of the first occurrence of
  // `needle` in `self`, or the first byte after `self` if not found.
  function findPtr(
    uint256 selflen,
    uint256 selfptr,
    uint256 needlelen,
    uint256 needleptr
  ) private pure returns (uint256) {
    uint256 ptr = selfptr;
    uint256 idx;

    if (needlelen <= selflen) {
      if (needlelen <= 32) {
        bytes32 mask;
        if (needlelen > 0) {
          mask = bytes32(~(2**(8 * (32 - needlelen)) - 1));
        }

        bytes32 needledata;
        assembly {
          needledata := and(mload(needleptr), mask)
        }

        uint256 end = selfptr + selflen - needlelen;
        bytes32 ptrdata;
        assembly {
          ptrdata := and(mload(ptr), mask)
        }

        while (ptrdata != needledata) {
          if (ptr >= end) return selfptr + selflen;
          ptr++;
          assembly {
            ptrdata := and(mload(ptr), mask)
          }
        }
        return ptr;
      } else {
        // For long needles, use hashing
        bytes32 hash;
        assembly {
          hash := keccak256(needleptr, needlelen)
        }

        for (idx = 0; idx <= selflen - needlelen; idx++) {
          bytes32 testHash;
          assembly {
            testHash := keccak256(ptr, needlelen)
          }
          if (hash == testHash) return ptr;
          ptr += 1;
        }
      }
    }
    return selfptr + selflen;
  }

  // Returns the memory address of the first byte after the last occurrence of
  // `needle` in `self`, or the address of `self` if not found.
  function rfindPtr(
    uint256 selflen,
    uint256 selfptr,
    uint256 needlelen,
    uint256 needleptr
  ) private pure returns (uint256) {
    uint256 ptr;

    if (needlelen <= selflen) {
      if (needlelen <= 32) {
        bytes32 mask;
        if (needlelen > 0) {
          mask = bytes32(~(2**(8 * (32 - needlelen)) - 1));
        }

        bytes32 needledata;
        assembly {
          needledata := and(mload(needleptr), mask)
        }

        ptr = selfptr + selflen - needlelen;
        bytes32 ptrdata;
        assembly {
          ptrdata := and(mload(ptr), mask)
        }

        while (ptrdata != needledata) {
          if (ptr <= selfptr) return selfptr;
          ptr--;
          assembly {
            ptrdata := and(mload(ptr), mask)
          }
        }
        return ptr + needlelen;
      } else {
        // For long needles, use hashing
        bytes32 hash;
        assembly {
          hash := keccak256(needleptr, needlelen)
        }
        ptr = selfptr + (selflen - needlelen);
        while (ptr >= selfptr) {
          bytes32 testHash;
          assembly {
            testHash := keccak256(ptr, needlelen)
          }
          if (hash == testHash) return ptr + needlelen;
          ptr -= 1;
        }
      }
    }
    return selfptr;
  }

  /*
   * @dev Modifies `self` to contain everything from the first occurrence of
   *      `needle` to the end of the slice. `self` is set to the empty slice
   *      if `needle` is not found.
   * @param self The slice to search and modify.
   * @param needle The text to search for.
   * @return `self`.
   */
  function find(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory)
  {
    uint256 ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
    self._len -= ptr - self._ptr;
    self._ptr = ptr;
    return self;
  }

  /*
   * @dev Modifies `self` to contain the part of the string from the start of
   *      `self` to the end of the first occurrence of `needle`. If `needle`
   *      is not found, `self` is set to the empty slice.
   * @param self The slice to search and modify.
   * @param needle The text to search for.
   * @return `self`.
   */
  function rfind(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory)
  {
    uint256 ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
    self._len = ptr - self._ptr;
    return self;
  }

  /*
   * @dev Splits the slice, setting `self` to everything after the first
   *      occurrence of `needle`, and `token` to everything before it. If
   *      `needle` does not occur in `self`, `self` is set to the empty slice,
   *      and `token` is set to the entirety of `self`.
   * @param self The slice to split.
   * @param needle The text to search for in `self`.
   * @param token An output parameter to which the first token is written.
   * @return `token`.
   */
  function split(
    slice memory self,
    slice memory needle,
    slice memory token
  ) internal pure returns (slice memory) {
    uint256 ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
    token._ptr = self._ptr;
    token._len = ptr - self._ptr;
    if (ptr == self._ptr + self._len) {
      // Not found
      self._len = 0;
    } else {
      self._len -= token._len + needle._len;
      self._ptr = ptr + needle._len;
    }
    return token;
  }

  /*
   * @dev Splits the slice, setting `self` to everything after the first
   *      occurrence of `needle`, and returning everything before it. If
   *      `needle` does not occur in `self`, `self` is set to the empty slice,
   *      and the entirety of `self` is returned.
   * @param self The slice to split.
   * @param needle The text to search for in `self`.
   * @return The part of `self` up to the first occurrence of `delim`.
   */
  function split(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory token)
  {
    split(self, needle, token);
  }

  /*
   * @dev Splits the slice, setting `self` to everything before the last
   *      occurrence of `needle`, and `token` to everything after it. If
   *      `needle` does not occur in `self`, `self` is set to the empty slice,
   *      and `token` is set to the entirety of `self`.
   * @param self The slice to split.
   * @param needle The text to search for in `self`.
   * @param token An output parameter to which the first token is written.
   * @return `token`.
   */
  function rsplit(
    slice memory self,
    slice memory needle,
    slice memory token
  ) internal pure returns (slice memory) {
    uint256 ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
    token._ptr = ptr;
    token._len = self._len - (ptr - self._ptr);
    if (ptr == self._ptr) {
      // Not found
      self._len = 0;
    } else {
      self._len -= token._len + needle._len;
    }
    return token;
  }

  /*
   * @dev Splits the slice, setting `self` to everything before the last
   *      occurrence of `needle`, and returning everything after it. If
   *      `needle` does not occur in `self`, `self` is set to the empty slice,
   *      and the entirety of `self` is returned.
   * @param self The slice to split.
   * @param needle The text to search for in `self`.
   * @return The part of `self` after the last occurrence of `delim`.
   */
  function rsplit(slice memory self, slice memory needle)
    internal
    pure
    returns (slice memory token)
  {
    rsplit(self, needle, token);
  }

  /*
   * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
   * @param self The slice to search.
   * @param needle The text to search for in `self`.
   * @return The number of occurrences of `needle` found in `self`.
   */
  function count(slice memory self, slice memory needle)
    internal
    pure
    returns (uint256 cnt)
  {
    uint256 ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) +
      needle._len;
    while (ptr <= self._ptr + self._len) {
      cnt++;
      ptr =
        findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) +
        needle._len;
    }
  }

  /*
   * @dev Returns True if `self` contains `needle`.
   * @param self The slice to search.
   * @param needle The text to search for in `self`.
   * @return True if `needle` is found in `self`, false otherwise.
   */
  function contains(slice memory self, slice memory needle)
    internal
    pure
    returns (bool)
  {
    return
      rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
  }

  /*
   * @dev Returns a newly allocated string containing the concatenation of
   *      `self` and `other`.
   * @param self The first slice to concatenate.
   * @param other The second slice to concatenate.
   * @return The concatenation of the two strings.
   */
  function concat(slice memory self, slice memory other)
    internal
    pure
    returns (string memory)
  {
    string memory ret = new string(self._len + other._len);
    uint256 retptr;
    assembly {
      retptr := add(ret, 32)
    }
    memcpy(retptr, self._ptr, self._len);
    memcpy(retptr + self._len, other._ptr, other._len);
    return ret;
  }

  /*
   * @dev Joins an array of slices, using `self` as a delimiter, returning a
   *      newly allocated string.
   * @param self The delimiter to use.
   * @param parts A list of slices to join.
   * @return A newly allocated string containing all the slices in `parts`,
   *         joined with `self`.
   */
  function join(slice memory self, slice[] memory parts)
    internal
    pure
    returns (string memory)
  {
    if (parts.length == 0) return "";

    uint256 length = self._len * (parts.length - 1);
    for (uint256 i = 0; i < parts.length; i++) length += parts[i]._len;

    string memory ret = new string(length);
    uint256 retptr;
    assembly {
      retptr := add(ret, 32)
    }

    for (uint256 i = 0; i < parts.length; i++) {
      memcpy(retptr, parts[i]._ptr, parts[i]._len);
      retptr += parts[i]._len;
      if (i < parts.length - 1) {
        memcpy(retptr, self._ptr, self._len);
        retptr += self._len;
      }
    }

    return ret;
  }
}

File 5 of 14 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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 Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        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 6 of 14 : Counters.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

File 7 of 14 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../token/ERC721/extensions/IERC721Metadata.sol";

File 8 of 14 : ERC2771Recipient.sol
// SPDX-License-Identifier: MIT
// solhint-disable no-inline-assembly
pragma solidity >=0.6.9;

import "./interfaces/IERC2771Recipient.sol";

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Implementation
 *
 * @notice Note that this contract was called `BaseRelayRecipient` in the previous revision of the GSN.
 *
 * @notice A base contract to be inherited by any contract that want to receive relayed transactions.
 *
 * @notice A subclass must use `_msgSender()` instead of `msg.sender`.
 */
abstract contract ERC2771Recipient is IERC2771Recipient {

    /*
     * Forwarder singleton we accept calls from
     */
    address private _trustedForwarder;

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @notice Method is not a required method to allow Recipients to trust multiple Forwarders. Not recommended yet.
     * @return forwarder The address of the Forwarder contract that is being used.
     */
    function getTrustedForwarder() public virtual view returns (address forwarder){
        return _trustedForwarder;
    }

    function _setTrustedForwarder(address _forwarder) internal {
        _trustedForwarder = _forwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function isTrustedForwarder(address forwarder) public virtual override view returns(bool) {
        return forwarder == _trustedForwarder;
    }

    /// @inheritdoc IERC2771Recipient
    function _msgSender() internal override virtual view returns (address ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            ret = msg.sender;
        }
    }

    /// @inheritdoc IERC2771Recipient
    function _msgData() internal override virtual view returns (bytes calldata ret) {
        if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) {
            return msg.data[0:msg.data.length-20];
        } else {
            return msg.data;
        }
    }
}

File 9 of 14 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

File 10 of 14 : Versioned.sol
//                                                                        ,-,
//                            *                      .                   /.(              .
//                                       \|/                             \ {
//    .                 _    .  ,   .    -*-       .                      `-`
//     ,'-.         *  / \_ *  / \_      /|\         *   /\'__        *.                 *
//    (____".         /    \  /    \,     __      .    _/  /  \  * .               .
//               .   /\/\  /\/ :' __ \_  /  \       _^/  ^/    `—./\    /\   .
//   *       _      /    \/  \  _/  \-‘\/  ` \ /\  /.' ^_   \_   .’\\  /_/\           ,'-.
//          /_\   /\  .-   `. \/     \ /.     /  \ ;.  _/ \ -. `_/   \/.   \   _     (____".    *
//     .   /   \ /  `-.__ ^   / .-'.--\      -    \/  _ `--./ .-'  `-/.     \ / \             .
//        /     /.       `.  / /       `.   /   `  .-'      '-._ `._         /.  \
// ~._,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'2_,-'
// ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~
// ~~    ~~~~    ~~~~     ~~~~   ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~    ~~
//     ~~     ~~      ~~      ~~      ~~      ~~      ~~      ~~       ~~     ~~      ~~      ~~
//                          ๐
//                                                                              _
//                                                  ₒ                         ><_>
//                                  _______     __      _______
//          .-'                    |   _  "\   |" \    /" _   "|                               ๐
//     '--./ /     _.---.          (. |_)  :)  ||  |  (: ( \___)
//     '-,  (__..-`       \        |:     \/   |:  |   \/ \
//        \          .     |       (|  _  \\   |.  |   //  \ ___
//         `,.__.   ,__.--/        |: |_)  :)  |\  |   (:   _(  _|
//           '._/_.'___.-`         (_______/   |__\|    \_______)                 ๐
//
//                  __   __  ___   __    __         __       ___         _______
//                 |"  |/  \|  "| /" |  | "\       /""\     |"  |       /"     "|
//      ๐          |'  /    \:  |(:  (__)  :)     /    \    ||  |      (: ______)
//                 |: /'        | \/      \/     /' /\  \   |:  |   ₒ   \/    |
//                  \//  /\'    | //  __  \\    //  __'  \   \  |___    // ___)_
//                  /   /  \\   |(:  (  )  :)  /   /  \\  \ ( \_|:  \  (:      "|
//                 |___/    \___| \__|  |__/  (___/    \___) \_______)  \_______)
//                                                                                     ₒ৹
//                          ___             __       _______     ________
//         _               |"  |     ₒ     /""\     |   _  "\   /"       )
//       ><_>              ||  |          /    \    (. |_)  :) (:   \___/
//                         |:  |         /' /\  \   |:     \/   \___  \
//                          \  |___     //  __'  \  (|  _  \\    __/  \\          \_____)\_____
//                         ( \_|:  \   /   /  \\  \ |: |_)  :)  /" \   :)         /--v____ __`<
//                          \_______) (___/    \___)(_______/  (_______/                  )/
//                                                                                        '
//
//            ๐                          .    '    ,                                           ₒ
//                         ₒ               _______
//                                 ____  .`_|___|_`.  ____
//                                        \ \   / /                        ₒ৹
//                                          \ ' /                         ๐
//   ₒ                                        \/
//                                   ₒ     /      \       )                                 (
//           (   ₒ৹               (                      (                                  )
//            )                   )               _      )                )                (
//           (        )          (       (      ><_>    (       (        (                  )
//     )      )      (     (      )       )              )       )        )         )      (
//    (      (        )     )    (       (              (       (        (         (        )
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

contract Versioned {
  string public version;

  constructor(string memory _version) {
    version = _version;
  }
}

File 11 of 14 : 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 12 of 14 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

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

pragma solidity ^0.8.0;

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

File 14 of 14 : IERC2771Recipient.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

/**
 * @title The ERC-2771 Recipient Base Abstract Class - Declarations
 *
 * @notice A contract must implement this interface in order to support relayed transaction.
 *
 * @notice It is recommended that your contract inherits from the ERC2771Recipient contract.
 */
abstract contract IERC2771Recipient {

    /**
     * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder.
     * @param forwarder The address of the Forwarder contract that is being used.
     * @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient.
     */
    function isTrustedForwarder(address forwarder) public virtual view returns(bool);

    /**
     * @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions.
     * @return sender The real sender of this call.
     * For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`.
     * Otherwise simply returns `msg.sender`.
     */
    function _msgSender() internal virtual view returns (address);

    /**
     * @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.)
     * @return data The real `msg.data` of this call.
     * For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes
     * of the `msg.data` - so this method will strip those 20 bytes off.
     * Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`.
     */
    function _msgData() internal virtual view returns (bytes calldata);
}

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_ledgerAddress","type":"address"},{"internalType":"uint256","name":"_maxPostLength","type":"uint256"},{"internalType":"uint256","name":"_infixLength","type":"uint256"},{"internalType":"address","name":"_forwarder","type":"address"},{"internalType":"string","name":"_version","type":"string"},{"internalType":"address","name":"_replyAllAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"post","type":"string"},{"indexed":true,"internalType":"address","name":"derivativeAddress","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"threadId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"replyToId","type":"bytes32"}],"name":"PostSaved","type":"event"},{"inputs":[],"name":"currentPostId","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_skip","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getPosts","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"post","type":"string"},{"internalType":"address","name":"derivativeAddress","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"threadId","type":"uint256"},{"internalType":"bytes32","name":"replyToId","type":"bytes32"}],"internalType":"struct Post[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_threadId","type":"uint256"}],"name":"getThread","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"post","type":"string"},{"internalType":"address","name":"derivativeAddress","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"threadId","type":"uint256"},{"internalType":"bytes32","name":"replyToId","type":"bytes32"}],"internalType":"struct Post[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTrustedForwarder","outputs":[{"internalType":"address","name":"forwarder","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"infixLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ledgerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPostLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"posts","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"post","type":"string"},{"internalType":"address","name":"derivativeAddress","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"threadId","type":"uint256"},{"internalType":"bytes32","name":"replyToId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"replyAllAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"post","type":"string"},{"internalType":"string","name":"original","type":"string"},{"internalType":"uint256","name":"threadId","type":"uint256"},{"internalType":"bytes32","name":"replyToId","type":"bytes32"}],"name":"savePost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_infixLength","type":"uint256"}],"name":"setInfixLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPostLength","type":"uint256"}],"name":"setMaxPostLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_replyAllAddress","type":"address"}],"name":"setReplyAllAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b5060405162001c1738038062001c178339810160408190526200003491620001a7565b816200004962000043620000d2565b620000ee565b600262000057828262000355565b50506001600160a01b038616608052600485905560058490556200009783600180546001600160a01b0319166001600160a01b0392909216919091179055565b6002620000a5838262000355565b50600780546001600160a01b0319166001600160a01b039290921691909117905550620004219350505050565b6000620000e96200013e60201b62000fb91760201c565b905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000601436108015906200015c57506001546001600160a01b031633145b156200016f575060131936013560601c90565b503390565b80516001600160a01b03811681146200018c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060c08789031215620001c157600080fd5b620001cc8762000174565b9550602080880151955060408801519450620001eb6060890162000174565b60808901519094506001600160401b03808211156200020957600080fd5b818a0191508a601f8301126200021e57600080fd5b81518181111562000233576200023362000191565b604051601f8201601f19908116603f011681019083821181831017156200025e576200025e62000191565b816040528281528d868487010111156200027757600080fd5b600093505b828410156200029b57848401860151818501870152928501926200027c565b6000868483010152809750505050505050620002ba60a0880162000174565b90509295509295509295565b600181811c90821680620002db57607f821691505b602082108103620002fc57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200035057600081815260208120601f850160051c810160208610156200032b5750805b601f850160051c820191505b818110156200034c5782815560010162000337565b5050505b505050565b81516001600160401b0381111562000371576200037162000191565b6200038981620003828454620002c6565b8462000302565b602080601f831160018114620003c15760008415620003a85750858301515b600019600386901b1c1916600185901b1785556200034c565b600085815260208120601f198616915b82811015620003f257888601518255948401946001909101908401620003d1565b5085821015620004115787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516117d36200044460003960008181610263015261058201526117d36000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c806395ccd428116100a2578063d1d2005611610071578063d1d200561461025e578063d39b4c6b14610285578063e2e3ac5814610298578063f2fde38b146102a1578063fbe03180146102b457600080fd5b806395ccd42814610219578063ac4666851461022c578063cb81d41c14610243578063ce1b815f1461024d57600080fd5b80634ffd1be6116100e95780634ffd1be61461019257806354fd4d50146101a5578063572b6c05146101ba578063715018a6146101ec5780638da5cb5b146101f457600080fd5b80630b1e7f831461011b578063368f1e231461014a5780633848d7851461016a578063471ce09a1461017f575b600080fd5b61012e6101293660046111f0565b6102c7565b6040516101419796959493929190611259565b60405180910390f35b61015d6101583660046111f0565b6103ab565b60405161014191906112a8565b61017d6101783660046111f0565b61055b565b005b61017d61018d366004611424565b610568565b61015d6101a0366004611498565b610bf3565b6101ad610e67565b60405161014191906114ba565b6101dc6101c83660046114e9565b6001546001600160a01b0391821691161490565b6040519015158152602001610141565b61017d610ef5565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610141565b600754610201906001600160a01b031681565b61023560045481565b604051908152602001610141565b6006546102359081565b6001546001600160a01b0316610201565b6102017f000000000000000000000000000000000000000000000000000000000000000081565b61017d6102933660046114e9565b610f09565b61023560055481565b61017d6102af3660046114e9565b610f33565b61017d6102c23660046111f0565b610fac565b600381815481106102d757600080fd5b600091825260209091206007909102018054600182018054919350906102fc90611506565b80601f016020809104026020016040519081016040528092919081815260200182805461032890611506565b80156103755780601f1061034a57610100808354040283529160200191610375565b820191906000526020600020905b81548152906001019060200180831161035857829003601f168201915b505050600284015460038501546004860154600587015460069097015495966001600160a01b0393841696929093169450925087565b60035460609060008167ffffffffffffffff8111156103cc576103cc61135f565b60405190808252806020026020018201604052801561040557816020015b6103f261119e565b8152602001906001900390816103ea5790505b50905060005b828110156105535760006003828154811061042857610428611540565b906000526020600020906007020190508581600501540361054a57806040518060e00160405290816000820154815260200160018201805461046990611506565b80601f016020809104026020016040519081016040528092919081815260200182805461049590611506565b80156104e25780601f106104b7576101008083540402835291602001916104e2565b820191906000526020600020905b8154815290600101906020018083116104c557829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a090910152835184908490811061053e5761053e611540565b60200260200101819052505b5060010161040b565b509392505050565b610563610fed565b600455565b60405163c520cc7960e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c520cc79906105b79087906004016114ba565b602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190611556565b90506001600160a01b0381166106555760405162461bcd60e51b815260206004820152601d60248201527f4465726976617469766520636f6e7472616374206e6f7420666f756e6400000060448201526064015b60405180910390fd5b6000816001600160a01b03166370a0823161066e611066565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156106b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d69190611573565b116107235760405162461bcd60e51b815260206004820152601e60248201527f596f7520646f206e6f74206f776e207468697320646572697661746976650000604482015260640161064c565b6002816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610763573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261078b919081019061158c565b516005546040805180820182526000808252602091820152815180830190925289518252808a01908201526107bf90611075565b6107c99190611619565b6107d39190611619565b6107dd919061162c565b600454101561082e5760405162461bcd60e51b815260206004820152601c60248201527f506f73742065786365656473206d617820706f7374206c656e67746800000000604482015260640161064c565b6006548311156108735760405162461bcd60e51b815260206004820152601060248201526f151a1c995859081b9bdd08199bdd5b9960821b604482015260640161064c565b8215610a51576000600361088860018661162c565b8154811061089857610898611540565b90600052602060002090600702016040518060e0016040529081600082015481526020016001820180546108cb90611506565b80601f01602080910402602001604051908101604052809291908181526020018280546108f790611506565b80156109445780601f1061091957610100808354040283529160200191610944565b820191906000526020600020905b81548152906001019060200180831161092757829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a0909101529050610996611066565b6001600160a01b031681606001516001600160a01b031614806109cb575060075460608201516001600160a01b039081169116145b610a4f5760405162461bcd60e51b815260206004820152604960248201527f596f752063616e206f6e6c79207265706c7920746f20796f7572206f776e207460448201527f6872656164206f7220746f2074686520746872656164206f66207265706c79416064820152686c6c4164647265737360b81b608482015260a40161064c565b505b610a5f600680546001019055565b6000610a6a60065490565b905060006040518060e00160405280838152602001888152602001846001600160a01b03168152602001610a9c611066565b6001600160a01b031681524260208083019190915260408201889052606090910186905260038054600181018255600091909152825160079091027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810191825591830151929350839290917fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c0190610b35908261168e565b5060408201516002820180546001600160a01b039283166001600160a01b03199182161790915560608401516003840180549190931691161790556080820151600482015560a0820151600582015560c090910151600690910155610b98611066565b6001600160a01b0316836001600160a01b03167fe9d58122fca7f18c20167e40b5360f35f392cc7fe56725f0b0adaa8b531ee1a9848a428a8a604051610be295949392919061174e565b60405180910390a350505050505050565b600354606090831115610c39576040805160008082526020820190925290610c31565b610c1e61119e565b815260200190600190039081610c165790505b509050610e61565b600354600003610c7b576040805160008082526020820190925290610c31565b610c6161119e565b815260200190600190039081610c59579050509050610e61565b600354600090610c8d9060019061162c565b610c978486611619565b11610ca25782610cb0565b600354610cb090859061162c565b905060008167ffffffffffffffff811115610ccd57610ccd61135f565b604051908082528060200260200182016040528015610d0657816020015b610cf361119e565b815260200190600190039081610ceb5790505b50905060005b82811015610e5c5760006003610d228389611619565b81548110610d3257610d32611540565b90600052602060002090600702019050806040518060e001604052908160008201548152602001600182018054610d6890611506565b80601f0160208091040260200160405190810160405280929190818152602001828054610d9490611506565b8015610de15780601f10610db657610100808354040283529160200191610de1565b820191906000526020600020905b815481529060010190602001808311610dc457829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a0909101528351849084908110610e3d57610e3d611540565b6020026020010181905250508080610e5490611784565b915050610d0c565b509150505b92915050565b60028054610e7490611506565b80601f0160208091040260200160405190810160405280929190818152602001828054610ea090611506565b8015610eed5780601f10610ec257610100808354040283529160200191610eed565b820191906000526020600020905b815481529060010190602001808311610ed057829003601f168201915b505050505081565b610efd610fed565b610f07600061114e565b565b610f11610fed565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610f3b610fed565b6001600160a01b038116610fa05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161064c565b610fa98161114e565b50565b610fb4610fed565b600555565b600060143610801590610fd657506001546001600160a01b031633145b15610fe8575060131936013560601c90565b503390565b610ff5611066565b6001600160a01b03166110106000546001600160a01b031690565b6001600160a01b031614610f075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064c565b6000611070610fb9565b905090565b600080601f8360200151611089919061162c565b835190915060009061109b9083611619565b9050600092505b8082101561114757815160ff1660808110156110ca576110c3600184611619565b9250611134565b60e08160ff1610156110e1576110c3600284611619565b60f08160ff1610156110f8576110c3600384611619565b60f88160ff16101561110f576110c3600484611619565b60fc8160ff161015611126576110c3600584611619565b611131600684611619565b92505b508261113f81611784565b9350506110a2565b5050919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060e00160405280600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600080191681525090565b60006020828403121561120257600080fd5b5035919050565b60005b8381101561122457818101518382015260200161120c565b50506000910152565b60008151808452611245816020860160208601611209565b601f01601f19169290920160200192915050565b87815260e06020820152600061127260e083018961122d565b6001600160a01b039788166040840152959096166060820152608081019390935260a083019190915260c0909101529392505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561135157603f19898403018552815160e08151855288820151818a8701526112fd8287018261122d565b838a01516001600160a01b03908116888c0152606080860151909116908801526080808501519088015260a0808501519088015260c0938401519390960192909252505093860193908601906001016112cf565b509098975050505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561139e5761139e61135f565b604052919050565b600067ffffffffffffffff8211156113c0576113c061135f565b50601f01601f191660200190565b600082601f8301126113df57600080fd5b81356113f26113ed826113a6565b611375565b81815284602083860101111561140757600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561143a57600080fd5b843567ffffffffffffffff8082111561145257600080fd5b61145e888389016113ce565b9550602087013591508082111561147457600080fd5b50611481878288016113ce565b949794965050505060408301359260600135919050565b600080604083850312156114ab57600080fd5b50508035926020909101359150565b6020815260006114cd602083018461122d565b9392505050565b6001600160a01b0381168114610fa957600080fd5b6000602082840312156114fb57600080fd5b81356114cd816114d4565b600181811c9082168061151a57607f821691505b60208210810361153a57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561156857600080fd5b81516114cd816114d4565b60006020828403121561158557600080fd5b5051919050565b60006020828403121561159e57600080fd5b815167ffffffffffffffff8111156115b557600080fd5b8201601f810184136115c657600080fd5b80516115d46113ed826113a6565b8181528560208385010111156115e957600080fd5b6115fa826020830160208601611209565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e6157610e61611603565b81810381811115610e6157610e61611603565b601f82111561168957600081815260208120601f850160051c810160208610156116665750805b601f850160051c820191505b8181101561168557828155600101611672565b5050505b505050565b815167ffffffffffffffff8111156116a8576116a861135f565b6116bc816116b68454611506565b8461163f565b602080601f8311600181146116f157600084156116d95750858301515b600019600386901b1c1916600185901b178555611685565b600085815260208120601f198616915b8281101561172057888601518255948401946001909101908401611701565b508582101561173e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b85815260a06020820152600061176760a083018761122d565b604083019590955250606081019290925260809091015292915050565b60006001820161179657611796611603565b506001019056fea264697066735822122060c123eb7ec2c4621df5716a29ae30bdc4a957b5433f601488e7a9bb10176d0964736f6c6343000811003300000000000000000000000055ea2cdca3a2b63f88104c790705f26fb340f186000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000030000000000000000000000007a95fa73250dc53556d264522150a940d4c5023800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302e302e31352d32000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101165760003560e01c806395ccd428116100a2578063d1d2005611610071578063d1d200561461025e578063d39b4c6b14610285578063e2e3ac5814610298578063f2fde38b146102a1578063fbe03180146102b457600080fd5b806395ccd42814610219578063ac4666851461022c578063cb81d41c14610243578063ce1b815f1461024d57600080fd5b80634ffd1be6116100e95780634ffd1be61461019257806354fd4d50146101a5578063572b6c05146101ba578063715018a6146101ec5780638da5cb5b146101f457600080fd5b80630b1e7f831461011b578063368f1e231461014a5780633848d7851461016a578063471ce09a1461017f575b600080fd5b61012e6101293660046111f0565b6102c7565b6040516101419796959493929190611259565b60405180910390f35b61015d6101583660046111f0565b6103ab565b60405161014191906112a8565b61017d6101783660046111f0565b61055b565b005b61017d61018d366004611424565b610568565b61015d6101a0366004611498565b610bf3565b6101ad610e67565b60405161014191906114ba565b6101dc6101c83660046114e9565b6001546001600160a01b0391821691161490565b6040519015158152602001610141565b61017d610ef5565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610141565b600754610201906001600160a01b031681565b61023560045481565b604051908152602001610141565b6006546102359081565b6001546001600160a01b0316610201565b6102017f00000000000000000000000055ea2cdca3a2b63f88104c790705f26fb340f18681565b61017d6102933660046114e9565b610f09565b61023560055481565b61017d6102af3660046114e9565b610f33565b61017d6102c23660046111f0565b610fac565b600381815481106102d757600080fd5b600091825260209091206007909102018054600182018054919350906102fc90611506565b80601f016020809104026020016040519081016040528092919081815260200182805461032890611506565b80156103755780601f1061034a57610100808354040283529160200191610375565b820191906000526020600020905b81548152906001019060200180831161035857829003601f168201915b505050600284015460038501546004860154600587015460069097015495966001600160a01b0393841696929093169450925087565b60035460609060008167ffffffffffffffff8111156103cc576103cc61135f565b60405190808252806020026020018201604052801561040557816020015b6103f261119e565b8152602001906001900390816103ea5790505b50905060005b828110156105535760006003828154811061042857610428611540565b906000526020600020906007020190508581600501540361054a57806040518060e00160405290816000820154815260200160018201805461046990611506565b80601f016020809104026020016040519081016040528092919081815260200182805461049590611506565b80156104e25780601f106104b7576101008083540402835291602001916104e2565b820191906000526020600020905b8154815290600101906020018083116104c557829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a090910152835184908490811061053e5761053e611540565b60200260200101819052505b5060010161040b565b509392505050565b610563610fed565b600455565b60405163c520cc7960e01b81526000906001600160a01b037f00000000000000000000000055ea2cdca3a2b63f88104c790705f26fb340f186169063c520cc79906105b79087906004016114ba565b602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190611556565b90506001600160a01b0381166106555760405162461bcd60e51b815260206004820152601d60248201527f4465726976617469766520636f6e7472616374206e6f7420666f756e6400000060448201526064015b60405180910390fd5b6000816001600160a01b03166370a0823161066e611066565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156106b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d69190611573565b116107235760405162461bcd60e51b815260206004820152601e60248201527f596f7520646f206e6f74206f776e207468697320646572697661746976650000604482015260640161064c565b6002816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610763573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261078b919081019061158c565b516005546040805180820182526000808252602091820152815180830190925289518252808a01908201526107bf90611075565b6107c99190611619565b6107d39190611619565b6107dd919061162c565b600454101561082e5760405162461bcd60e51b815260206004820152601c60248201527f506f73742065786365656473206d617820706f7374206c656e67746800000000604482015260640161064c565b6006548311156108735760405162461bcd60e51b815260206004820152601060248201526f151a1c995859081b9bdd08199bdd5b9960821b604482015260640161064c565b8215610a51576000600361088860018661162c565b8154811061089857610898611540565b90600052602060002090600702016040518060e0016040529081600082015481526020016001820180546108cb90611506565b80601f01602080910402602001604051908101604052809291908181526020018280546108f790611506565b80156109445780601f1061091957610100808354040283529160200191610944565b820191906000526020600020905b81548152906001019060200180831161092757829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a0909101529050610996611066565b6001600160a01b031681606001516001600160a01b031614806109cb575060075460608201516001600160a01b039081169116145b610a4f5760405162461bcd60e51b815260206004820152604960248201527f596f752063616e206f6e6c79207265706c7920746f20796f7572206f776e207460448201527f6872656164206f7220746f2074686520746872656164206f66207265706c79416064820152686c6c4164647265737360b81b608482015260a40161064c565b505b610a5f600680546001019055565b6000610a6a60065490565b905060006040518060e00160405280838152602001888152602001846001600160a01b03168152602001610a9c611066565b6001600160a01b031681524260208083019190915260408201889052606090910186905260038054600181018255600091909152825160079091027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b810191825591830151929350839290917fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c0190610b35908261168e565b5060408201516002820180546001600160a01b039283166001600160a01b03199182161790915560608401516003840180549190931691161790556080820151600482015560a0820151600582015560c090910151600690910155610b98611066565b6001600160a01b0316836001600160a01b03167fe9d58122fca7f18c20167e40b5360f35f392cc7fe56725f0b0adaa8b531ee1a9848a428a8a604051610be295949392919061174e565b60405180910390a350505050505050565b600354606090831115610c39576040805160008082526020820190925290610c31565b610c1e61119e565b815260200190600190039081610c165790505b509050610e61565b600354600003610c7b576040805160008082526020820190925290610c31565b610c6161119e565b815260200190600190039081610c59579050509050610e61565b600354600090610c8d9060019061162c565b610c978486611619565b11610ca25782610cb0565b600354610cb090859061162c565b905060008167ffffffffffffffff811115610ccd57610ccd61135f565b604051908082528060200260200182016040528015610d0657816020015b610cf361119e565b815260200190600190039081610ceb5790505b50905060005b82811015610e5c5760006003610d228389611619565b81548110610d3257610d32611540565b90600052602060002090600702019050806040518060e001604052908160008201548152602001600182018054610d6890611506565b80601f0160208091040260200160405190810160405280929190818152602001828054610d9490611506565b8015610de15780601f10610db657610100808354040283529160200191610de1565b820191906000526020600020905b815481529060010190602001808311610dc457829003601f168201915b505050918352505060028201546001600160a01b0390811660208301526003830154166040820152600482015460608201526005820154608082015260069091015460a0909101528351849084908110610e3d57610e3d611540565b6020026020010181905250508080610e5490611784565b915050610d0c565b509150505b92915050565b60028054610e7490611506565b80601f0160208091040260200160405190810160405280929190818152602001828054610ea090611506565b8015610eed5780601f10610ec257610100808354040283529160200191610eed565b820191906000526020600020905b815481529060010190602001808311610ed057829003601f168201915b505050505081565b610efd610fed565b610f07600061114e565b565b610f11610fed565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610f3b610fed565b6001600160a01b038116610fa05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161064c565b610fa98161114e565b50565b610fb4610fed565b600555565b600060143610801590610fd657506001546001600160a01b031633145b15610fe8575060131936013560601c90565b503390565b610ff5611066565b6001600160a01b03166110106000546001600160a01b031690565b6001600160a01b031614610f075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161064c565b6000611070610fb9565b905090565b600080601f8360200151611089919061162c565b835190915060009061109b9083611619565b9050600092505b8082101561114757815160ff1660808110156110ca576110c3600184611619565b9250611134565b60e08160ff1610156110e1576110c3600284611619565b60f08160ff1610156110f8576110c3600384611619565b60f88160ff16101561110f576110c3600484611619565b60fc8160ff161015611126576110c3600584611619565b611131600684611619565b92505b508261113f81611784565b9350506110a2565b5050919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040518060e00160405280600081526020016060815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600080191681525090565b60006020828403121561120257600080fd5b5035919050565b60005b8381101561122457818101518382015260200161120c565b50506000910152565b60008151808452611245816020860160208601611209565b601f01601f19169290920160200192915050565b87815260e06020820152600061127260e083018961122d565b6001600160a01b039788166040840152959096166060820152608081019390935260a083019190915260c0909101529392505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561135157603f19898403018552815160e08151855288820151818a8701526112fd8287018261122d565b838a01516001600160a01b03908116888c0152606080860151909116908801526080808501519088015260a0808501519088015260c0938401519390960192909252505093860193908601906001016112cf565b509098975050505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561139e5761139e61135f565b604052919050565b600067ffffffffffffffff8211156113c0576113c061135f565b50601f01601f191660200190565b600082601f8301126113df57600080fd5b81356113f26113ed826113a6565b611375565b81815284602083860101111561140757600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561143a57600080fd5b843567ffffffffffffffff8082111561145257600080fd5b61145e888389016113ce565b9550602087013591508082111561147457600080fd5b50611481878288016113ce565b949794965050505060408301359260600135919050565b600080604083850312156114ab57600080fd5b50508035926020909101359150565b6020815260006114cd602083018461122d565b9392505050565b6001600160a01b0381168114610fa957600080fd5b6000602082840312156114fb57600080fd5b81356114cd816114d4565b600181811c9082168061151a57607f821691505b60208210810361153a57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561156857600080fd5b81516114cd816114d4565b60006020828403121561158557600080fd5b5051919050565b60006020828403121561159e57600080fd5b815167ffffffffffffffff8111156115b557600080fd5b8201601f810184136115c657600080fd5b80516115d46113ed826113a6565b8181528560208385010111156115e957600080fd5b6115fa826020830160208601611209565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e6157610e61611603565b81810381811115610e6157610e61611603565b601f82111561168957600081815260208120601f850160051c810160208610156116665750805b601f850160051c820191505b8181101561168557828155600101611672565b5050505b505050565b815167ffffffffffffffff8111156116a8576116a861135f565b6116bc816116b68454611506565b8461163f565b602080601f8311600181146116f157600084156116d95750858301515b600019600386901b1c1916600185901b178555611685565b600085815260208120601f198616915b8281101561172057888601518255948401946001909101908401611701565b508582101561173e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b85815260a06020820152600061176760a083018761122d565b604083019590955250606081019290925260809091015292915050565b60006001820161179657611796611603565b506001019056fea264697066735822122060c123eb7ec2c4621df5716a29ae30bdc4a957b5433f601488e7a9bb10176d0964736f6c63430008110033

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

00000000000000000000000055ea2cdca3a2b63f88104c790705f26fb340f186000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000030000000000000000000000007a95fa73250dc53556d264522150a940d4c5023800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302e302e31352d32000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _ledgerAddress (address): 0x55EA2cdCA3a2B63F88104C790705f26Fb340f186
Arg [1] : _maxPostLength (uint256): 291
Arg [2] : _infixLength (uint256): 3
Arg [3] : _forwarder (address): 0x7A95fA73250dc53556d264522150A940d4C50238
Arg [4] : _version (string): 0.0.15-2
Arg [5] : _replyAllAddress (address): 0x0000000000000000000000000000000000000000

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000055ea2cdca3a2b63f88104c790705f26fb340f186
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000123
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [3] : 0000000000000000000000007a95fa73250dc53556d264522150a940d4c50238
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [7] : 302e302e31352d32000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.