xDAI Price: $0.999233 (-0.02%)

Contract

0x47a55e897a271A6Acbf4f226DC629084546eeff4

Overview

XDAI Balance

Gnosis Chain LogoGnosis Chain LogoGnosis Chain Logo0 XDAI

XDAI Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
328091162024-03-07 11:04:20688 days ago1709809460
0x47a55e89...4546eeff4
0 XDAI
328091162024-03-07 11:04:20688 days ago1709809460
0x47a55e89...4546eeff4
0 XDAI
328091162024-03-07 11:04:20688 days ago1709809460
0x47a55e89...4546eeff4
0 XDAI
328091162024-03-07 11:04:20688 days ago1709809460
0x47a55e89...4546eeff4
0 XDAI
328090702024-03-07 11:00:30688 days ago1709809230
0x47a55e89...4546eeff4
0 XDAI
328090702024-03-07 11:00:30688 days ago1709809230
0x47a55e89...4546eeff4
0 XDAI
328090702024-03-07 11:00:30688 days ago1709809230
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090632024-03-07 10:59:55688 days ago1709809195
0x47a55e89...4546eeff4
0 XDAI
328090512024-03-07 10:58:55688 days ago1709809135
0x47a55e89...4546eeff4
0 XDAI
328090512024-03-07 10:58:55688 days ago1709809135
0x47a55e89...4546eeff4
0 XDAI
328090512024-03-07 10:58:55688 days ago1709809135
0x47a55e89...4546eeff4
0 XDAI
328090432024-03-07 10:58:15688 days ago1709809095
0x47a55e89...4546eeff4
0 XDAI
328090432024-03-07 10:58:15688 days ago1709809095
0x47a55e89...4546eeff4
0 XDAI
328090432024-03-07 10:58:15688 days ago1709809095
0x47a55e89...4546eeff4
0 XDAI
328090432024-03-07 10:58:15688 days ago1709809095
0x47a55e89...4546eeff4
0 XDAI
328090282024-03-07 10:56:55688 days ago1709809015
0x47a55e89...4546eeff4
0 XDAI
328090282024-03-07 10:56:55688 days ago1709809015
0x47a55e89...4546eeff4
0 XDAI
328090282024-03-07 10:56:55688 days ago1709809015
0x47a55e89...4546eeff4
0 XDAI
328090282024-03-07 10:56:55688 days ago1709809015
0x47a55e89...4546eeff4
0 XDAI
328090282024-03-07 10:56:55688 days ago1709809015
0x47a55e89...4546eeff4
0 XDAI
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SmartController

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, Apache-2.0 license

Contract Source Code (Solidity Multiple files format)

File 1 of 34: SmartController.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./SmartTokenLib.sol";
import "./MintableController.sol";
import "./IValidator.sol";

/**
 * @title SmartController
 * @dev This contract adds "smart" functionality which is required from a regulatory perspective.
 */
contract SmartController is MintableController {
    using SmartTokenLib for SmartTokenLib.SmartStorage;

    SmartTokenLib.SmartStorage internal smartToken;

    bytes3 public ticker;
    uint256 public constant INITIAL_SUPPLY = 0;

    /**
     * @dev Contract constructor.
     * @param storage_ Address of the token storage for the controller.
     * @param validator Address of validator.
     * @param ticker_ 3 letter currency ticker.
     * @param frontend_ Address of the authorized frontend.
     */
    constructor(
        address storage_,
        address validator,
        bytes3 ticker_,
        address frontend_
    ) MintableController(storage_, INITIAL_SUPPLY, frontend_) {
        require(
            validator != address(0x0),
            "validator cannot be the null address"
        );
        smartToken.setValidator(validator);
        ticker = ticker_;
    }

    /**
     * @dev Sets a new validator.
     * @param validator Address of validator.
     */
    function setValidator(address validator) external onlyOwner {
        smartToken.setValidator(validator);
    }

    /**
     * @dev Recovers tokens from an address and reissues them to another address.
     * In case a user loses its private key the tokens can be recovered by burning
     * the tokens from that address and reissuing to a new address.
     * To recover tokens the contract owner needs to provide a signature
     * proving that the token owner has authorized the owner to do so.
     * @param caller Address of the caller passed through the frontend.
     * @param from Address to burn tokens from.
     * @param to Address to mint tokens to.
     * @param h Hash which the token owner signed.
     * @param v Signature component.
     * @param r Signature component.
     * @param s Sigature component.
     * @return Amount recovered.
     */
    function recover_withCaller(
        address caller,
        address from,
        address to,
        bytes32 h,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external onlyFrontend onlySystemAccount(caller) returns (uint) {
        _avoidBlackholes(to);
        return SmartTokenLib.recover(token, from, to, h, v, r, s);
    }

    /**
     * @dev Transfers tokens [ERC20].
     * The caller, to address and amount are validated before executing method.
     * Prior to transfering tokens the validator needs to approve.
     * @notice Overrides method in a parent.
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transfer_withCaller(
        address caller,
        address to,
        uint256 amount
    ) public override returns (bool) {
        require(
            smartToken.validate(caller, to, amount),
            "transfer request not valid"
        );
        return super.transfer_withCaller(caller, to, amount);
    }

    /**
     * @dev Transfers tokens from a specific address [ERC20].
     * The address owner has to approve the spender beforehand.
     * The from address, to address and amount are validated before executing method.
     * @notice Overrides method in a parent.
     * Prior to transfering tokens the validator needs to approve.
     * @param caller Address of the caller passed through the frontend.
     * @param from Address to debet the tokens from.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transferFrom_withCaller(
        address caller,
        address from,
        address to,
        uint256 amount
    ) public override returns (bool) {
        require(
            smartToken.validate(from, to, amount),
            "transferFrom request not valid"
        );
        return super.transferFrom_withCaller(caller, from, to, amount);
    }

    /**
     * @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
     * If the recipient is a non-contract address this method behaves just like transfer.
     * The caller, to address and amount are validated before executing method.
     * @notice Overrides method in a parent.
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     * @param data Additional data passed to the recipient's tokenFallback method.
     */
    function transferAndCall_withCaller(
        address caller,
        address to,
        uint256 amount,
        bytes calldata data
    ) public override returns (bool) {
        require(
            smartToken.validate(caller, to, amount),
            "transferAndCall request not valid"
        );
        return super.transferAndCall_withCaller(caller, to, amount, data);
    }

    /**
     * @dev Gets the current validator.
     * @return Address of validator.
     */
    function getValidator() external view returns (address) {
        return smartToken.getValidator();
    }
}

File 2 of 34: AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "./Context.sol";
import "./Strings.sol";
import "./ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 3 of 34: Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 4 of 34: CanReclaimToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./Ownable.sol";
import "./ERC20Basic.sol";
import "./SafeERC20.sol";

/**
 * @title Contracts that should be able to recover tokens
 * @author SylTi
 * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
 * This will prevent any accidental loss of tokens.
 */
contract CanReclaimToken is Ownable {
    using SafeERC20 for ERC20Basic;

    /**
     * @dev Reclaim all ERC20Basic compatible tokens
     * @param _token ERC20Basic The address of the token contract
     */
    function reclaimToken(ERC20Basic _token) external onlyOwner {
        uint256 balance = _token.balanceOf(address(this));
        _token.safeTransfer(owner, balance);
    }
}

File 5 of 34: Claimable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./Ownable.sol";

/**
 * @title Claimable
 * @dev Extension for the Ownable contract, where the ownership needs to be claimed.
 * This allows the new owner to accept the transfer.
 */
abstract contract Claimable is Ownable {
    address public pendingOwner;

    /**
     * @dev emitted when the pendingOwner address is changed
     * @param previousPendingOwner previous pendingOwner address
     * @param newPendingOwner new pendingOwner address
     */
    event OwnershipTransferPending(
        address indexed previousPendingOwner,
        address indexed newPendingOwner
    );

    /**
     * @dev Modifier throws if called by any account other than the pendingOwner.
     */
    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner);
        _;
    }

    /**
     * @dev Allows the current owner to set the pendingOwner address.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(
        address newOwner
    ) public virtual override onlyOwner {
        emit OwnershipTransferPending(pendingOwner, newOwner);
        pendingOwner = newOwner;
    }

    /**
     * @dev Allows the pendingOwner address to finalize the transfer.
     */
    function claimOwnership() public onlyPendingOwner {
        emit OwnershipTransferred(owner, pendingOwner);
        owner = pendingOwner;
        pendingOwner = address(0);
    }
}

File 6 of 34: ClaimableSystemRole.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./SystemRole.sol";

/**
 * @title ClaimableSystemRole
 * @dev Extension for the SystemRole contract, where the ownership needs to be claimed.
 * This allows the new owner to accept the transfer.
 */
abstract contract ClaimableSystemRole is SystemRole {
    address public pendingOwner;

    /**
     * @dev emitted when the pendingOwner address is changed
     * @param previousPendingOwner previous pendingOwner address
     * @param newPendingOwner new pendingOwner address
     */
    event OwnershipTransferPending(
        address indexed previousPendingOwner,
        address indexed newPendingOwner
    );

    /**
     * @dev Modifier throws if called by any account other than the pendingOwner.
     */
    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner);
        _;
    }

    /**
     * @dev Allows the current owner to set the pendingOwner address.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(
        address newOwner
    ) public virtual override onlyOwner {
        emit OwnershipTransferPending(pendingOwner, newOwner);
        pendingOwner = newOwner;
    }

    /**
     * @dev Allows the pendingOwner address to finalize the transfer.
     */
    function claimOwnership() public onlyPendingOwner {
        emit OwnershipTransferred(owner, pendingOwner);
        owner = pendingOwner;
        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        pendingOwner = address(0);
    }
}

File 7 of 34: 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 8 of 34: ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "./Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 9 of 34: ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 10 of 34: ERC20Basic.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * See https://github.com/ethereum/EIPs/issues/179
 */
abstract contract ERC20Basic {
    function totalSupply() public view virtual returns (uint256);

    function balanceOf(address _who) public view virtual returns (uint256);

    function transfer(
        address _to,
        uint256 _value
    ) public virtual returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
}

File 11 of 34: ERC20Lib.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./TokenStorage.sol";

/**
 * @title ERC20Lib
 * @dev Standard ERC20 token functionality.
 * https://github.com/ethereum/EIPs/issues/20
 */
library ERC20Lib {
    /**
     * @dev Transfers tokens [ERC20].
     * @param db Token storage to operate on.
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transfer(
        TokenStorage db,
        address caller,
        address to,
        uint256 amount
    ) external returns (bool success) {
        db.subBalance(caller, amount);
        db.addBalance(to, amount);
        return true;
    }

    /**
     * @dev Transfers tokens from a specific address [ERC20].
     * The address owner has to approve the spender beforehand.
     * @param db Token storage to operate on.
     * @param caller Address of the caller passed through the frontend.
     * @param from Address to debet the tokens from.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transferFrom(
        TokenStorage db,
        address caller,
        address from,
        address to,
        uint256 amount
    ) external returns (bool success) {
        uint256 allowance_ = db.getAllowed(from, caller);
        db.subBalance(from, amount);
        db.addBalance(to, amount);
        db.setAllowed(from, caller, allowance_ - amount);
        return true;
    }

    /**
     * @dev Approves a spender [ERC20].
     * Note that using the approve/transferFrom presents a possible
     * security vulnerability described in:
     * https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.quou09mcbpzw
     * Use transferAndCall to mitigate.
     * @param db Token storage to operate on.
     * @param caller Address of the caller passed through the frontend.
     * @param spender The address of the future spender.
     * @param amount The allowance of the spender.
     */
    function approve(
        TokenStorage db,
        address caller,
        address spender,
        uint256 amount
    ) public returns (bool success) {
        db.setAllowed(caller, spender, amount);
        return true;
    }

    /**
     * @dev Returns the number tokens associated with an address.
     * @param db Token storage to operate on.
     * @param who Address to lookup.
     * @return balance Balance of address.
     */
    function balanceOf(
        TokenStorage db,
        address who
    ) external view returns (uint256 balance) {
        return db.getBalance(who);
    }

    /**
     * @dev Returns the allowance for a spender
     * @param db Token storage to operate on.
     * @param owner The address of the owner of the tokens.
     * @param spender The address of the spender.
     * @return remaining Number of tokens the spender is allowed to spend.
     */
    function allowance(
        TokenStorage db,
        address owner,
        address spender
    ) external view returns (uint256 remaining) {
        return db.getAllowed(owner, spender);
    }
}

File 12 of 34: ERC677Lib.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./Address.sol";
import "./IERC677Recipient.sol";
import "./TokenStorage.sol";
import "./ERC20Lib.sol";

/**
 * @title ERC677
 * @dev ERC677 token functionality.
 * https://github.com/ethereum/EIPs/issues/677
 */
library ERC677Lib {
    using ERC20Lib for TokenStorage;
    using Address for address;

    /**
     * @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
     * If the recipient is a non-contract address this method behaves just like transfer.
     * @notice db.transfer either returns true or reverts.
     * @param db Token storage to operate on.
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     * @param data Additional data passed to the recipient's tokenFallback method.
     */
    function transferAndCall(
        TokenStorage db,
        address caller,
        address to,
        uint256 amount,
        bytes calldata data
    ) external returns (bool) {
        require(db.transfer(caller, to, amount), "unable to transfer");
        if (to.isContract()) {
            IERC677Recipient recipient = IERC677Recipient(to);
            require(
                recipient.onTokenTransfer(caller, amount, data),
                "token handler returns false"
            );
        }
        return true;
    }
}

File 13 of 34: HasNoContracts.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./Ownable.sol";

/**
 * @title Contracts that should not own Contracts
 * @author Remco Bloemen <remco@2π.com>
 * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
 * of this contract to reclaim ownership of the contracts.
 */
contract HasNoContracts is Ownable {
    /**
     * @dev Reclaim ownership of Ownable contracts
     * @param _contractAddr The address of the Ownable to be reclaimed.
     */
    function reclaimContract(address _contractAddr) external onlyOwner {
        Ownable contractInst = Ownable(_contractAddr);
        contractInst.transferOwnership(owner);
    }
}

File 14 of 34: HasNoEther.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./Ownable.sol";

/**
 * @title Contracts that should not own Ether
 * @author Remco Bloemen <remco@2π.com>
 * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
 * in the contract, it will allow the owner to reclaim this Ether.
 * @notice Ether can still be sent to this contract by:
 * calling functions labeled `payable`
 * `selfdestruct(contract_address)`
 * mining directly to the contract address
 */
contract HasNoEther is Ownable {
    /**
     * @dev Constructor that rejects incoming Ether
     * The `payable` flag is added so we can access `msg.value` without compiler warning. If we
     * leave out payable, then Solidity will allow inheriting contracts to implement a payable
     * constructor. By doing it this way we prevent a payable constructor from working. Alternatively
     * we could use assembly to access msg.value.
     */
    constructor() payable {
        require(msg.value == 0);
    }

    /**
     * @dev Disallows direct send by setting a default function without the `payable` flag.
     */
    fallback() external {}

    /**
     * @dev Transfer all Ether held by the contract to the owner.
     */
    function reclaimEther() external onlyOwner {
        payable(owner).transfer(address(this).balance);
    }
}

File 15 of 34: HasNoTokens.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./CanReclaimToken.sol";

/**
 * @title Contracts that should not own Tokens
 * @author Remco Bloemen <remco@2π.com>
 * @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens.
 * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
 * owner to reclaim the tokens.
 */
contract HasNoTokens is CanReclaimToken {
    /**
     * @dev Reject all ERC223 compatible tokens
     * @param _from address The address that is transferring the tokens
     * @param _value uint256 the amount of the specified token
     * @param _data Bytes The data passed from the caller.
     */
    function tokenFallback(
        address _from,
        uint256 _value,
        bytes calldata _data
    ) external pure {
        _from;
        _value;
        _data;
        revert();
    }
}

File 16 of 34: IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 17 of 34: IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 18 of 34: 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 19 of 34: IERC20.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 20 of 34: IERC677Recipient.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

/**
 * @title IERC677Recipient
 * @dev Contracts implementing this interface can participate in [ERC677].
 */
interface IERC677Recipient {
    /**
     * @dev Receives notification from [ERC677] transferAndCall.
     * @param from Sender address.
     * @param amount Number of tokens.
     * @param data Additional data.
     */
    function onTokenTransfer(
        address from,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}

File 21 of 34: IValidator.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

/**
 * @title IValidator
 * @dev Contracts implementing this interface validate token transfers.
 */
interface IValidator {
    /**
     * @dev Emitted when a validator makes a decision.
     * @param from Sender address.
     * @param to Recipient address.
     * @param amount Number of tokens.
     * @param valid True if transfer approved, false if rejected.
     */
    event Decision(
        address indexed from,
        address indexed to,
        uint256 amount,
        bool valid
    );

    /**
     * @dev Validates token transfer.
     * If the sender is on the blacklist the transfer is denied.
     * @param from Sender address.
     * @param to Recipient address.
     * @param amount Number of tokens.
     */
    function validate(
        address from,
        address to,
        uint256 amount
    ) external returns (bool valid);
}

File 22 of 34: Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 23 of 34: MintableController.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./StandardController.sol";
import "./MintableTokenLib.sol";

/**
 * @title MintableController
 * @dev This contracts implements functionality allowing for minting and burning of tokens.
 */
contract MintableController is StandardController {
    using MintableTokenLib for TokenStorage;

    mapping(address => uint256) internal mintAllowances;
    uint256 internal maxMintAllowance;

    /**
     * @dev Contract constructor.
     * @param storage_ Address of the token storage for the controller.
     * @param initialSupply The amount of tokens to mint upon creation.
     * @param frontend_ Address of the authorized frontend.
     */
    constructor(
        address storage_,
        uint256 initialSupply,
        address frontend_
    ) StandardController(storage_, initialSupply, frontend_) {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    /**
     * @dev Emitted when allowance is set.
     * @param account The address of the account.
     * @param amount The amount of allowance.
     */
    event MintAllowance(address indexed account, uint256 amount);

    /**
     * @dev Emitted when max allowance is set.
     * @param amount The amount of allowance.
     */
    event MaxMintAllowance(uint256 amount);

    /**
     * @dev modifier to restrict access to system accounts with enough allowance
     * @param account The address of the account.
     * @param amount The amount of allowance.
     */
    modifier onlyAllowedSystemAccount(address account, uint256 amount) {
        require(
            hasRole(SYSTEM_ROLE, account),
            "MintableController: caller is not a system account"
        );
        require(
            mintAllowances[account] >= amount,
            "MintableController: caller is not allowed to perform this action"
        );
        _;
    }

    /**
     * @dev Mints new tokens.
     * @param caller Address of the caller passed through the frontend.
     * @param to Address to credit the tokens.
     * @param amount Number of tokens to mint.
     */
    function mintTo_withCaller(
        address caller,
        address to,
        uint256 amount
    )
        public
        onlyFrontend
        onlyAllowedSystemAccount(caller, amount)
        returns (bool)
    {
        _avoidBlackholes(to);
        mintAllowances[caller] = mintAllowances[caller] - amount;
        require(token.mint(to, amount), "MintableController: mint failed");
        return true;
    }

    /**
     * @dev Burns tokens from token owner.
     * This removes the burned tokens from circulation.
     * @param caller Address of the caller passed through the frontend.
     * @param from Address of the token owner.
     * @param amount Number of tokens to burn.
     * @param h Hash which the token owner signed.
     * @param v Signature component.
     * @param r Signature component.
     * @param s Sigature component.
     */
    function burnFrom_withCaller(
        address caller,
        address from,
        uint256 amount,
        bytes32 h,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public onlyFrontend onlySystemAccount(caller) returns (bool) {
        require(
            token.burn(from, amount, h, v, r, s),
            "MintableController: burn failed"
        );
        return true;
    }

    /**
     * @dev Burns tokens from token owner.
     * This removes the burned tokens from circulation.
     * @param from Address of the token owner.
     * @param amount Number of tokens to burn.
     */
    function burnFrom(
        address from,
        uint256 amount
    ) public onlyFrontend onlySystemAccount(msg.sender) returns (bool) {
        require(token.burn(from, amount), "MintableController: burn failed");
        return true;
    }

    /**
     * @dev set maximum allowance for system accounts.
     * @param amount The amount of allowance.
     */
    function setMaxMintAllowance(uint256 amount) public virtual onlyOwner {
        emit MaxMintAllowance(amount);
        maxMintAllowance = amount;
    }

    /**
     * @dev get maximum allowance for system accounts.
     * @return The amount of allowance.
     */
    function getMaxMintAllowance() public view virtual returns (uint256) {
        return maxMintAllowance;
    }

    /**
     * @dev set allowance for an account.
     * @param account The address of the account.
     * @param amount The amount of allowance.
     */
    function setMintAllowance(
        address account,
        uint256 amount
    ) public virtual onlyAdminAccounts {
        require(
            amount <= maxMintAllowance,
            "MintableController: allowance exceeds maximum setted by owner"
        );
        mintAllowances[account] = amount;
        emit MintAllowance(account, amount);
    }

    /**
     * @dev get allowance for an account.
     * @param account The address of the account.
     * @return The amount of allowance.
     */
    function getMintAllowance(
        address account
    ) public view virtual returns (uint256) {
        return mintAllowances[account];
    }
}

File 24 of 34: MintableTokenLib.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./SignatureChecker.sol";
import "./ERC20Lib.sol";
import "./TokenStorage.sol";

/**
 * @title Mintable token
 * @dev Simple ERC20 Token example, with mintable token creation
 * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
 * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
 */

library MintableTokenLib {
    using SignatureChecker for address;

    /**
     * @dev Mints new tokens.
     * @param db Token storage to operate on.
     * @param to The address that will recieve the minted tokens.
     * @param amount The amount of tokens to mint.
     */
    function mint(
        TokenStorage db,
        address to,
        uint256 amount
    ) external returns (bool) {
        db.addBalance(to, amount);
        return true;
    }

    /**
     * @dev Burns tokens.
     * @param db Token storage to operate on.
     * @param from The address holding tokens.
     * @param amount The amount of tokens to burn.
     */
    function burn(
        TokenStorage db,
        address from,
        uint256 amount
    ) public returns (bool) {
        db.subBalance(from, amount);
        return true;
    }

    /**
     * @dev Burns tokens from a specific address.
     * To burn the tokens the caller needs to provide a signature
     * proving that the caller is authorized by the token owner to do so.
     * @param db Token storage to operate on.
     * @param from The address holding tokens.
     * @param amount The amount of tokens to burn.
     * @param h Hash which the token owner signed.
     * @param v Signature component.
     * @param r Signature component.
     * @param s Sigature component.
     */
    function burn(
        TokenStorage db,
        address from,
        uint256 amount,
        bytes32 h,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (bool) {
        bytes memory signature;
        if (r != bytes32(0) || s != bytes32(0)) {
            signature = bytes(abi.encodePacked(r, s, v));
        }
        require(
            from.isValidSignatureNow(h, signature),
            "signature/hash does not match"
        );
        return burn(db, from, amount);
    }
}

File 25 of 34: NoOwner.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./HasNoEther.sol";
import "./HasNoTokens.sol";
import "./HasNoContracts.sol";

/**
 * @title Base contract for contracts that should not own things.
 * @author Remco Bloemen <remco@2π.com>
 * @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
 * Owned contracts. See respective base contracts for details.
 */
contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {

}

File 26 of 34: Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address public owner;

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

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor() {
        owner = msg.sender;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param _newOwner The address to transfer ownership to.
     */
    function transferOwnership(address _newOwner) public virtual onlyOwner {
        _transferOwnership(_newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param _newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address _newOwner) internal {
        require(_newOwner != address(0));
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
    }
}

File 27 of 34: SafeERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.11;

import "./ERC20Basic.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    function safeTransfer(
        ERC20Basic _token,
        address _to,
        uint256 _value
    ) internal {
        require(_token.transfer(_to, _value));
    }
}

File 28 of 34: SignatureChecker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.0;

import "./ECDSA.sol";
import "./Address.sol";
import "./IERC1271.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Gnosis Safe.
 *
 * _Available since v4.1._
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
        if (error == ECDSA.RecoverError.NoError && recovered == signer) {
            return true;
        }

        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
        );
        return (success &&
            result.length == 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

File 29 of 34: SmartTokenLib.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./ERC20Lib.sol";
import "./MintableTokenLib.sol";
import "./IValidator.sol";
import "./SignatureChecker.sol";

/**
 * @title SmartTokenLib
 * @dev This library provides functionality which is required from a regulatory perspective.
 */
library SmartTokenLib {
    using ERC20Lib for TokenStorage;
    using MintableTokenLib for TokenStorage;
    using SignatureChecker for address;

    struct SmartStorage {
        IValidator validator;
    }

    /**
     * @dev Emitted when the contract owner recovers tokens.
     * @param from Sender address.
     * @param to Recipient address.
     * @param amount Number of tokens.
     */
    event Recovered(address indexed from, address indexed to, uint256 amount);

    /**
     * @dev Emitted when updating the validator.
     * @param old Address of the old validator.
     * @param current Address of the new validator.
     */
    event Validator(address indexed old, address indexed current);

    /**
     * @dev Sets a new validator.
     * @param self Smart storage to operate on.
     * @param validator Address of validator.
     */
    function setValidator(
        SmartStorage storage self,
        address validator
    ) external {
        emit Validator(address(self.validator), validator);
        self.validator = IValidator(validator);
    }

    /**
     * @dev Approves or rejects a transfer request.
     * The request is forwarded to a validator which implements
     * the actual business logic.
     * @param self Smart storage to operate on.
     * @param from Sender address.
     * @param to Recipient address.
     * @param amount Number of tokens.
     */
    function validate(
        SmartStorage storage self,
        address from,
        address to,
        uint256 amount
    ) external returns (bool valid) {
        return self.validator.validate(from, to, amount);
    }

    /**
     * @dev Recovers tokens from an address and reissues them to another address.
     * In case a user loses its private key the tokens can be recovered by burning
     * the tokens from that address and reissuing to a new address.
     * To recover tokens the contract owner needs to provide a signature
     * proving that the token owner has authorized the owner to do so.
     * @param from Address to burn tokens from.
     * @param to Address to mint tokens to.
     * @param h Hash which the token owner signed.
     * @param v Signature component.
     * @param r Signature component.
     * @param s Sigature component.
     * @return Amount recovered.
     */
    function recover(
        TokenStorage token,
        address from,
        address to,
        bytes32 h,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256) {
        bytes memory signature;
        if (r != bytes32(0) || s != bytes32(0)) {
            signature = bytes(abi.encodePacked(r, s, v));
        }
        require(
            from.isValidSignatureNow(h, signature),
            "signature/hash does not recover from address"
        );
        uint256 amount = token.balanceOf(from);
        require(token.burn(from, amount), "burn failed");
        require(token.mint(to, amount), "mint failed");
        emit Recovered(from, to, amount);
        return amount;
    }

    /**
     * @dev Gets the current validator.
     * @param self Smart storage to operate on.
     * @return Address of validator.
     */
    function getValidator(
        SmartStorage storage self
    ) external view returns (address) {
        return address(self.validator);
    }
}

File 30 of 34: StandardController.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./TokenStorage.sol";
import "./IERC20.sol";
import "./ERC20Lib.sol";
import "./ERC677Lib.sol";
import "./ClaimableSystemRole.sol";

/**
 * @title StandardController
 * @dev This is the base contract which delegates token methods [ERC20 and ERC677]
 * to their respective library implementations.
 * The controller is primarily intended to be interacted with via a token frontend.
 */
contract StandardController is ClaimableSystemRole {
    using ERC20Lib for TokenStorage;
    using ERC677Lib for TokenStorage;

    TokenStorage internal token;
    address internal frontend;
    mapping(address => bool) internal bridgeFrontends;
    uint8 public decimals = 18;

    /**
     * @dev Emitted when updating the frontend.
     * @param old Address of the old frontend.
     * @param current Address of the new frontend.
     */
    event Frontend(address indexed old, address indexed current);

    /**
     * @dev Emitted when updating the Bridge frontend.
     * @param frontend Address of the new Bridge frontend.
     * @param title String of the frontend name.
     */
    event BridgeFrontend(address indexed frontend, string indexed title);

    /**
     * @dev Emitted when removing a Bridge frontend.
     * @param frontend Address of the Bridge frontend.
     */
    event BridgeFrontendRemoved(address indexed frontend);

    /**
     * @dev Emitted when updating the storage.
     * @param old Address of the old storage.
     * @param current Address of the new storage.
     */
    event Storage(address indexed old, address indexed current);

    /**
     * @dev Modifier which prevents the function from being called by unauthorized parties.
     * The caller must be the frontend otherwise the call is reverted.
     */
    modifier onlyFrontend() {
        require(isFrontend(msg.sender));
        _;
    }

    /**
     * @dev Contract constructor.
     * @param storage_ Address of the token storage for the controller.
     * @param initialSupply The amount of tokens to mint upon creation.
     * @param frontend_ Address of the authorized frontend.
     */
    constructor(address storage_, uint256 initialSupply, address frontend_) {
        require(
            storage_ == address(0x0) || initialSupply == 0,
            "either a token storage must be initialized or no initial supply"
        );
        if (storage_ == address(0x0)) {
            token = new TokenStorage();
            token.addBalance(msg.sender, initialSupply);
        } else {
            token = TokenStorage(storage_);
        }
        frontend = frontend_;
    }

    /**
     * @dev Prevents tokens to be sent to well known blackholes by throwing on known blackholes.
     * @param to The address of the intended recipient.
     */
    function _avoidBlackholes(address to) internal view {
        require(to != address(0x0), "must not send to 0x0");
        require(to != address(this), "must not send to controller");
        require(to != address(token), "must not send to token storage");
        require(to != frontend, "must not send to frontend");
        require(isFrontend(to) == false, "must not send to bridgeFrontends");
    }

    /**
     * @dev Returns the current frontend.
     * @return Address of the frontend.
     */
    function getFrontend() external view returns (address) {
        return frontend;
    }

    /**
     * @dev Returns the current storage.
     * @return Address of the storage.
     */
    function getStorage() external view returns (address) {
        return address(token);
    }

    /**
     * @dev Sets a new frontend.
     * @param frontend_ Address of the new frontend.
     */
    function setFrontend(address frontend_) public onlyOwner {
        emit Frontend(frontend, frontend_);
        frontend = frontend_;
    }

    /**
     * @dev Set a new bridge frontend.
     * @param frontend_ Address of the new bridge frontend.
     * @param title Keccack256 hash of the frontend title.
     */
    function setBridgeFrontend(
        address frontend_,
        string calldata title
    ) public onlyOwner {
        bridgeFrontends[frontend_] = true;
        emit BridgeFrontend(frontend_, title);
    }

    /**
     * @dev Removes a bridge frontend.
     * @param frontend_ Address of the bridge frontend to remove.
     */
    function removeBridgeFrontend(address frontend_) public onlyOwner {
        bridgeFrontends[frontend_] = false;
        emit BridgeFrontendRemoved(frontend_);
    }

    /**
     * @dev Checks wether an address is a frontend.
     * @param frontend_ Address of the frontend candidate.
     */
    function isFrontend(address frontend_) public view returns (bool) {
        return (frontend_ == frontend) || bridgeFrontends[frontend_];
    }

    /**
     * @dev Sets a new storage.
     * @param storage_ Address of the new storage.
     */
    function setStorage(address storage_) external onlyOwner {
        emit Storage(address(token), storage_);
        token = TokenStorage(storage_);
    }

    /**
     * @dev Transfers the ownership of the storage.
     * @param newOwner Address of the new storage owner.
     */
    function transferStorageOwnership(address newOwner) public onlyOwner {
        token.transferOwnership(newOwner);
    }

    /**
     * @dev Claims the ownership of the storage.
     */
    function claimStorageOwnership() public onlyOwner {
        token.claimOwnership();
    }

    /**
     * @dev Transfers tokens [ERC20].
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transfer_withCaller(
        address caller,
        address to,
        uint256 amount
    ) public virtual onlyFrontend returns (bool ok) {
        _avoidBlackholes(to);
        return token.transfer(caller, to, amount);
    }

    /**
     * @dev Transfers tokens from a specific address [ERC20].
     * The address owner has to approve the spender beforehand.
     * @param caller Address of the caller passed through the frontend.
     * @param from Address to debet the tokens from.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     */
    function transferFrom_withCaller(
        address caller,
        address from,
        address to,
        uint256 amount
    ) public virtual onlyFrontend returns (bool ok) {
        _avoidBlackholes(to);
        return token.transferFrom(caller, from, to, amount);
    }

    /**
     * @dev Approves a spender [ERC20].
     * Note that using the approve/transferFrom presents a possible
     * security vulnerability described in:
     * https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.quou09mcbpzw
     * Use transferAndCall to mitigate.
     * @param caller Address of the caller passed through the frontend.
     * @param spender The address of the future spender.
     * @param amount The allowance of the spender.
     */
    function approve_withCaller(
        address caller,
        address spender,
        uint256 amount
    ) public onlyFrontend returns (bool ok) {
        return token.approve(caller, spender, amount);
    }

    /**
     * @dev Transfers tokens and subsequently calls a method on the recipient [ERC677].
     * If the recipient is a non-contract address this method behaves just like transfer.
     * @param caller Address of the caller passed through the frontend.
     * @param to Recipient address.
     * @param amount Number of tokens to transfer.
     * @param data Additional data passed to the recipient's tokenFallback method.
     */
    function transferAndCall_withCaller(
        address caller,
        address to,
        uint256 amount,
        bytes calldata data
    ) public virtual onlyFrontend returns (bool ok) {
        _avoidBlackholes(to);
        return token.transferAndCall(caller, to, amount, data);
    }

    /**
     * @dev Returns the total supply.
     * @return Number of tokens.
     */
    function totalSupply() external view returns (uint) {
        return token.getSupply();
    }

    /**
     * @dev Returns the number tokens associated with an address.
     * @param who Address to lookup.
     * @return Balance of address.
     */
    function balanceOf(address who) external view returns (uint) {
        return token.getBalance(who);
    }

    /**
     * @dev Returns the allowance for a spender
     * @param owner The address of the owner of the tokens.
     * @param spender The address of the spender.
     * @return Number of tokens the spender is allowed to spend.
     */
    function allowance(
        address owner,
        address spender
    ) external view returns (uint) {
        return token.allowance(owner, spender);
    }
}

File 31 of 34: Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./Math.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

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

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 32 of 34: SystemRole.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./AccessControl.sol";
import "./Ownable.sol";

/**
 * @title SystemRole
 * @dev SystemRole accounts have been approved to perform operational actions (e.g. mint and burn).
 * @dev AdminRole accounts have been approved to perform administrative actions (e.g. setting allowances).
 * @notice The contract is an abstract contract.
 */
abstract contract SystemRole is AccessControl, Ownable {
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant SYSTEM_ROLE = keccak256("SYSTEM_ROLE");

    /**
     * @dev Emitted when system account is added.
     * @param account The address of the account.
     */
    event SystemAccountAdded(address indexed account);

    /**
     * @dev Emitted when system account is removed.
     * @param account The address of the account.
     */
    event SystemAccountRemoved(address indexed account);

    /**
     * @dev Emitted when admin account is added.
     * @param account The address of the account.
     */
    event AdminAccountAdded(address indexed account);

    /**
     * @dev Emitted when admin account is removed.
     * @param account The address of the account.
     */
    event AdminAccountRemoved(address indexed account);

    /**
     * @dev modifier to restrict access to system accounts.
     */
    modifier onlySystemAccounts() {
        require(
            hasRole(SYSTEM_ROLE, msg.sender),
            "SystemRole: caller is not a system account"
        );
        _;
    }

    /**
     * @dev modifier to restrict access to system accounts.
     * @param account The address of the account.
     */
    modifier onlySystemAccount(address account) {
        require(
            hasRole(SYSTEM_ROLE, account),
            "SystemRole: caller is not a system account"
        );
        _;
    }

    /**
     * @dev modifier to restrict access to admin accounts.
     */
    modifier onlyAdminAccounts() {
        require(
            hasRole(ADMIN_ROLE, msg.sender),
            "SystemRole: caller is not an admin account"
        );
        _;
    }

    /**
     * @dev modifier to restrict access to admin accounts.
     * @param account The address of the account.
     */
    modifier onlyAdminAccount(address account) {
        require(
            hasRole(ADMIN_ROLE, account),
            "SystemRole: caller is not an admin account"
        );
        _;
    }

    /**
     * @dev Checks wether an address is a system account.
     * @param account The address of the account.
     * @return true if system account.
     */
    function isSystemAccount(address account) public view returns (bool) {
        return hasRole(SYSTEM_ROLE, account);
    }

    /**
     * @dev add system account.
     * @param account The address of the account.
     */
    function addSystemAccount(address account) public virtual onlyOwner {
        grantRole(SYSTEM_ROLE, account);
        emit SystemAccountAdded(account);
    }

    /**
     * @dev remove system account.
     * @param account The address of the account.
     */
    function removeSystemAccount(address account) public virtual onlyOwner {
        revokeRole(SYSTEM_ROLE, account);
        emit SystemAccountRemoved(account);
    }

    /**
     * @dev add admin account.
     * @param account The address of the account.
     */
    function addAdminAccount(address account) public virtual onlyOwner {
        grantRole(ADMIN_ROLE, account);
        emit AdminAccountAdded(account);
    }

    /**
     * @dev remove admin account.
     * @param account The address of the account.
     */
    function removeAdminAccount(address account) public virtual onlyOwner {
        revokeRole(ADMIN_ROLE, account);
        emit AdminAccountRemoved(account);
    }
}

File 33 of 34: TokenStorage.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

import "./Claimable.sol";
import "./CanReclaimToken.sol";
import "./NoOwner.sol";
import "./TokenStorageLib.sol";

/**
 * @title TokenStorage
 * @dev External storage for tokens.
 * The storage is implemented in a separate contract to maintain state
 * between token upgrades.
 */
contract TokenStorage is Claimable, CanReclaimToken, NoOwner {
    using TokenStorageLib for TokenStorageLib.TokenStorage;

    TokenStorageLib.TokenStorage internal tokenStorage;

    /**
     * @dev Increases balance of an address.
     * @param to Address to increase.
     * @param amount Number of units to add.
     */
    function addBalance(address to, uint256 amount) external onlyOwner {
        tokenStorage.addBalance(to, amount);
    }

    /**
     * @dev Decreases balance of an address.
     * @param from Address to decrease.
     * @param amount Number of units to subtract.
     */
    function subBalance(address from, uint256 amount) external onlyOwner {
        tokenStorage.subBalance(from, amount);
    }

    /**
     * @dev Sets the allowance for a spender.
     * @param owner Address of the owner of the tokens to spend.
     * @param spender Address of the spender.
     * @param amount Quantity of allowance.
     */
    function setAllowed(
        address owner,
        address spender,
        uint256 amount
    ) external onlyOwner {
        tokenStorage.setAllowed(owner, spender, amount);
    }

    /**
     * @dev Returns the supply of tokens.
     * @return Total supply.
     */
    function getSupply() external view returns (uint256) {
        return tokenStorage.getSupply();
    }

    /**
     * @dev Returns the balance of an address.
     * @param who Address to lookup.
     * @return Number of units.
     */
    function getBalance(address who) external view returns (uint256) {
        return tokenStorage.getBalance(who);
    }

    /**
     * @dev Returns the allowance for a spender.
     * @param owner Address of the owner of the tokens to spend.
     * @param spender Address of the spender.
     * @return Number of units.
     */
    function getAllowed(
        address owner,
        address spender
    ) external view returns (uint256) {
        return tokenStorage.getAllowed(owner, spender);
    }

    /**
     * @dev Explicit override of transferOwnership from Claimable and Ownable
     * @param newOwner Address to transfer ownership to.
     */
    function transferOwnership(
        address newOwner
    ) public override(Claimable, Ownable) {
        Claimable.transferOwnership(newOwner);
    }
}

File 34 of 34: TokenStorageLib.sol
/* SPDX-License-Identifier: apache-2.0 */
/**
 * Copyright 2022 Monerium ehf.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity 0.8.11;

/*
 * @title TokenStorageLib
 * @dev Implementation of an[external storage for tokens.
 */
library TokenStorageLib {
    struct TokenStorage {
        mapping(address => uint) balances;
        mapping(address => mapping(address => uint)) allowed;
        uint256 totalSupply;
    }

    /**
     * @dev Increases balance of an address.
     * @param self Token storage to operate on.
     * @param to Address to increase.
     * @param amount Number of units to add.
     */
    function addBalance(
        TokenStorage storage self,
        address to,
        uint256 amount
    ) external {
        self.totalSupply = self.totalSupply + amount;
        self.balances[to] = self.balances[to] + amount;
    }

    /**
     * @dev Decreases balance of an address.
     * @param self Token storage to operate on.
     * @param from Address to decrease.
     * @param amount Number of units to subtract.
     */
    function subBalance(
        TokenStorage storage self,
        address from,
        uint256 amount
    ) external {
        self.totalSupply = self.totalSupply - amount;
        self.balances[from] = self.balances[from] - amount;
    }

    /**
     * @dev Sets the allowance for a spender.
     * @param self Token storage to operate on.
     * @param owner Address of the owner of the tokens to spend.
     * @param spender Address of the spender.
     * @param amount Qunatity of allowance.
     */
    function setAllowed(
        TokenStorage storage self,
        address owner,
        address spender,
        uint256 amount
    ) external {
        self.allowed[owner][spender] = amount;
    }

    /**
     * @dev Returns the supply of tokens.
     * @param self Token storage to operate on.
     * @return Total supply.
     */
    function getSupply(TokenStorage storage self) external view returns (uint) {
        return self.totalSupply;
    }

    /**
     * @dev Returns the balance of an address.
     * @param self Token storage to operate on.
     * @param who Address to lookup.
     * @return Number of units.
     */
    function getBalance(
        TokenStorage storage self,
        address who
    ) external view returns (uint) {
        return self.balances[who];
    }

    /**
     * @dev Returns the allowance for a spender.
     * @param self Token storage to operate on.
     * @param owner Address of the owner of the tokens to spend.
     * @param spender Address of the spender.
     * @return Number of units.
     */
    function getAllowed(
        TokenStorage storage self,
        address owner,
        address spender
    ) external view returns (uint) {
        return self.allowed[owner][spender];
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"storage_","type":"address"},{"internalType":"address","name":"validator","type":"address"},{"internalType":"bytes3","name":"ticker_","type":"bytes3"},{"internalType":"address","name":"frontend_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AdminAccountAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AdminAccountRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"frontend","type":"address"},{"indexed":true,"internalType":"string","name":"title","type":"string"}],"name":"BridgeFrontend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"frontend","type":"address"}],"name":"BridgeFrontendRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"old","type":"address"},{"indexed":true,"internalType":"address","name":"current","type":"address"}],"name":"Frontend","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MaxMintAllowance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MintAllowance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousPendingOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"OwnershipTransferPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"old","type":"address"},{"indexed":true,"internalType":"address","name":"current","type":"address"}],"name":"Storage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SystemAccountAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SystemAccountRemoved","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SYSTEM_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addSystemAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve_withCaller","outputs":[{"internalType":"bool","name":"ok","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"h","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"burnFrom_withCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimStorageOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFrontend","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxMintAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getMintAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStorage","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"frontend_","type":"address"}],"name":"isFrontend","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSystemAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintTo_withCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes32","name":"h","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"recover_withCaller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"frontend_","type":"address"}],"name":"removeBridgeFrontend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeSystemAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"frontend_","type":"address"},{"internalType":"string","name":"title","type":"string"}],"name":"setBridgeFrontend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"frontend_","type":"address"}],"name":"setFrontend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setMaxMintAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setMintAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"storage_","type":"address"}],"name":"setStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"setValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticker","outputs":[{"internalType":"bytes3","name":"","type":"bytes3"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferAndCall_withCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom_withCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferStorageOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer_withCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60806040526006805460ff191660121790553480156200001e57600080fd5b5060405162003bed38038062003bed8339810160408190526200004191620003c1565b600180546001600160a01b03191633179055836000828282826001600160a01b03831615806200006f575081155b620000e75760405162461bcd60e51b815260206004820152603f60248201527f656974686572206120746f6b656e2073746f72616765206d757374206265206960448201527f6e697469616c697a6564206f72206e6f20696e697469616c20737570706c790060648201526084015b60405180910390fd5b6001600160a01b0383166200019e57604051620001049062000396565b604051809103906000f08015801562000121573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b039290921691821790556040516310f29c1d60e11b8152336004820152602481018490526321e5383a90604401600060405180830381600087803b1580156200017f57600080fd5b505af115801562000194573d6000803e3d6000fd5b50505050620001ba565b600380546001600160a01b0319166001600160a01b0385161790555b600480546001600160a01b0319166001600160a01b039290921691909117905550620001ea9050600033620002e6565b5050506001600160a01b038316620002515760405162461bcd60e51b8152602060048201526024808201527f76616c696461746f722063616e6e6f7420626520746865206e756c6c206164646044820152637265737360e01b6064820152608401620000de565b60405163ad41534960e01b8152600960048201526001600160a01b038416602482015273ceb6728300915d56ac58fc99b4becc01a630ed8a9063ad4153499060440160006040518083038186803b158015620002ac57600080fd5b505af4158015620002c1573d6000803e3d6000fd5b5050600a805462ffffff191660e89590951c94909417909355506200042d9350505050565b620002f28282620002f6565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620002f2576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620003523390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610b1780620030d683390190565b80516001600160a01b0381168114620003bc57600080fd5b919050565b60008060008060808587031215620003d857600080fd5b620003e385620003a4565b9350620003f360208601620003a4565b60408601519093506001600160e81b0319811681146200041257600080fd5b91506200042260608601620003a4565b905092959194509250565b612c99806200043d6000396000f3fe608060405234801561001057600080fd5b50600436106103145760003560e01c806375b238fc116101a7578063a84c56d0116100ee578063e974fee911610097578063f27c5f6e11610071578063f27c5f6e146106e6578063f2fde38b146106f9578063fd2319c41461070c57600080fd5b8063e974fee9146106ad578063ebbc3d46146106c0578063ee0b5445146106d357600080fd5b8063dd62ed3e116100c8578063dd62ed3e14610674578063e174fd9414610687578063e30c39781461069a57600080fd5b8063a84c56d014610646578063b516af7014610659578063d547741f1461066157600080fd5b80638fb81d98116101505780639e7f43ca1161012a5780639e7f43ca1461062b5780639ea33e191461063e578063a217fddf146103e257600080fd5b80638fb81d98146105ce5780639137c1a7146105e157806391d14854146105f457600080fd5b8063802d441f11610181578063802d441f1461056a5780638ba47bdd1461057d5780638da5cb5b146105bb57600080fd5b806375b238fc1461051d578063774d54091461054457806379cc67901461055757600080fd5b8063326ecb051161026b5780634eb007541161021457806369569a51116101ee57806369569a51146104d057806370a08231146104e357806375071d2a146104f657600080fd5b80634eb00754146104975780634fe57e7a146104aa57806367a89a72146104bd57600080fd5b80633cd1570f116102455780633cd1570f146104535780634a36703b146104665780634e71e0c81461048f57600080fd5b8063326ecb051461041c5780633408f73a1461042f57806336568abe1461044057600080fd5b8063248a9ca3116102cd5780632ff2e9dc116102a75780632ff2e9dc146103e2578063313ce567146103ea578063322ec0fb1461040957600080fd5b8063248a9ca31461039957806325ec2eb0146103bc5780632f2ff15d146103cf57600080fd5b80631195e07e116102fe5780631195e07e146103665780631327d3d81461036e57806318160ddd1461038357600080fd5b80623074ff1461031957806301ffc9a714610343575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b61035661035136600461267e565b61071f565b604051901515815260200161033a565b6103266107b8565b61038161037c3660046126d5565b61084d565b005b61038b6108f2565b60405190815260200161033a565b61038b6103a73660046126f2565b60009081526020819052604090206001015490565b6103566103ca3660046126d5565b610979565b6103816103dd36600461270b565b6109b2565b61038b600081565b6006546103f79060ff1681565b60405160ff909116815260200161033a565b61035661041736600461273b565b6109dc565b61035661042a3660046126d5565b610c78565b6003546001600160a01b0316610326565b61038161044e36600461270b565b610cb8565b61038b610461366004612792565b610d44565b61038b6104743660046126d5565b6001600160a01b031660009081526007602052604090205490565b610381610ed1565b6103566104a5366004612809565b610f66565b6103816104b83660046126d5565b611137565b6103816104cb3660046126d5565b6111af565b6103816104de3660046126d5565b611227565b61038b6104f13660046126d5565b61129a565b61038b7f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f81565b61038b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61035661055236600461273b565b611322565b61035661056536600461285b565b6113ef565b6103816105783660046126d5565b611592565b600a5461058a9060e81b81565b6040517fffffff0000000000000000000000000000000000000000000000000000000000909116815260200161033a565b600154610326906001600160a01b031681565b6103816105dc3660046128d0565b6115f2565b6103816105ef3660046126d5565b61167c565b61035661060236600461270b565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610356610639366004612925565b6116ef565b60085461038b565b6103816106543660046126d5565b61180d565b610381611885565b61038161066f36600461270b565b611906565b61038b610682366004612998565b61192b565b61035661069536600461273b565b6119de565b600254610326906001600160a01b031681565b6103566106bb3660046129c6565b611aca565b6103816106ce3660046126d5565b611bc0565b6103816106e13660046126d5565b611c38565b6103816106f436600461285b565b611cc3565b6103816107073660046126d5565b611e38565b61038161071a3660046126f2565b611eab565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107b257507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6271970c0000000000000000000000000000000000000000000000000000000081526009600482015260009073ceb6728300915d56ac58fc99b4becc01a630ed8a90636271970c90602401602060405180830381865af4158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190612a17565b905090565b6001546001600160a01b0316331461086457600080fd5b6040517fad415349000000000000000000000000000000000000000000000000000000008152600960048201526001600160a01b038216602482015273ceb6728300915d56ac58fc99b4becc01a630ed8a9063ad4153499060440160006040518083038186803b1580156108d757600080fd5b505af41580156108eb573d6000803e3d6000fd5b5050505050565b600354604080517f6c9c2faf00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691636c9c2faf9160048083019260209291908290030181865afa158015610955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190612a34565b6004546000906001600160a01b03838116911614806107b25750506001600160a01b031660009081526005602052604090205460ff1690565b6000828152602081905260409020600101546109cd81611efa565b6109d78383611f07565b505050565b60006109e733610979565b6109f057600080fd5b6001600160a01b03841660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe60205260409020548490839060ff16610aa65760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420612073797374656d206163636f756e74000000000000000000000000000060648201526084015b60405180910390fd5b6001600160a01b038216600090815260076020526040902054811115610b36576040805162461bcd60e51b81526020600482015260248101919091527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420616c6c6f77656420746f20706572666f726d207468697320616374696f6e6064820152608401610a9d565b610b3f85611fa5565b6001600160a01b038616600090815260076020526040902054610b63908590612a63565b6001600160a01b03878116600090815260076020526040908190209290925560035491517fb0c29c7400000000000000000000000000000000000000000000000000000000815291811660048301528616602482015260448101859052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063b0c29c7490606401602060405180830381865af4158015610bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c209190612a7a565b610c6c5760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206d696e74206661696c6564006044820152606401610a9d565b50600195945050505050565b6001600160a01b03811660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe602052604081205460ff166107b2565b6001600160a01b0381163314610d365760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a9d565b610d408282612166565b5050565b6000610d4f33610979565b610d5857600080fd5b6001600160a01b03881660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe6020526040902054889060ff16610df45760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b610dfd87611fa5565b6003546040517f8f7227340000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152898216602482015290881660448201526064810187905260ff8616608482015260a4810185905260c4810184905273ceb6728300915d56ac58fc99b4becc01a630ed8a90638f7227349060e401602060405180830381865af4158015610ea0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec49190612a34565b9998505050505050505050565b6002546001600160a01b03163314610ee857600080fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600254600180546001600160a01b0319166001600160a01b039092169182179055610f54906000906121e5565b600280546001600160a01b0319169055565b6000610f7133610979565b610f7a57600080fd5b6001600160a01b03881660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe6020526040902054889060ff166110165760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b6003546040517f799639d40000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201529089166024820152604481018890526064810187905260ff8616608482015260a4810185905260c48101849052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063799639d49060e401602060405180830381865af41580156110b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110dc9190612a7a565b6111285760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610a9d565b50600198975050505050505050565b6001546001600160a01b0316331461114e57600080fd5b6111787fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775826109b2565b6040516001600160a01b038216907f5c7eb798b922f0164aa9c5340006161c64436190a49eebc58b4e6e0715700ae690600090a250565b6001546001600160a01b031633146111c657600080fd5b6111f07fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177582611906565b6040516001600160a01b038216907fc3198db98a2c50068f0a99b9297e60b2dbf0eafcde57e366e70a29f887c44e1090600090a250565b6001546001600160a01b0316331461123e57600080fd5b6004546040516001600160a01b038084169216907fcb01f884fc4203d4c1643cb0e126faeb397682c122ca8c0433776d42cdc0060a90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040517ff8b2cb4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152600092169063f8b2cb4f90602401602060405180830381865afa1580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b29190612a34565b600061132d33610979565b61133657600080fd5b6003546040517f365feff10000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201528582166024820152908416604482015260648101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd39063365feff1906084015b602060405180830381865af41580156113c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e79190612a7a565b949350505050565b60006113fa33610979565b61140357600080fd5b3360008181527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe602052604090205460ff166114945760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b6003546040517fa6c9ac280000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152908516602482015260448101849052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063a6c9ac2890606401602060405180830381865af4158015611518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153c9190612a7a565b6115885760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610a9d565b5060019392505050565b6001546001600160a01b031633146115a957600080fd5b6001600160a01b038116600081815260056020526040808220805460ff19169055517f10cf5a523a14a54e61c21610dc10c01e40e2ebc37baa3effd74032f7d3865e6d9190a250565b6001546001600160a01b0316331461160957600080fd5b6001600160a01b03831660009081526005602052604090819020805460ff191660011790555161163c9083908390612a9c565b604051908190038120906001600160a01b038516907fec75908259de4d038ff5f2b6b99e3725bc21871f4d2a44adeff9bb814afbc9f790600090a3505050565b6001546001600160a01b0316331461169357600080fd5b6003546040516001600160a01b038084169216907fdaaa9d417a3107fd3d9db02eba3eeafbae2b8af16ee08c534f5bc449054c1c4c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038087166024830152851660448201526064810184905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611760573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117849190612a7a565b6117f65760405162461bcd60e51b815260206004820152602160248201527f7472616e73666572416e6443616c6c2072657175657374206e6f742076616c6960448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a9d565b61180386868686866121ef565b9695505050505050565b6001546001600160a01b0316331461182457600080fd5b61184e7f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f826109b2565b6040516001600160a01b038216907fdfb5b1167ef9eadf5cac67570f1a2971a6f6175303b9d4166a65a11d0a294e3490600090a250565b6001546001600160a01b0316331461189c57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b50505050565b60008281526020819052604090206001015461192181611efa565b6109d78383612166565b6003546040517f1045d7ce0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015283821660248201529082166044820152600090731d94e102e1c7a2cab9ba6d6d344d34d023628bd390631045d7ce90606401602060405180830381865af41580156119b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d79190612a34565b9392505050565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038085166024830152831660448201526064810182905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190612a7a565b611abf5760405162461bcd60e51b815260206004820152601a60248201527f7472616e736665722072657175657374206e6f742076616c69640000000000006044820152606401610a9d565b6113e78484846122b2565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038085166024830152831660448201526064810182905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5f9190612a7a565b611bab5760405162461bcd60e51b815260206004820152601e60248201527f7472616e7366657246726f6d2072657175657374206e6f742076616c696400006044820152606401610a9d565b611bb785858585612343565b95945050505050565b6001546001600160a01b03163314611bd757600080fd5b611c017f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f82611906565b6040516001600160a01b038216907f21bfb3de07221bc6197a8c23f7a059308b7a741f259cf4ef3b519cde0fde7ac390600090a250565b6001546001600160a01b03163314611c4f57600080fd5b6003546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015611caf57600080fd5b505af11580156108eb573d6000803e3d6000fd5b3360009081527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611d675760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420616e2061646d60448201527f696e206163636f756e74000000000000000000000000000000000000000000006064820152608401610a9d565b600854811115611ddf5760405162461bcd60e51b815260206004820152603d60248201527f4d696e7461626c65436f6e74726f6c6c65723a20616c6c6f77616e636520657860448201527f6365656473206d6178696d756d20736574746564206279206f776e65720000006064820152608401610a9d565b6001600160a01b03821660008181526007602052604090819020839055517f8fe74a1bbab5a9534a04463cd7b9423b985ed316426821cace8ed4aeac5a4d1490611e2c9084815260200190565b60405180910390a25050565b6001546001600160a01b03163314611e4f57600080fd5b6002546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314611ec257600080fd5b6040518181527f34affbf2a21d1f1d12e5e49bdca58fb75dba6879f5430f2fbf5c1d07476018d29060200160405180910390a1600855565b611f048133612418565b50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610d40576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611f613390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116611ffb5760405162461bcd60e51b815260206004820152601460248201527f6d757374206e6f742073656e6420746f203078300000000000000000000000006044820152606401610a9d565b6001600160a01b0381163014156120545760405162461bcd60e51b815260206004820152601b60248201527f6d757374206e6f742073656e6420746f20636f6e74726f6c6c657200000000006044820152606401610a9d565b6003546001600160a01b03828116911614156120b25760405162461bcd60e51b815260206004820152601e60248201527f6d757374206e6f742073656e6420746f20746f6b656e2073746f7261676500006044820152606401610a9d565b6004546001600160a01b03828116911614156121105760405162461bcd60e51b815260206004820152601960248201527f6d757374206e6f742073656e6420746f2066726f6e74656e64000000000000006044820152606401610a9d565b61211981610979565b15611f045760405162461bcd60e51b815260206004820181905260248201527f6d757374206e6f742073656e6420746f2062726964676546726f6e74656e64736044820152606401610a9d565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610d40576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610d408282611f07565b60006121fa33610979565b61220357600080fd5b61220c85611fa5565b6003546040517f1eb8bccb00000000000000000000000000000000000000000000000000000000815273e74b37a54e8ae26d8c6c50830804f689888ef9a091631eb8bccb91612271916001600160a01b0316908a908a908a908a908a90600401612aac565b602060405180830381865af415801561228e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118039190612a7a565b60006122bd33610979565b6122c657600080fd5b6122cf83611fa5565b6003546040517f44ded8ba0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201528582166024820152908416604482015260648101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd3906344ded8ba906084016113a6565b600061234e33610979565b61235757600080fd5b61236083611fa5565b6003546040517ff3a0ddf90000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015286821660248201528582166044820152908416606482015260848101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd39063f3a0ddf99060a401602060405180830381865af41580156123f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb79190612a7a565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610d40576124498161248b565b61245483602061249d565b604051602001612465929190612b35565b60408051601f198184030181529082905262461bcd60e51b8252610a9d91600401612bb6565b60606107b26001600160a01b03831660145b606060006124ac836002612be9565b6124b7906002612c08565b67ffffffffffffffff8111156124cf576124cf612c20565b6040519080825280601f01601f1916602001820160405280156124f9576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061253057612530612c36565b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061257b5761257b612c36565b60200101906001600160f81b031916908160001a905350600061259f846002612be9565b6125aa906001612c08565b90505b600181111561262f577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106125eb576125eb612c36565b1a60f81b82828151811061260157612601612c36565b60200101906001600160f81b031916908160001a90535060049490941c9361262881612c4c565b90506125ad565b5083156119d75760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a9d565b60006020828403121561269057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146119d757600080fd5b6001600160a01b0381168114611f0457600080fd5b6000602082840312156126e757600080fd5b81356119d7816126c0565b60006020828403121561270457600080fd5b5035919050565b6000806040838503121561271e57600080fd5b823591506020830135612730816126c0565b809150509250929050565b60008060006060848603121561275057600080fd5b833561275b816126c0565b9250602084013561276b816126c0565b929592945050506040919091013590565b803560ff8116811461278d57600080fd5b919050565b600080600080600080600060e0888a0312156127ad57600080fd5b87356127b8816126c0565b965060208801356127c8816126c0565b955060408801356127d8816126c0565b9450606088013593506127ed6080890161277c565b925060a0880135915060c0880135905092959891949750929550565b600080600080600080600060e0888a03121561282457600080fd5b873561282f816126c0565b9650602088013561283f816126c0565b955060408801359450606088013593506127ed6080890161277c565b6000806040838503121561286e57600080fd5b8235612879816126c0565b946020939093013593505050565b60008083601f84011261289957600080fd5b50813567ffffffffffffffff8111156128b157600080fd5b6020830191508360208285010111156128c957600080fd5b9250929050565b6000806000604084860312156128e557600080fd5b83356128f0816126c0565b9250602084013567ffffffffffffffff81111561290c57600080fd5b61291886828701612887565b9497909650939450505050565b60008060008060006080868803121561293d57600080fd5b8535612948816126c0565b94506020860135612958816126c0565b935060408601359250606086013567ffffffffffffffff81111561297b57600080fd5b61298788828901612887565b969995985093965092949392505050565b600080604083850312156129ab57600080fd5b82356129b6816126c0565b91506020830135612730816126c0565b600080600080608085870312156129dc57600080fd5b84356129e7816126c0565b935060208501356129f7816126c0565b92506040850135612a07816126c0565b9396929550929360600135925050565b600060208284031215612a2957600080fd5b81516119d7816126c0565b600060208284031215612a4657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082821015612a7557612a75612a4d565b500390565b600060208284031215612a8c57600080fd5b815180151581146119d757600080fd5b8183823760009101908152919050565b60006001600160a01b038089168352808816602084015280871660408401525084606083015260a060808301528260a0830152828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60005b83811015612b24578181015183820152602001612b0c565b838111156119005750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612b6d816017850160208801612b09565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612baa816028840160208801612b09565b01602801949350505050565b6020815260008251806020840152612bd5816040850160208701612b09565b601f01601f19169190910160400192915050565b6000816000190483118215151615612c0357612c03612a4d565b500290565b60008219821115612c1b57612c1b612a4d565b500190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081612c5b57612c5b612a4d565b50600019019056fea2646970667358221220440686b156ac6a64c9b87b2366b5617a8d4b3945365accdb6737e8a5ec19647664736f6c634300080b0033608060405234801561001057600080fd5b50600080546001600160a01b03191633179055341561002e57600080fd5b610ada8061003d6000396000f3fe608060405234801561001057600080fd5b50600436106100e15760003560e01c80639f727c2711610086578063cf8eeb7e11610063578063cf8eeb7e146101ab578063e30c3978146101be578063f2fde38b146101d1578063f8b2cb4f146101e457005b80639f727c271461017d578063c0ee0b8a14610185578063c7c7e9ea1461019857005b806333dd1b8a116100bf57806333dd1b8a1461011c5780634e71e0c81461012f5780636c9c2faf146101375780638da5cb5b1461015257005b806317ffc320146100e357806321e5383a146100f65780632aed7f3f14610109575b005b6100e16100f136600461091d565b6101f7565b6100e161010436600461093a565b6102b3565b6100e161011736600461091d565b610361565b6100e161012a366004610966565b6103ed565b6100e16104a3565b61013f61052b565b6040519081526020015b60405180910390f35b600054610165906001600160a01b031681565b6040516001600160a01b039091168152602001610149565b6100e16105c0565b6100e16101933660046109a7565b600080fd5b61013f6101a6366004610a30565b610614565b6100e16101b936600461093a565b6106c2565b600154610165906001600160a01b031681565b6100e16101df36600461091d565b610740565b61013f6101f236600461091d565b610749565b6000546001600160a01b0316331461020e57600080fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102929190610a69565b6000549091506102af906001600160a01b038481169116836107ee565b5050565b6000546001600160a01b031633146102ca57600080fd5b6040517f7aeb0ed5000000000000000000000000000000000000000000000000000000008152600260048201526001600160a01b0383166024820152604481018290527366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc90637aeb0ed5906064015b60006040518083038186803b15801561034557600080fd5b505af4158015610359573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461037857600080fd5b6000546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152829182169063f2fde38b90602401600060405180830381600087803b1580156103d957600080fd5b505af1158015610359573d6000803e3d6000fd5b6000546001600160a01b0316331461040457600080fd5b6040517f5599b4b7000000000000000000000000000000000000000000000000000000008152600260048201526001600160a01b03808516602483015283166044820152606481018290527366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc90635599b4b79060840160006040518083038186803b15801561048657600080fd5b505af415801561049a573d6000803e3d6000fd5b50505050505050565b6001546001600160a01b031633146104ba57600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600180546000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b03841617909155169055565b6040517f072f9a50000000000000000000000000000000000000000000000000000000008152600260048201526000907366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc9063072f9a5090602401602060405180830381865af4158015610597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bb9190610a69565b905090565b6000546001600160a01b031633146105d757600080fd5b600080546040516001600160a01b03909116914780156108fc02929091818181858888f19350505050158015610611573d6000803e3d6000fd5b50565b6040517f9daeae1e000000000000000000000000000000000000000000000000000000008152600260048201526001600160a01b038084166024830152821660448201526000907366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc90639daeae1e90606401602060405180830381865af4158015610697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bb9190610a69565b9392505050565b6000546001600160a01b031633146106d957600080fd5b6040517fd9c7339e000000000000000000000000000000000000000000000000000000008152600260048201526001600160a01b0383166024820152604481018290527366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc9063d9c7339e9060640161032d565b61061181610888565b6040517fb0aacf24000000000000000000000000000000000000000000000000000000008152600260048201526001600160a01b03821660248201526000907366c121c0d400e57ef1ec453b72f7ecfa7c77e1dc9063b0aacf2490604401602060405180830381865af41580156107c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e89190610a69565b92915050565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301526024820183905284169063a9059cbb906044016020604051808303816000875af1158015610856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087a9190610a82565b61088357600080fd5b505050565b6000546001600160a01b0316331461089f57600080fd5b6001546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a36001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6001600160a01b038116811461061157600080fd5b60006020828403121561092f57600080fd5b81356106bb81610908565b6000806040838503121561094d57600080fd5b823561095881610908565b946020939093013593505050565b60008060006060848603121561097b57600080fd5b833561098681610908565b9250602084013561099681610908565b929592945050506040919091013590565b600080600080606085870312156109bd57600080fd5b84356109c881610908565b935060208501359250604085013567ffffffffffffffff808211156109ec57600080fd5b818701915087601f830112610a0057600080fd5b813581811115610a0f57600080fd5b886020828501011115610a2157600080fd5b95989497505060200194505050565b60008060408385031215610a4357600080fd5b8235610a4e81610908565b91506020830135610a5e81610908565b809150509250929050565b600060208284031215610a7b57600080fd5b5051919050565b600060208284031215610a9457600080fd5b815180151581146106bb57600080fdfea2646970667358221220e51bdfea16490038892f8feb2068851f6ae531d935e40110b020c2e80aafd7c664736f6c634300080b0033000000000000000000000000455bc1d1528108b51bbbd7a9542ba6cc10e6a33c0000000000000000000000003fe4db892b4572a24b4431ef5742a88ef68ff5414555520000000000000000000000000000000000000000000000000000000000000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103145760003560e01c806375b238fc116101a7578063a84c56d0116100ee578063e974fee911610097578063f27c5f6e11610071578063f27c5f6e146106e6578063f2fde38b146106f9578063fd2319c41461070c57600080fd5b8063e974fee9146106ad578063ebbc3d46146106c0578063ee0b5445146106d357600080fd5b8063dd62ed3e116100c8578063dd62ed3e14610674578063e174fd9414610687578063e30c39781461069a57600080fd5b8063a84c56d014610646578063b516af7014610659578063d547741f1461066157600080fd5b80638fb81d98116101505780639e7f43ca1161012a5780639e7f43ca1461062b5780639ea33e191461063e578063a217fddf146103e257600080fd5b80638fb81d98146105ce5780639137c1a7146105e157806391d14854146105f457600080fd5b8063802d441f11610181578063802d441f1461056a5780638ba47bdd1461057d5780638da5cb5b146105bb57600080fd5b806375b238fc1461051d578063774d54091461054457806379cc67901461055757600080fd5b8063326ecb051161026b5780634eb007541161021457806369569a51116101ee57806369569a51146104d057806370a08231146104e357806375071d2a146104f657600080fd5b80634eb00754146104975780634fe57e7a146104aa57806367a89a72146104bd57600080fd5b80633cd1570f116102455780633cd1570f146104535780634a36703b146104665780634e71e0c81461048f57600080fd5b8063326ecb051461041c5780633408f73a1461042f57806336568abe1461044057600080fd5b8063248a9ca3116102cd5780632ff2e9dc116102a75780632ff2e9dc146103e2578063313ce567146103ea578063322ec0fb1461040957600080fd5b8063248a9ca31461039957806325ec2eb0146103bc5780632f2ff15d146103cf57600080fd5b80631195e07e116102fe5780631195e07e146103665780631327d3d81461036e57806318160ddd1461038357600080fd5b80623074ff1461031957806301ffc9a714610343575b600080fd5b6004546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b61035661035136600461267e565b61071f565b604051901515815260200161033a565b6103266107b8565b61038161037c3660046126d5565b61084d565b005b61038b6108f2565b60405190815260200161033a565b61038b6103a73660046126f2565b60009081526020819052604090206001015490565b6103566103ca3660046126d5565b610979565b6103816103dd36600461270b565b6109b2565b61038b600081565b6006546103f79060ff1681565b60405160ff909116815260200161033a565b61035661041736600461273b565b6109dc565b61035661042a3660046126d5565b610c78565b6003546001600160a01b0316610326565b61038161044e36600461270b565b610cb8565b61038b610461366004612792565b610d44565b61038b6104743660046126d5565b6001600160a01b031660009081526007602052604090205490565b610381610ed1565b6103566104a5366004612809565b610f66565b6103816104b83660046126d5565b611137565b6103816104cb3660046126d5565b6111af565b6103816104de3660046126d5565b611227565b61038b6104f13660046126d5565b61129a565b61038b7f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f81565b61038b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61035661055236600461273b565b611322565b61035661056536600461285b565b6113ef565b6103816105783660046126d5565b611592565b600a5461058a9060e81b81565b6040517fffffff0000000000000000000000000000000000000000000000000000000000909116815260200161033a565b600154610326906001600160a01b031681565b6103816105dc3660046128d0565b6115f2565b6103816105ef3660046126d5565b61167c565b61035661060236600461270b565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b610356610639366004612925565b6116ef565b60085461038b565b6103816106543660046126d5565b61180d565b610381611885565b61038161066f36600461270b565b611906565b61038b610682366004612998565b61192b565b61035661069536600461273b565b6119de565b600254610326906001600160a01b031681565b6103566106bb3660046129c6565b611aca565b6103816106ce3660046126d5565b611bc0565b6103816106e13660046126d5565b611c38565b6103816106f436600461285b565b611cc3565b6103816107073660046126d5565b611e38565b61038161071a3660046126f2565b611eab565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107b257507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040517f6271970c0000000000000000000000000000000000000000000000000000000081526009600482015260009073ceb6728300915d56ac58fc99b4becc01a630ed8a90636271970c90602401602060405180830381865af4158015610824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190612a17565b905090565b6001546001600160a01b0316331461086457600080fd5b6040517fad415349000000000000000000000000000000000000000000000000000000008152600960048201526001600160a01b038216602482015273ceb6728300915d56ac58fc99b4becc01a630ed8a9063ad4153499060440160006040518083038186803b1580156108d757600080fd5b505af41580156108eb573d6000803e3d6000fd5b5050505050565b600354604080517f6c9c2faf00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691636c9c2faf9160048083019260209291908290030181865afa158015610955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108489190612a34565b6004546000906001600160a01b03838116911614806107b25750506001600160a01b031660009081526005602052604090205460ff1690565b6000828152602081905260409020600101546109cd81611efa565b6109d78383611f07565b505050565b60006109e733610979565b6109f057600080fd5b6001600160a01b03841660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe60205260409020548490839060ff16610aa65760405162461bcd60e51b815260206004820152603260248201527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420612073797374656d206163636f756e74000000000000000000000000000060648201526084015b60405180910390fd5b6001600160a01b038216600090815260076020526040902054811115610b36576040805162461bcd60e51b81526020600482015260248101919091527f4d696e7461626c65436f6e74726f6c6c65723a2063616c6c6572206973206e6f60448201527f7420616c6c6f77656420746f20706572666f726d207468697320616374696f6e6064820152608401610a9d565b610b3f85611fa5565b6001600160a01b038616600090815260076020526040902054610b63908590612a63565b6001600160a01b03878116600090815260076020526040908190209290925560035491517fb0c29c7400000000000000000000000000000000000000000000000000000000815291811660048301528616602482015260448101859052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063b0c29c7490606401602060405180830381865af4158015610bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c209190612a7a565b610c6c5760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206d696e74206661696c6564006044820152606401610a9d565b50600195945050505050565b6001600160a01b03811660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe602052604081205460ff166107b2565b6001600160a01b0381163314610d365760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a9d565b610d408282612166565b5050565b6000610d4f33610979565b610d5857600080fd5b6001600160a01b03881660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe6020526040902054889060ff16610df45760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b610dfd87611fa5565b6003546040517f8f7227340000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152898216602482015290881660448201526064810187905260ff8616608482015260a4810185905260c4810184905273ceb6728300915d56ac58fc99b4becc01a630ed8a90638f7227349060e401602060405180830381865af4158015610ea0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec49190612a34565b9998505050505050505050565b6002546001600160a01b03163314610ee857600080fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600254600180546001600160a01b0319166001600160a01b039092169182179055610f54906000906121e5565b600280546001600160a01b0319169055565b6000610f7133610979565b610f7a57600080fd5b6001600160a01b03881660009081527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe6020526040902054889060ff166110165760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b6003546040517f799639d40000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201529089166024820152604481018890526064810187905260ff8616608482015260a4810185905260c48101849052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063799639d49060e401602060405180830381865af41580156110b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110dc9190612a7a565b6111285760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610a9d565b50600198975050505050505050565b6001546001600160a01b0316331461114e57600080fd5b6111787fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775826109b2565b6040516001600160a01b038216907f5c7eb798b922f0164aa9c5340006161c64436190a49eebc58b4e6e0715700ae690600090a250565b6001546001600160a01b031633146111c657600080fd5b6111f07fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177582611906565b6040516001600160a01b038216907fc3198db98a2c50068f0a99b9297e60b2dbf0eafcde57e366e70a29f887c44e1090600090a250565b6001546001600160a01b0316331461123e57600080fd5b6004546040516001600160a01b038084169216907fcb01f884fc4203d4c1643cb0e126faeb397682c122ca8c0433776d42cdc0060a90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040517ff8b2cb4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152600092169063f8b2cb4f90602401602060405180830381865afa1580156112fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b29190612a34565b600061132d33610979565b61133657600080fd5b6003546040517f365feff10000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201528582166024820152908416604482015260648101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd39063365feff1906084015b602060405180830381865af41580156113c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e79190612a7a565b949350505050565b60006113fa33610979565b61140357600080fd5b3360008181527f1feb9b335997de56b08b04054f0301e3df87667f2dfed59b0299f6d9a067ecbe602052604090205460ff166114945760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420612073797374604482015269195b481858d8dbdd5b9d60b21b6064820152608401610a9d565b6003546040517fa6c9ac280000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152908516602482015260448101849052731007a6c78354f0c0033d1f96bb7b6b76402af3de9063a6c9ac2890606401602060405180830381865af4158015611518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153c9190612a7a565b6115885760405162461bcd60e51b815260206004820152601f60248201527f4d696e7461626c65436f6e74726f6c6c65723a206275726e206661696c6564006044820152606401610a9d565b5060019392505050565b6001546001600160a01b031633146115a957600080fd5b6001600160a01b038116600081815260056020526040808220805460ff19169055517f10cf5a523a14a54e61c21610dc10c01e40e2ebc37baa3effd74032f7d3865e6d9190a250565b6001546001600160a01b0316331461160957600080fd5b6001600160a01b03831660009081526005602052604090819020805460ff191660011790555161163c9083908390612a9c565b604051908190038120906001600160a01b038516907fec75908259de4d038ff5f2b6b99e3725bc21871f4d2a44adeff9bb814afbc9f790600090a3505050565b6001546001600160a01b0316331461169357600080fd5b6003546040516001600160a01b038084169216907fdaaa9d417a3107fd3d9db02eba3eeafbae2b8af16ee08c534f5bc449054c1c4c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038087166024830152851660448201526064810184905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611760573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117849190612a7a565b6117f65760405162461bcd60e51b815260206004820152602160248201527f7472616e73666572416e6443616c6c2072657175657374206e6f742076616c6960448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a9d565b61180386868686866121ef565b9695505050505050565b6001546001600160a01b0316331461182457600080fd5b61184e7f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f826109b2565b6040516001600160a01b038216907fdfb5b1167ef9eadf5cac67570f1a2971a6f6175303b9d4166a65a11d0a294e3490600090a250565b6001546001600160a01b0316331461189c57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b0316634e71e0c86040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b50505050565b60008281526020819052604090206001015461192181611efa565b6109d78383612166565b6003546040517f1045d7ce0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015283821660248201529082166044820152600090731d94e102e1c7a2cab9ba6d6d344d34d023628bd390631045d7ce90606401602060405180830381865af41580156119b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d79190612a34565b9392505050565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038085166024830152831660448201526064810182905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190612a7a565b611abf5760405162461bcd60e51b815260206004820152601a60248201527f7472616e736665722072657175657374206e6f742076616c69640000000000006044820152606401610a9d565b6113e78484846122b2565b6040516332c5a6eb60e01b8152600960048201526001600160a01b038085166024830152831660448201526064810182905260009073ceb6728300915d56ac58fc99b4becc01a630ed8a906332c5a6eb90608401602060405180830381865af4158015611b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5f9190612a7a565b611bab5760405162461bcd60e51b815260206004820152601e60248201527f7472616e7366657246726f6d2072657175657374206e6f742076616c696400006044820152606401610a9d565b611bb785858585612343565b95945050505050565b6001546001600160a01b03163314611bd757600080fd5b611c017f5719df9ef2c4678b547f89e4f5ae410dbf400fc51cf3ded434c55f6adea2c43f82611906565b6040516001600160a01b038216907f21bfb3de07221bc6197a8c23f7a059308b7a741f259cf4ef3b519cde0fde7ac390600090a250565b6001546001600160a01b03163314611c4f57600080fd5b6003546040517ff2fde38b0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301529091169063f2fde38b90602401600060405180830381600087803b158015611caf57600080fd5b505af11580156108eb573d6000803e3d6000fd5b3360009081527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611d675760405162461bcd60e51b815260206004820152602a60248201527f53797374656d526f6c653a2063616c6c6572206973206e6f7420616e2061646d60448201527f696e206163636f756e74000000000000000000000000000000000000000000006064820152608401610a9d565b600854811115611ddf5760405162461bcd60e51b815260206004820152603d60248201527f4d696e7461626c65436f6e74726f6c6c65723a20616c6c6f77616e636520657860448201527f6365656473206d6178696d756d20736574746564206279206f776e65720000006064820152608401610a9d565b6001600160a01b03821660008181526007602052604090819020839055517f8fe74a1bbab5a9534a04463cd7b9423b985ed316426821cace8ed4aeac5a4d1490611e2c9084815260200190565b60405180910390a25050565b6001546001600160a01b03163314611e4f57600080fd5b6002546040516001600160a01b038084169216907f8573d4aae9f7fb051c6b88d7440011a1c12376acda6603a45f45bad36a8db4ce90600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314611ec257600080fd5b6040518181527f34affbf2a21d1f1d12e5e49bdca58fb75dba6879f5430f2fbf5c1d07476018d29060200160405180910390a1600855565b611f048133612418565b50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610d40576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611f613390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b038116611ffb5760405162461bcd60e51b815260206004820152601460248201527f6d757374206e6f742073656e6420746f203078300000000000000000000000006044820152606401610a9d565b6001600160a01b0381163014156120545760405162461bcd60e51b815260206004820152601b60248201527f6d757374206e6f742073656e6420746f20636f6e74726f6c6c657200000000006044820152606401610a9d565b6003546001600160a01b03828116911614156120b25760405162461bcd60e51b815260206004820152601e60248201527f6d757374206e6f742073656e6420746f20746f6b656e2073746f7261676500006044820152606401610a9d565b6004546001600160a01b03828116911614156121105760405162461bcd60e51b815260206004820152601960248201527f6d757374206e6f742073656e6420746f2066726f6e74656e64000000000000006044820152606401610a9d565b61211981610979565b15611f045760405162461bcd60e51b815260206004820181905260248201527f6d757374206e6f742073656e6420746f2062726964676546726f6e74656e64736044820152606401610a9d565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610d40576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610d408282611f07565b60006121fa33610979565b61220357600080fd5b61220c85611fa5565b6003546040517f1eb8bccb00000000000000000000000000000000000000000000000000000000815273e74b37a54e8ae26d8c6c50830804f689888ef9a091631eb8bccb91612271916001600160a01b0316908a908a908a908a908a90600401612aac565b602060405180830381865af415801561228e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118039190612a7a565b60006122bd33610979565b6122c657600080fd5b6122cf83611fa5565b6003546040517f44ded8ba0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201528582166024820152908416604482015260648101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd3906344ded8ba906084016113a6565b600061234e33610979565b61235757600080fd5b61236083611fa5565b6003546040517ff3a0ddf90000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015286821660248201528582166044820152908416606482015260848101839052731d94e102e1c7a2cab9ba6d6d344d34d023628bd39063f3a0ddf99060a401602060405180830381865af41580156123f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb79190612a7a565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610d40576124498161248b565b61245483602061249d565b604051602001612465929190612b35565b60408051601f198184030181529082905262461bcd60e51b8252610a9d91600401612bb6565b60606107b26001600160a01b03831660145b606060006124ac836002612be9565b6124b7906002612c08565b67ffffffffffffffff8111156124cf576124cf612c20565b6040519080825280601f01601f1916602001820160405280156124f9576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061253057612530612c36565b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061257b5761257b612c36565b60200101906001600160f81b031916908160001a905350600061259f846002612be9565b6125aa906001612c08565b90505b600181111561262f577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106125eb576125eb612c36565b1a60f81b82828151811061260157612601612c36565b60200101906001600160f81b031916908160001a90535060049490941c9361262881612c4c565b90506125ad565b5083156119d75760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a9d565b60006020828403121561269057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146119d757600080fd5b6001600160a01b0381168114611f0457600080fd5b6000602082840312156126e757600080fd5b81356119d7816126c0565b60006020828403121561270457600080fd5b5035919050565b6000806040838503121561271e57600080fd5b823591506020830135612730816126c0565b809150509250929050565b60008060006060848603121561275057600080fd5b833561275b816126c0565b9250602084013561276b816126c0565b929592945050506040919091013590565b803560ff8116811461278d57600080fd5b919050565b600080600080600080600060e0888a0312156127ad57600080fd5b87356127b8816126c0565b965060208801356127c8816126c0565b955060408801356127d8816126c0565b9450606088013593506127ed6080890161277c565b925060a0880135915060c0880135905092959891949750929550565b600080600080600080600060e0888a03121561282457600080fd5b873561282f816126c0565b9650602088013561283f816126c0565b955060408801359450606088013593506127ed6080890161277c565b6000806040838503121561286e57600080fd5b8235612879816126c0565b946020939093013593505050565b60008083601f84011261289957600080fd5b50813567ffffffffffffffff8111156128b157600080fd5b6020830191508360208285010111156128c957600080fd5b9250929050565b6000806000604084860312156128e557600080fd5b83356128f0816126c0565b9250602084013567ffffffffffffffff81111561290c57600080fd5b61291886828701612887565b9497909650939450505050565b60008060008060006080868803121561293d57600080fd5b8535612948816126c0565b94506020860135612958816126c0565b935060408601359250606086013567ffffffffffffffff81111561297b57600080fd5b61298788828901612887565b969995985093965092949392505050565b600080604083850312156129ab57600080fd5b82356129b6816126c0565b91506020830135612730816126c0565b600080600080608085870312156129dc57600080fd5b84356129e7816126c0565b935060208501356129f7816126c0565b92506040850135612a07816126c0565b9396929550929360600135925050565b600060208284031215612a2957600080fd5b81516119d7816126c0565b600060208284031215612a4657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082821015612a7557612a75612a4d565b500390565b600060208284031215612a8c57600080fd5b815180151581146119d757600080fd5b8183823760009101908152919050565b60006001600160a01b038089168352808816602084015280871660408401525084606083015260a060808301528260a0830152828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60005b83811015612b24578181015183820152602001612b0c565b838111156119005750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612b6d816017850160208801612b09565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612baa816028840160208801612b09565b01602801949350505050565b6020815260008251806020840152612bd5816040850160208701612b09565b601f01601f19169190910160400192915050565b6000816000190483118215151615612c0357612c03612a4d565b500290565b60008219821115612c1b57612c1b612a4d565b500190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081612c5b57612c5b612a4d565b50600019019056fea2646970667358221220440686b156ac6a64c9b87b2366b5617a8d4b3945365accdb6737e8a5ec19647664736f6c634300080b0033

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

000000000000000000000000455bc1d1528108b51bbbd7a9542ba6cc10e6a33c0000000000000000000000003fe4db892b4572a24b4431ef5742a88ef68ff5414555520000000000000000000000000000000000000000000000000000000000000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e

-----Decoded View---------------
Arg [0] : storage_ (address): 0x455bC1d1528108b51bBbd7A9542Ba6cC10e6A33C
Arg [1] : validator (address): 0x3fe4dB892b4572A24B4431ef5742A88EF68FF541
Arg [2] : ticker_ (bytes3): 0x455552
Arg [3] : frontend_ (address): 0xcB444e90D8198415266c6a2724b7900fb12FC56E

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000455bc1d1528108b51bbbd7a9542ba6cc10e6a33c
Arg [1] : 0000000000000000000000003fe4db892b4572a24b4431ef5742a88ef68ff541
Arg [2] : 4555520000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000cb444e90d8198415266c6a2724b7900fb12fc56e


Deployed Bytecode Sourcemap

891:5009:27:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3921:87:29;3993:8;;-1:-1:-1;;;;;3993:8:29;3921:87;;;-1:-1:-1;;;;;178:55:34;;;160:74;;148:2;133:18;3921:87:29;;;;;;;;2571:202:0;;;;;;:::i;:::-;;:::i;:::-;;;747:14:34;;740:22;722:41;;710:2;695:18;2571:202:0;582:187:34;5793:105:27;;;:::i;1880:111::-;;;;;;:::i;:::-;;:::i;:::-;;8693:93:29;;;:::i;:::-;;;1331:25:34;;;1319:2;1304:18;8693:93:29;1185:177:34;4343:129:0;;;;;;:::i;:::-;4417:7;4443:12;;;;;;;;;;:22;;;;4343:129;5257:143:29;;;;;;:::i;:::-;;:::i;4768:145:0:-;;;;;;:::i;:::-;;:::i;1080:42:27:-;;1121:1;1080:42;;1310:26:29;;;;;;;;;;;;2226:4:34;2214:17;;;2196:36;;2184:2;2169:18;1310:26:29;2054:184:34;2701:413:21;;;;;;:::i;:::-;;:::i;3217:122:31:-;;;;;;:::i;:::-;;:::i;4110:92:29:-;4189:5;;-1:-1:-1;;;;;4189:5:29;4110:92;;5877:214:0;;;;;;:::i;:::-;;:::i;2748:341:27:-;;;;;;:::i;:::-;;:::i;5576:142:21:-;;;;;;:::i;:::-;-1:-1:-1;;;;;5688:23:21;5662:7;5688:23;;;:14;:23;;;;;;;5576:142;1313:225:4;;;:::i;3562:392:21:-;;;;;;:::i;:::-;;:::i;3975:155:31:-;;;;;;:::i;:::-;;:::i;4236:161::-;;;;;;:::i;:::-;;:::i;4310:138:29:-;;;;;;:::i;:::-;;:::i;8946:106::-;;;;;;:::i;:::-;;:::i;1133:62:31:-;;1171:24;1133:62;;1067:60;;1104:23;1067:60;;7665:207:29;;;;;;:::i;:::-;;:::i;4169:241:21:-;;;;;;:::i;:::-;;:::i;4960:164:29:-;;;;;;:::i;:::-;;:::i;1054:20:27:-;;;;;;;;;;;;4910:66:34;4898:79;;;4880:98;;4868:2;4853:18;1054:20:27;4736:248:34;270:20:24;;;;;-1:-1:-1;;;;;270:20:24;;;4628:205:29;;;;;;:::i;:::-;;:::i;5505:152::-;;;;;;:::i;:::-;;:::i;2860:145:0:-;;;;;;:::i;:::-;2946:4;2969:12;;;;;;;;;;;-1:-1:-1;;;;;2969:29:0;;;;;;;;;;;;;;;2860:145;5313:381:27;;;;;;:::i;:::-;;:::i;4801:109:21:-;4887:16;;4801:109;;3443:158:31;;;;;;:::i;:::-;;:::i;5978:89:29:-;;;:::i;5193:147:0:-;;;;;;:::i;:::-;;:::i;9297:157:29:-;;;;;;:::i;:::-;;:::i;3500:325:27:-;;;;;;:::i;:::-;;:::i;322:27:4:-;;;;;-1:-1:-1;;;;;322:27:4;;;4383:363:27;;;;;;:::i;:::-;;:::i;3708:164:31:-;;;;;;:::i;:::-;;:::i;5788:119:29:-;;;;;;:::i;:::-;;:::i;5070:352:21:-;;;;;;:::i;:::-;;:::i;1025:196:4:-;;;;;;:::i;:::-;;:::i;4533:151:21:-;;;;;;:::i;:::-;;:::i;2571:202:0:-;2656:4;2679:47;;;2694:32;2679:47;;:87;;-1:-1:-1;952:25:7;937:40;;;;2730:36:0;2672:94;2571:202;-1:-1:-1;;2571:202:0:o;5793:105:27:-;5866:25;;;;;:10;:25;;;1331::34;5840:7:27;;5866:23;;;;1304:18:34;;5866:25:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5859:32;;5793:105;:::o;1880:111::-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;1950:34:27::1;::::0;;;;:10:::1;:34;::::0;::::1;8524:25:34::0;-1:-1:-1;;;;;8585:55:34;;8565:18;;;8558:83;1950:23:27::1;::::0;::::1;::::0;8497:18:34;;1950:34:27::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;1880:111:::0;:::o;8693:93:29:-;8762:5;;:17;;;;;;;;8739:4;;-1:-1:-1;;;;;8762:5:29;;:15;;:17;;;;;;;;;;;;;;:5;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;5257:143::-;5354:8;;5317:4;;-1:-1:-1;;;;;5341:21:29;;;5354:8;;5341:21;;5340:53;;-1:-1:-1;;;;;;;5367:26:29;;;;;:15;:26;;;;;;;;;5257:143::o;4768:145:0:-;4417:7;4443:12;;;;;;;;;;:22;;;2470:16;2481:4;2470:10;:16::i;:::-;4881:25:::1;4892:4;4898:7;4881:10;:25::i;:::-;4768:145:::0;;;:::o;2701:413:21:-;2904:4;2456:22:29;2467:10;2456;:22::i;:::-;2448:31;;;;;;-1:-1:-1;;;;;2969:29:0;;2946:4;2969:29;;;:12;;:29;:12;:29;;;2871:6:21;;2879;;2969:29:0;;2185:126:21::1;;;::::0;-1:-1:-1;;;2185:126:21;;9043:2:34;2185:126:21::1;::::0;::::1;9025:21:34::0;9082:2;9062:18;;;9055:30;9121:34;9101:18;;;9094:62;9192:20;9172:18;;;9165:48;9230:19;;2185:126:21::1;;;;;;;;;-1:-1:-1::0;;;;;2342:23:21;::::1;;::::0;;;:14:::1;:23;::::0;;;;;:33;-1:-1:-1;2342:33:21::1;2321:144;;;::::0;;-1:-1:-1;;;2321:144:21;;9462:2:34;2321:144:21::1;::::0;::::1;9444:21:34::0;9481:18;;;9474:30;;;;9540:34;9520:18;;;9513:62;9611:34;9591:18;;;9584:62;9663:19;;2321:144:21::1;9260:428:34::0;2321:144:21::1;2924:20:::2;2941:2;2924:16;:20::i;:::-;-1:-1:-1::0;;;;;2979:22:21;::::2;;::::0;;;:14:::2;:22;::::0;;;;;:31:::2;::::0;3004:6;;2979:31:::2;:::i;:::-;-1:-1:-1::0;;;;;2954:22:21;;::::2;;::::0;;;:14:::2;:22;::::0;;;;;;:56;;;;3028:5:::2;::::0;:22;;;;;:5;;::::2;:22;::::0;::::2;10304:34:34::0;10374:15;;10354:18;;;10347:43;10406:18;;;10399:34;;;3028:10:21::2;::::0;::::2;::::0;10216:18:34;;3028:22:21::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3020:66;;;::::0;-1:-1:-1;;;3020:66:21;;10928:2:34;3020:66:21::2;::::0;::::2;10910:21:34::0;10967:2;10947:18;;;10940:30;11006:33;10986:18;;;10979:61;11057:18;;3020:66:21::2;10726:355:34::0;3020:66:21::2;-1:-1:-1::0;3103:4:21::2;::::0;2701:413;-1:-1:-1;;;;;2701:413:21:o;3217:122:31:-;-1:-1:-1;;;;;2969:29:0;;3280:4:31;2969:29:0;;;:12;;:29;:12;:29;;;;;3303::31;2860:145:0;5877:214;-1:-1:-1;;;;;5972:23:0;;719:10:5;5972:23:0;5964:83;;;;-1:-1:-1;;;5964:83:0;;11288:2:34;5964:83:0;;;11270:21:34;11327:2;11307:18;;;11300:30;11366:34;11346:18;;;11339:62;11437:17;11417:18;;;11410:45;11472:19;;5964:83:0;11086:411:34;5964:83:0;6058:26;6070:4;6076:7;6058:11;:26::i;:::-;5877:214;;:::o;2748:341:27:-;2979:4;2456:22:29;2467:10;2456;:22::i;:::-;2448:31;;;;;;-1:-1:-1;;;;;2969:29:0;;2946:4;2969:29;;;:12;;:29;:12;:29;;;2962:6:27;;2969:29:0;;2335:118:31::1;;;::::0;-1:-1:-1;;;2335:118:31;;11704:2:34;2335:118:31::1;::::0;::::1;11686:21:34::0;11743:2;11723:18;;;11716:30;11782:34;11762:18;;;11755:62;-1:-1:-1;;;11833:18:34;;;11826:40;11883:19;;2335:118:31::1;11502:406:34::0;2335:118:31::1;2995:20:27::2;3012:2;2995:16;:20::i;:::-;3054:5;::::0;3032:50:::2;::::0;;;;-1:-1:-1;;;;;3054:5:27;;::::2;3032:50;::::0;::::2;12314:34:34::0;12384:15;;;12364:18;;;12357:43;12436:15;;;12416:18;;;12409:43;12468:18;;;12461:34;;;12544:4;12532:17;;12511:19;;;12504:46;12566:19;;;12559:35;;;12610:19;;;12603:35;;;3032:13:27::2;::::0;:21:::2;::::0;12225:19:34;;3032:50:27::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3025:57:::0;2748:341;-1:-1:-1;;;;;;;;;2748:341:27:o;1313:225:4:-;841:12;;-1:-1:-1;;;;;841:12:4;827:10;:26;819:35;;;;;;1406:12:::1;::::0;;1399:5;1378:41:::1;::::0;-1:-1:-1;;;;;1406:12:4;;::::1;::::0;1399:5;;::::1;::::0;1378:41:::1;::::0;1406:12:::1;::::0;1378:41:::1;1437:12;::::0;;1429:20;;-1:-1:-1;;;;;;1429:20:4::1;-1:-1:-1::0;;;;;1437:12:4;;::::1;1429:20:::0;;::::1;::::0;;1459:37:::1;::::0;1437:12:::1;::::0;1459:10:::1;:37::i;:::-;1506:12;:25:::0;;-1:-1:-1;;;;;;1506:25:4::1;::::0;;1313:225::o;3562:392:21:-;3796:4;2456:22:29;2467:10;2456;:22::i;:::-;2448:31;;;;;;-1:-1:-1;;;;;2969:29:0;;2946:4;2969:29;;;:12;;:29;:12;:29;;;3779:6:21;;2969:29:0;;2335:118:31::1;;;::::0;-1:-1:-1;;;2335:118:31;;11704:2:34;2335:118:31::1;::::0;::::1;11686:21:34::0;11743:2;11723:18;;;11716:30;11782:34;11762:18;;;11755:62;-1:-1:-1;;;11833:18:34;;;11826:40;11883:19;;2335:118:31::1;11502:406:34::0;2335:118:31::1;3833:5:21::2;::::0;:36:::2;::::0;;;;-1:-1:-1;;;;;3833:5:21;;::::2;:36;::::0;::::2;13050:34:34::0;13120:15;;;13100:18;;;13093:43;13152:18;;;13145:34;;;13195:18;;;13188:34;;;13271:4;13259:17;;13238:19;;;13231:46;13293:19;;;13286:35;;;13337:19;;;13330:35;;;3833:10:21::2;::::0;::::2;::::0;12961:19:34;;3833:36:21::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3812:114;;;::::0;-1:-1:-1;;;3812:114:21;;13578:2:34;3812:114:21::2;::::0;::::2;13560:21:34::0;13617:2;13597:18;;;13590:30;13656:33;13636:18;;;13629:61;13707:18;;3812:114:21::2;13376:355:34::0;3812:114:21::2;-1:-1:-1::0;3943:4:21::2;::::0;3562:392;-1:-1:-1;;;;;;;;3562:392:21:o;3975:155:31:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;4052:30:31::1;1104:23;4074:7;4052:9;:30::i;:::-;4097:26;::::0;-1:-1:-1;;;;;4097:26:31;::::1;::::0;::::1;::::0;;;::::1;3975:155:::0;:::o;4236:161::-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;4316:31:31::1;1104:23;4339:7;4316:10;:31::i;:::-;4362:28;::::0;-1:-1:-1;;;;;4362:28:31;::::1;::::0;::::1;::::0;;;::::1;4236:161:::0;:::o;4310:138:29:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;4391:8:29::1;::::0;4382:29:::1;::::0;-1:-1:-1;;;;;4382:29:29;;::::1;::::0;4391:8:::1;::::0;4382:29:::1;::::0;4391:8:::1;::::0;4382:29:::1;4421:8;:20:::0;;-1:-1:-1;;;;;;4421:20:29::1;-1:-1:-1::0;;;;;4421:20:29;;;::::1;::::0;;;::::1;::::0;;4310:138::o;8946:106::-;9024:5;;:21;;;;;-1:-1:-1;;;;;178:55:34;;;9024:21:29;;;160:74:34;9001:4:29;;9024:5;;:16;;133:18:34;;9024:21:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;7665:207::-;7801:7;2456:22;2467:10;2456;:22::i;:::-;2448:31;;;;;;7827:5:::1;::::0;:38:::1;::::0;;;;-1:-1:-1;;;;;7827:5:29;;::::1;:38;::::0;::::1;14057:34:34::0;14127:15;;;14107:18;;;14100:43;14179:15;;;14159:18;;;14152:43;14211:18;;;14204:34;;;7827:13:29::1;::::0;::::1;::::0;13968:19:34;;7827:38:29::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7820:45:::0;7665:207;-1:-1:-1;;;;7665:207:29:o;4169:241:21:-;4298:4;2456:22:29;2467:10;2456;:22::i;:::-;2448:31;;;;;;4277:10:21::1;2946:4:0::0;2969:29;;;:12;;:29;:12;:29;;;;;2335:118:31::1;;;::::0;-1:-1:-1;;;2335:118:31;;11704:2:34;2335:118:31::1;::::0;::::1;11686:21:34::0;11743:2;11723:18;;;11716:30;11782:34;11762:18;;;11755:62;-1:-1:-1;;;11833:18:34;;;11826:40;11883:19;;2335:118:31::1;11502:406:34::0;2335:118:31::1;4322:5:21::2;::::0;:24:::2;::::0;;;;-1:-1:-1;;;;;4322:5:21;;::::2;:24;::::0;::::2;10304:34:34::0;10374:15;;;10354:18;;;10347:43;10406:18;;;10399:34;;;4322:10:21::2;::::0;::::2;::::0;10216:18:34;;4322:24:21::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4314:68;;;::::0;-1:-1:-1;;;4314:68:21;;13578:2:34;4314:68:21::2;::::0;::::2;13560:21:34::0;13617:2;13597:18;;;13590:30;13656:33;13636:18;;;13629:61;13707:18;;4314:68:21::2;13376:355:34::0;4314:68:21::2;-1:-1:-1::0;4399:4:21::2;::::0;4169:241;-1:-1:-1;;;4169:241:21:o;4960:164:29:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;-1:-1:-1;;;;;5036:26:29;::::1;5065:5;5036:26:::0;;;:15:::1;:26;::::0;;;;;:34;;-1:-1:-1;;5036:34:29::1;::::0;;5085:32;::::1;::::0;5065:5;5085:32:::1;4960:164:::0;:::o;4628:205::-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;-1:-1:-1;;;;;4746:26:29;::::1;;::::0;;;:15:::1;:26;::::0;;;;;;:33;;-1:-1:-1;;4746:33:29::1;4775:4;4746:33;::::0;;4794:32;::::1;::::0;4820:5;;;;4794:32:::1;:::i;:::-;;::::0;;;;::::1;::::0;;;-1:-1:-1;;;;;4794:32:29;::::1;::::0;::::1;::::0;;;::::1;4628:205:::0;;;:::o;5505:152::-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;5593:5:29::1;::::0;5577:33:::1;::::0;-1:-1:-1;;;;;5577:33:29;;::::1;::::0;5593:5:::1;::::0;5577:33:::1;::::0;5593:5:::1;::::0;5577:33:::1;5620:5;:30:::0;;-1:-1:-1;;;;;;5620:30:29::1;-1:-1:-1::0;;;;;5620:30:29;;;::::1;::::0;;;::::1;::::0;;5505:152::o;5313:381:27:-;5514:39;;-1:-1:-1;;;5514:39:27;;:10;:39;;;14797:25:34;-1:-1:-1;;;;;14919:15:34;;;14899:18;;;14892:43;14971:15;;14951:18;;;14944:43;15003:18;;;14996:34;;;5477:4:27;;5514:19;;;;14769::34;;5514:39:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5493:119;;;;-1:-1:-1;;;5493:119:27;;15243:2:34;5493:119:27;;;15225:21:34;15282:2;15262:18;;;15255:30;15321:34;15301:18;;;15294:62;15392:3;15372:18;;;15365:31;15413:19;;5493:119:27;15041:397:34;5493:119:27;5629:58;5662:6;5670:2;5674:6;5682:4;;5629:32;:58::i;:::-;5622:65;5313:381;-1:-1:-1;;;;;;5313:381:27:o;3443:158:31:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;3521:31:31::1;1171:24;3544:7;3521:9;:31::i;:::-;3567:27;::::0;-1:-1:-1;;;;;3567:27:31;::::1;::::0;::::1;::::0;;;::::1;3443:158:::0;:::o;5978:89:29:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;6038:5:29::1;;;;;;;;;-1:-1:-1::0;;;;;6038:5:29::1;-1:-1:-1::0;;;;;6038:20:29::1;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;5978:89::o:0;5193:147:0:-;4417:7;4443:12;;;;;;;;;;:22;;;2470:16;2481:4;2470:10;:16::i;:::-;5307:26:::1;5319:4;5325:7;5307:11;:26::i;9297:157:29:-:0;9416:5;;:31;;;;;-1:-1:-1;;;;;9416:5:29;;;:31;;;15735:34:34;15805:15;;;15785:18;;;15778:43;15857:15;;;15837:18;;;15830:43;9393:4:29;;9416:15;;;;15647:18:34;;9416:31:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9409:38;9297:157;-1:-1:-1;;;9297:157:29:o;3500:325:27:-;3665:39;;-1:-1:-1;;;3665:39:27;;:10;:39;;;14797:25:34;-1:-1:-1;;;;;14919:15:34;;;14899:18;;;14892:43;14971:15;;14951:18;;;14944:43;15003:18;;;14996:34;;;3628:4:27;;3665:19;;;;14769::34;;3665:39:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3644:112;;;;-1:-1:-1;;;3644:112:27;;16086:2:34;3644:112:27;;;16068:21:34;16125:2;16105:18;;;16098:30;16164:28;16144:18;;;16137:56;16210:18;;3644:112:27;15884:350:34;3644:112:27;3773:45;3799:6;3807:2;3811:6;3773:25;:45::i;4383:363::-;4574:37;;-1:-1:-1;;;4574:37:27;;:10;:37;;;14797:25:34;-1:-1:-1;;;;;14919:15:34;;;14899:18;;;14892:43;14971:15;;14951:18;;;14944:43;15003:18;;;14996:34;;;4537:4:27;;4574:19;;;;14769::34;;4574:37:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4553:114;;;;-1:-1:-1;;;4553:114:27;;16441:2:34;4553:114:27;;;16423:21:34;16480:2;16460:18;;;16453:30;16519:32;16499:18;;;16492:60;16569:18;;4553:114:27;16239:354:34;4553:114:27;4684:55;4714:6;4722:4;4728:2;4732:6;4684:29;:55::i;:::-;4677:62;4383:363;-1:-1:-1;;;;;4383:363:27:o;3708:164:31:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;3789:32:31::1;1171:24;3813:7;3789:10;:32::i;:::-;3836:29;::::0;-1:-1:-1;;;;;3836:29:31;::::1;::::0;::::1;::::0;;;::::1;3708:164:::0;:::o;5788:119:29:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;5867:5:29::1;::::0;:33:::1;::::0;;;;-1:-1:-1;;;;;178:55:34;;;5867:33:29::1;::::0;::::1;160:74:34::0;5867:5:29;;::::1;::::0;:23:::1;::::0;133:18:34;;5867:33:29::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;5070:352:21::0;2632:10:31;2946:4:0;2969:29;;;:12;;:29;:12;:29;;;;;2591:120:31;;;;-1:-1:-1;;;2591:120:31;;16800:2:34;2591:120:31;;;16782:21:34;16839:2;16819:18;;;16812:30;16878:34;16858:18;;;16851:62;16949:12;16929:18;;;16922:40;16979:19;;2591:120:31;16598:406:34;2591:120:31;5225:16:21::1;;5215:6;:26;;5194:134;;;::::0;-1:-1:-1;;;5194:134:21;;17211:2:34;5194:134:21::1;::::0;::::1;17193:21:34::0;17250:2;17230:18;;;17223:30;17289:34;17269:18;;;17262:62;17360:31;17340:18;;;17333:59;17409:19;;5194:134:21::1;17009:425:34::0;5194:134:21::1;-1:-1:-1::0;;;;;5338:23:21;::::1;;::::0;;;:14:::1;:23;::::0;;;;;;:32;;;5385:30;::::1;::::0;::::1;::::0;5364:6;1331:25:34;;1319:2;1304:18;;1185:177;5385:30:21::1;;;;;;;;5070:352:::0;;:::o;1025:196:4:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;1158:12:4::1;::::0;1133:48:::1;::::0;-1:-1:-1;;;;;1133:48:4;;::::1;::::0;1158:12:::1;::::0;1133:48:::1;::::0;1158:12:::1;::::0;1133:48:::1;1191:12;:23:::0;;-1:-1:-1;;;;;;1191:23:4::1;-1:-1:-1::0;;;;;1191:23:4;;;::::1;::::0;;;::::1;::::0;;1025:196::o;4533:151:21:-;784:5:24;;-1:-1:-1;;;;;784:5:24;770:10;:19;762:28;;;;;;4618:24:21::1;::::0;1331:25:34;;;4618:24:21::1;::::0;1319:2:34;1304:18;4618:24:21::1;;;;;;;4652:16;:25:::0;4533:151::o;3299:103:0:-;3365:30;3376:4;719:10:5;3365::0;:30::i;:::-;3299:103;:::o;7426:233::-;2946:4;2969:12;;;;;;;;;;;-1:-1:-1;;;;;2969:29:0;;;;;;;;;;;;7504:149;;7547:6;:12;;;;;;;;;;;-1:-1:-1;;;;;7547:29:0;;;;;;;;;:36;;-1:-1:-1;;7547:36:0;7579:4;7547:36;;;7629:12;719:10:5;;640:96;7629:12:0;-1:-1:-1;;;;;7602:40:0;7620:7;-1:-1:-1;;;;;7602:40:0;7614:4;7602:40;;;;;;;;;;7426:233;;:::o;3415:402:29:-;-1:-1:-1;;;;;3485:18:29;;3477:51;;;;-1:-1:-1;;;3477:51:29;;17641:2:34;3477:51:29;;;17623:21:34;17680:2;17660:18;;;17653:30;17719:22;17699:18;;;17692:50;17759:18;;3477:51:29;17439:344:34;3477:51:29;-1:-1:-1;;;;;3546:19:29;;3560:4;3546:19;;3538:59;;;;-1:-1:-1;;;3538:59:29;;17990:2:34;3538:59:29;;;17972:21:34;18029:2;18009:18;;;18002:30;18068:29;18048:18;;;18041:57;18115:18;;3538:59:29;17788:351:34;3538:59:29;3629:5;;-1:-1:-1;;;;;3615:20:29;;;3629:5;;3615:20;;3607:63;;;;-1:-1:-1;;;3607:63:29;;18346:2:34;3607:63:29;;;18328:21:34;18385:2;18365:18;;;18358:30;18424:32;18404:18;;;18397:60;18474:18;;3607:63:29;18144:354:34;3607:63:29;3694:8;;-1:-1:-1;;;;;3688:14:29;;;3694:8;;3688:14;;3680:52;;;;-1:-1:-1;;;3680:52:29;;18705:2:34;3680:52:29;;;18687:21:34;18744:2;18724:18;;;18717:30;18783:27;18763:18;;;18756:55;18828:18;;3680:52:29;18503:349:34;3680:52:29;3750:14;3761:2;3750:10;:14::i;:::-;:23;3742:68;;;;-1:-1:-1;;;3742:68:29;;19059:2:34;3742:68:29;;;19041:21:34;;;19078:18;;;19071:30;19137:34;19117:18;;;19110:62;19189:18;;3742:68:29;18857:356:34;7830:234:0;2946:4;2969:12;;;;;;;;;;;-1:-1:-1;;;;;2969:29:0;;;;;;;;;;;;7909:149;;;7983:5;7951:12;;;;;;;;;;;-1:-1:-1;;;;;7951:29:0;;;;;;;;;;:37;;-1:-1:-1;;7951:37:0;;;8007:40;719:10:5;;7951:12:0;;8007:40;;7983:5;8007:40;7830:234;;:::o;6776:110::-;6854:25;6865:4;6871:7;6854:10;:25::i;8314:286:29:-;8490:7;2456:22;2467:10;2456;:22::i;:::-;2448:31;;;;;;8509:20:::1;8526:2;8509:16;:20::i;:::-;8546:5;::::0;:47:::1;::::0;;;;:21:::1;::::0;::::1;::::0;:47:::1;::::0;-1:-1:-1;;;;;8546:5:29::1;::::0;8568:6;;8576:2;;8580:6;;8588:4;;;;8546:47:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;6286:237::-:0;6426:7;2456:22;2467:10;2456;:22::i;:::-;2448:31;;;;;;6445:20:::1;6462:2;6445:16;:20::i;:::-;6482:5;::::0;:34:::1;::::0;;;;-1:-1:-1;;;;;6482:5:29;;::::1;:34;::::0;::::1;14057::34::0;14127:15;;;14107:18;;;14100:43;14179:15;;;14159:18;;;14152:43;14211:18;;;14204:34;;;6482:14:29::1;::::0;::::1;::::0;13968:19:34;;6482:34:29::1;13736:508:34::0;6883:273:29;7049:7;2456:22;2467:10;2456;:22::i;:::-;2448:31;;;;;;7068:20:::1;7085:2;7068:16;:20::i;:::-;7105:5;::::0;:44:::1;::::0;;;;-1:-1:-1;;;;;7105:5:29;;::::1;:44;::::0;::::1;20367:34:34::0;20437:15;;;20417:18;;;20410:43;20489:15;;;20469:18;;;20462:43;20541:15;;;20521:18;;;20514:43;20573:19;;;20566:35;;;7105:18:29::1;::::0;::::1;::::0;20278:19:34;;7105:44:29::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;3683:479:0:-:0;2946:4;2969:12;;;;;;;;;;;-1:-1:-1;;;;;2969:29:0;;;;;;;;;;;;3766:390;;3954:28;3974:7;3954:19;:28::i;:::-;4053:38;4081:4;4088:2;4053:19;:38::i;:::-;3861:252;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;3861:252:0;;;;;;;;;;-1:-1:-1;;;3809:336:0;;;;;;;:::i;2097:149:30:-;2155:13;2187:52;-1:-1:-1;;;;;2199:22:30;;306:2;1508:437;1583:13;1608:19;1640:10;1644:6;1640:1;:10;:::i;:::-;:14;;1653:1;1640:14;:::i;:::-;1630:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1630:25:30;;1608:47;;1665:15;:6;1672:1;1665:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;1665:15:30;;;;;;;;;1690;:6;1697:1;1690:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;1690:15:30;;;;;;;;-1:-1:-1;1720:9:30;1732:10;1736:6;1732:1;:10;:::i;:::-;:14;;1745:1;1732:14;:::i;:::-;1720:26;;1715:128;1752:1;1748;:5;1715:128;;;1786:8;1795:5;1803:3;1795:11;1786:21;;;;;;;:::i;:::-;;;;1774:6;1781:1;1774:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;1774:33:30;;;;;;;;-1:-1:-1;1831:1:30;1821:11;;;;;1755:3;;;:::i;:::-;;;1715:128;;;-1:-1:-1;1860:10:30;;1852:55;;;;-1:-1:-1;;;1852:55:30;;23081:2:34;1852:55:30;;;23063:21:34;;;23100:18;;;23093:30;23159:34;23139:18;;;23132:62;23211:18;;1852:55:30;22879:356:34;245:332;303:6;356:2;344:9;335:7;331:23;327:32;324:52;;;372:1;369;362:12;324:52;411:9;398:23;461:66;454:5;450:78;443:5;440:89;430:117;;543:1;540;533:12;774:154;-1:-1:-1;;;;;853:5:34;849:54;842:5;839:65;829:93;;918:1;915;908:12;933:247;992:6;1045:2;1033:9;1024:7;1020:23;1016:32;1013:52;;;1061:1;1058;1051:12;1013:52;1100:9;1087:23;1119:31;1144:5;1119:31;:::i;1367:180::-;1426:6;1479:2;1467:9;1458:7;1454:23;1450:32;1447:52;;;1495:1;1492;1485:12;1447:52;-1:-1:-1;1518:23:34;;1367:180;-1:-1:-1;1367:180:34:o;1734:315::-;1802:6;1810;1863:2;1851:9;1842:7;1838:23;1834:32;1831:52;;;1879:1;1876;1869:12;1831:52;1915:9;1902:23;1892:33;;1975:2;1964:9;1960:18;1947:32;1988:31;2013:5;1988:31;:::i;:::-;2038:5;2028:15;;;1734:315;;;;;:::o;2243:456::-;2320:6;2328;2336;2389:2;2377:9;2368:7;2364:23;2360:32;2357:52;;;2405:1;2402;2395:12;2357:52;2444:9;2431:23;2463:31;2488:5;2463:31;:::i;:::-;2513:5;-1:-1:-1;2570:2:34;2555:18;;2542:32;2583:33;2542:32;2583:33;:::i;:::-;2243:456;;2635:7;;-1:-1:-1;;;2689:2:34;2674:18;;;;2661:32;;2243:456::o;2704:156::-;2770:20;;2830:4;2819:16;;2809:27;;2799:55;;2850:1;2847;2840:12;2799:55;2704:156;;;:::o;2865:807::-;2976:6;2984;2992;3000;3008;3016;3024;3077:3;3065:9;3056:7;3052:23;3048:33;3045:53;;;3094:1;3091;3084:12;3045:53;3133:9;3120:23;3152:31;3177:5;3152:31;:::i;:::-;3202:5;-1:-1:-1;3259:2:34;3244:18;;3231:32;3272:33;3231:32;3272:33;:::i;:::-;3324:7;-1:-1:-1;3383:2:34;3368:18;;3355:32;3396:33;3355:32;3396:33;:::i;:::-;3448:7;-1:-1:-1;3502:2:34;3487:18;;3474:32;;-1:-1:-1;3525:37:34;3557:3;3542:19;;3525:37;:::i;:::-;3515:47;;3609:3;3598:9;3594:19;3581:33;3571:43;;3661:3;3650:9;3646:19;3633:33;3623:43;;2865:807;;;;;;;;;;:::o;3677:734::-;3788:6;3796;3804;3812;3820;3828;3836;3889:3;3877:9;3868:7;3864:23;3860:33;3857:53;;;3906:1;3903;3896:12;3857:53;3945:9;3932:23;3964:31;3989:5;3964:31;:::i;:::-;4014:5;-1:-1:-1;4071:2:34;4056:18;;4043:32;4084:33;4043:32;4084:33;:::i;:::-;4136:7;-1:-1:-1;4190:2:34;4175:18;;4162:32;;-1:-1:-1;4241:2:34;4226:18;;4213:32;;-1:-1:-1;4264:37:34;4296:3;4281:19;;4264:37;:::i;4416:315::-;4484:6;4492;4545:2;4533:9;4524:7;4520:23;4516:32;4513:52;;;4561:1;4558;4551:12;4513:52;4600:9;4587:23;4619:31;4644:5;4619:31;:::i;:::-;4669:5;4721:2;4706:18;;;;4693:32;;-1:-1:-1;;;4416:315:34:o;4989:348::-;5041:8;5051:6;5105:3;5098:4;5090:6;5086:17;5082:27;5072:55;;5123:1;5120;5113:12;5072:55;-1:-1:-1;5146:20:34;;5189:18;5178:30;;5175:50;;;5221:1;5218;5211:12;5175:50;5258:4;5250:6;5246:17;5234:29;;5310:3;5303:4;5294:6;5286;5282:19;5278:30;5275:39;5272:59;;;5327:1;5324;5317:12;5272:59;4989:348;;;;;:::o;5342:546::-;5422:6;5430;5438;5491:2;5479:9;5470:7;5466:23;5462:32;5459:52;;;5507:1;5504;5497:12;5459:52;5546:9;5533:23;5565:31;5590:5;5565:31;:::i;:::-;5615:5;-1:-1:-1;5671:2:34;5656:18;;5643:32;5698:18;5687:30;;5684:50;;;5730:1;5727;5720:12;5684:50;5769:59;5820:7;5811:6;5800:9;5796:22;5769:59;:::i;:::-;5342:546;;5847:8;;-1:-1:-1;5743:85:34;;-1:-1:-1;;;;5342:546:34:o;5893:755::-;5990:6;5998;6006;6014;6022;6075:3;6063:9;6054:7;6050:23;6046:33;6043:53;;;6092:1;6089;6082:12;6043:53;6131:9;6118:23;6150:31;6175:5;6150:31;:::i;:::-;6200:5;-1:-1:-1;6257:2:34;6242:18;;6229:32;6270:33;6229:32;6270:33;:::i;:::-;6322:7;-1:-1:-1;6376:2:34;6361:18;;6348:32;;-1:-1:-1;6431:2:34;6416:18;;6403:32;6458:18;6447:30;;6444:50;;;6490:1;6487;6480:12;6444:50;6529:59;6580:7;6571:6;6560:9;6556:22;6529:59;:::i;:::-;5893:755;;;;-1:-1:-1;5893:755:34;;-1:-1:-1;6607:8:34;;6503:85;5893:755;-1:-1:-1;;;5893:755:34:o;6653:388::-;6721:6;6729;6782:2;6770:9;6761:7;6757:23;6753:32;6750:52;;;6798:1;6795;6788:12;6750:52;6837:9;6824:23;6856:31;6881:5;6856:31;:::i;:::-;6906:5;-1:-1:-1;6963:2:34;6948:18;;6935:32;6976:33;6935:32;6976:33;:::i;7046:598::-;7132:6;7140;7148;7156;7209:3;7197:9;7188:7;7184:23;7180:33;7177:53;;;7226:1;7223;7216:12;7177:53;7265:9;7252:23;7284:31;7309:5;7284:31;:::i;:::-;7334:5;-1:-1:-1;7391:2:34;7376:18;;7363:32;7404:33;7363:32;7404:33;:::i;:::-;7456:7;-1:-1:-1;7515:2:34;7500:18;;7487:32;7528:33;7487:32;7528:33;:::i;:::-;7046:598;;;;-1:-1:-1;7580:7:34;;7634:2;7619:18;7606:32;;-1:-1:-1;;7046:598:34:o;8055:251::-;8125:6;8178:2;8166:9;8157:7;8153:23;8149:32;8146:52;;;8194:1;8191;8184:12;8146:52;8226:9;8220:16;8245:31;8270:5;8245:31;:::i;8652:184::-;8722:6;8775:2;8763:9;8754:7;8750:23;8746:32;8743:52;;;8791:1;8788;8781:12;8743:52;-1:-1:-1;8814:16:34;;8652:184;-1:-1:-1;8652:184:34:o;9693:::-;-1:-1:-1;;;9742:1:34;9735:88;9842:4;9839:1;9832:15;9866:4;9863:1;9856:15;9882:125;9922:4;9950:1;9947;9944:8;9941:34;;;9955:18;;:::i;:::-;-1:-1:-1;9992:9:34;;9882:125::o;10444:277::-;10511:6;10564:2;10552:9;10543:7;10539:23;10535:32;10532:52;;;10580:1;10577;10570:12;10532:52;10612:9;10606:16;10665:5;10658:13;10651:21;10644:5;10641:32;10631:60;;10687:1;10684;10677:12;14249:273;14434:6;14426;14421:3;14408:33;14390:3;14460:16;;14485:13;;;14460:16;14249:273;-1:-1:-1;14249:273:34:o;19218:795::-;19479:4;-1:-1:-1;;;;;19589:2:34;19581:6;19577:15;19566:9;19559:34;19641:2;19633:6;19629:15;19624:2;19613:9;19609:18;19602:43;19693:2;19685:6;19681:15;19676:2;19665:9;19661:18;19654:43;;19733:6;19728:2;19717:9;19713:18;19706:34;19777:3;19771;19760:9;19756:19;19749:32;19818:6;19812:3;19801:9;19797:19;19790:35;19876:6;19868;19862:3;19851:9;19847:19;19834:49;19933:1;19927:3;19918:6;19907:9;19903:22;19899:32;19892:43;20003:3;19996:2;19992:7;19987:2;19979:6;19975:15;19971:29;19960:9;19956:45;19952:55;19944:63;;19218:795;;;;;;;;;:::o;20612:258::-;20684:1;20694:113;20708:6;20705:1;20702:13;20694:113;;;20784:11;;;20778:18;20765:11;;;20758:39;20730:2;20723:10;20694:113;;;20825:6;20822:1;20819:13;20816:48;;;-1:-1:-1;;20860:1:34;20842:16;;20835:27;20612:258::o;20875:786::-;21286:25;21281:3;21274:38;21256:3;21341:6;21335:13;21357:62;21412:6;21407:2;21402:3;21398:12;21391:4;21383:6;21379:17;21357:62;:::i;:::-;21483:19;21478:2;21438:16;;;21470:11;;;21463:40;21528:13;;21550:63;21528:13;21599:2;21591:11;;21584:4;21572:17;;21550:63;:::i;:::-;21633:17;21652:2;21629:26;;20875:786;-1:-1:-1;;;;20875:786:34:o;21666:383::-;21815:2;21804:9;21797:21;21778:4;21847:6;21841:13;21890:6;21885:2;21874:9;21870:18;21863:34;21906:66;21965:6;21960:2;21949:9;21945:18;21940:2;21932:6;21928:15;21906:66;:::i;:::-;22033:2;22012:15;-1:-1:-1;;22008:29:34;21993:45;;;;22040:2;21989:54;;21666:383;-1:-1:-1;;21666:383:34:o;22054:168::-;22094:7;22160:1;22156;22152:6;22148:14;22145:1;22142:21;22137:1;22130:9;22123:17;22119:45;22116:71;;;22167:18;;:::i;:::-;-1:-1:-1;22207:9:34;;22054:168::o;22227:128::-;22267:3;22298:1;22294:6;22291:1;22288:13;22285:39;;;22304:18;;:::i;:::-;-1:-1:-1;22340:9:34;;22227:128::o;22360:184::-;-1:-1:-1;;;22409:1:34;22402:88;22509:4;22506:1;22499:15;22533:4;22530:1;22523:15;22549:184;-1:-1:-1;;;22598:1:34;22591:88;22698:4;22695:1;22688:15;22722:4;22719:1;22712:15;22738:136;22777:3;22805:5;22795:39;;22814:18;;:::i;:::-;-1:-1:-1;;;22850:18:34;;22738:136::o

Swarm Source

ipfs://e51bdfea16490038892f8feb2068851f6ae531d935e40110b020c2e80aafd7c6

Block Transaction Gas Used Reward
view all blocks validated

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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