ETH Price: $2,972.79 (+2.49%)
Gas: 1 Gwei

Contract

0xd69682366ba2763C1d48FF611088825D3AD2FeEa
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60808060180358772023-08-31 16:53:35309 days ago1693500815IN
 Contract Creation
0 ETH0.0924151646.22658115

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x08e46853...8EB8fF9e5
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
MilestoneFacet

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 37 : MilestoneFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin imports
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Diamond imports
import { LibDiamond } from "../../diamond/libraries/LibDiamond.sol";

// Local imports
import { MilestoneConstants } from "../constants/MilestoneConstants.sol";
import { MilestoneEncoder } from "../encoders/MilestoneEncoder.sol";
import { RequestTypes } from "../structs/RequestTypes.sol";
import { BaseTypes } from "../structs/BaseTypes.sol";
import { LibMilestone } from "../libraries/LibMilestone.sol";
import { LibEscrow } from "../libraries/LibEscrow.sol";
import { LibRaise } from "../libraries/LibRaise.sol";
import { LibRequest } from "../libraries/LibRequest.sol";
import { LibSignature } from "../../libraries/LibSignature.sol";
import { VerifySignatureMixin } from "../mixins/VerifySignatureMixin.sol";
import { MilestoneEvents } from "../events/MilestoneEvents.sol";
import { MilestoneErrors } from "../errors/MilestoneErrors.sol";
import { RaiseErrors } from "../errors/RaiseErrors.sol";
import { IMilestoneFacet } from "../interfaces/IMilestoneFacet.sol";

/**************************************

    Milestone facet

**************************************/

/// @notice Milestone facet implementing unlocking of new milestones for raises and claiming of unlocked tokens.
contract MilestoneFacet is IMilestoneFacet {
    // -----------------------------------------------------------------------
    //                              Unlock
    // -----------------------------------------------------------------------

    /// @dev Unlock new milestone for given raise.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Milestone data needs to have correct number and share under 100% cap in total.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: MilestoneUnlocked(string raiseId, BaseTypes.Milestone milestone).
    /// @param _request UnlockMilestoneRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function unlockMilestone(
        RequestTypes.UnlockMilestoneRequest calldata _request,
        bytes32 _message,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external {
        // validation
        LibRequest.validateBaseRequest(_request.base);
        _validateCompletedRaise(_request.raiseId);
        _validateUnlockMilestoneRequest(_request);

        // eip712 encoding
        bytes memory encodedMsg_ = MilestoneEncoder.encodeUnlockMilestone(_request);

        // verify message
        LibSignature.verifyMessage(MilestoneConstants.EIP712_NAME, MilestoneConstants.EIP712_VERSION, keccak256(encodedMsg_), _message);

        // verify signature
        VerifySignatureMixin.verifySignature(_message, _v, _r, _s);

        // unlock milestone
        LibMilestone.unlockMilestone(_request.raiseId, _request.milestone);

        // events
        emit MilestoneEvents.MilestoneUnlocked(_request.raiseId, _request.milestone);
    }

    // -----------------------------------------------------------------------
    //                              Claim
    // -----------------------------------------------------------------------

    // TODO: Temp remove cosign and bring back once we have startup management panel
    /// @dev Claim milestone by startup.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: StartupClaimed(string raiseId, address startup, uint256 claimed).
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimMilestoneStartup(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // validation
        LibRequest.validateBaseRequest(_request.base);
        _validateRaiseExists(_request.raiseId);
        _validateClaimMilestoneStartup(_request.raiseId, _request.recipient);

        // get available
        uint256 available_ = _getAvailableForStartup(_request.raiseId);
        if (available_ == 0) revert MilestoneErrors.NothingToClaim(_request.raiseId, _request.recipient);

        // validate msg and sig
        _verifyClaimMsgSig(_request, _message, _v, _r, _s);

        // claim USDT
        LibMilestone.claimMilestoneStartup(_request.raiseId, LibEscrow.getEscrow(_request.raiseId), _request.recipient, available_);

        // events
        emit MilestoneEvents.MilestoneUnlocked__StartupClaimed(_request.raiseId, _request.recipient, available_);
    }

    /// @dev Claim milestone by investor.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by user that invested in raise.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: InvestorClaimed(string raiseId, address erc20, address startup, uint256 claimed).
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimMilestoneInvestor(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // validate request
        LibRequest.validateBaseRequest(_request.base);
        _validateRaiseExists(_request.raiseId);
        _validateClaimMilestoneInvestor(_request.raiseId, _request.recipient);

        // get available
        uint256 available_ = _getAvailableForInvestor(_request.raiseId, msg.sender);
        if (available_ == 0) revert MilestoneErrors.NothingToClaim(_request.raiseId, _request.recipient);

        // validate msg and sig
        _verifyClaimMsgSig(_request, _message, _v, _r, _s);

        // get erc20
        address erc20_ = LibRaise.getVestedERC20(_request.raiseId);

        // claim ERC20
        LibMilestone.claimMilestoneInvestor(_request.raiseId, erc20_, LibEscrow.getEscrow(_request.raiseId), _request.recipient, available_);

        // events
        emit MilestoneEvents.MilestoneUnlocked__InvestorClaimed(_request.raiseId, erc20_, _request.recipient, available_);
    }

    // -----------------------------------------------------------------------
    //                              Internal
    // -----------------------------------------------------------------------

    /// @dev Validate unlock milestone request.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Milestone data needs to have correct number and share under 100% cap in total.
    /// @param _request UnlockMilestoneRequest struct
    function _validateUnlockMilestoneRequest(RequestTypes.UnlockMilestoneRequest calldata _request) internal view {
        // verify milestone number
        uint256 milestoneCount_ = LibMilestone.milestoneCount(_request.raiseId);
        if (_request.milestone.milestoneNo != milestoneCount_ + 1) {
            revert MilestoneErrors.InvalidMilestoneNumber(_request.milestone.milestoneNo, milestoneCount_);
        }

        // verify share greater than 0
        if (_request.milestone.share == 0) {
            revert MilestoneErrors.ZeroShare(_request.milestone.milestoneNo);
        }

        // verify sum of shares max 100
        uint256 shares_ = LibMilestone.totalShares(_request.raiseId);
        if (_request.milestone.share + shares_ > 100 * LibMilestone.SHARE_PRECISION) {
            revert MilestoneErrors.ShareExceedLimit(_request.milestone.share, shares_);
        }
    }

    /// @dev Validate claim milestone by startup request.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @param _raiseId ID of raise
    /// @param _recipient Address of startup
    function _validateClaimMilestoneStartup(string memory _raiseId, address _recipient) internal view {
        // TODO: Check if erc20 is on this chain

        // check if sender is startup
        if (_recipient != LibRaise.getRaiseOwner(_raiseId)) {
            revert RaiseErrors.CallerNotStartup(_recipient, _raiseId);
        }
    }

    /// @dev Validate claim milestone by investor request.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by user that invested in raise.
    /// @param _raiseId ID of raise
    /// @param _recipient Address of investor
    function _validateClaimMilestoneInvestor(string memory _raiseId, address _recipient) internal view {
        // TODO: Check if base asset is on this chain

        // check if sender invested
        if (LibRaise.getInvestment(_raiseId, _recipient) == 0) {
            revert RaiseErrors.UserHasNotInvested(_recipient, _raiseId);
        }

        // check if erc20 is set and deposited for claiming
        if (LibRaise.getRaiseType(_raiseId) == BaseTypes.RaiseType.EarlyStage) {
            _validateEarlyStageERC20(_raiseId);
        }
    }

    // -----------------------------------------------------------------------
    //                              Get available
    // -----------------------------------------------------------------------

    /// @dev Get available funds to claim by startup.
    /// @return Amount of unlocked base asset available to claim
    function getAvailableForStartup(string memory _raiseId) external view returns (uint256) {
        // validation
        _validateCompletedRaise(_raiseId);
        _validateClaimMilestoneStartup(_raiseId, msg.sender);

        // return
        return _getAvailableForStartup(_raiseId);
    }

    /// @dev Return available USDC to claim for startup
    function _getAvailableForStartup(string memory _raiseId) internal view returns (uint256) {
        // get raised
        uint256 total_ = LibRaise.getTotalInvestment(_raiseId);

        // compute claimable
        uint256 claimable_ = (LibMilestone.unlockedShares(_raiseId) * total_) / (100 * LibMilestone.SHARE_PRECISION);

        // get claimed
        uint256 claimed_ = LibMilestone.getStartupClaimedVoting(_raiseId);

        // return available
        return claimable_ - claimed_;
    }

    /// @dev Get available funds to claim by investor.
    /// @return Amount of unlocked ERC20s available to claim
    function getAvailableForInvestor(string memory _raiseId, address _account) external view returns (uint256) {
        // validation
        _validateCompletedRaise(_raiseId);
        _validateClaimMilestoneInvestor(_raiseId, _account);

        // return
        return _getAvailableForInvestor(_raiseId, _account);
    }

    /// @dev Return available ERC20 to claim for investor
    function _getAvailableForInvestor(string memory _raiseId, address _account) internal view returns (uint256) {
        // get investment
        uint256 invested_ = LibRaise.getInvestment(_raiseId, _account);

        // get raised
        uint256 total_ = LibRaise.getTotalInvestment(_raiseId);

        // compute share
        uint256 share_ = (invested_ * LibMilestone.SHARE_PRECISION) / total_;

        // get all tokens for investor
        uint256 userDebt_ = (share_ * LibRaise.getSold(_raiseId)) / LibMilestone.SHARE_PRECISION;

        // compute claimable
        uint256 claimable_ = (LibMilestone.unlockedShares(_raiseId) * userDebt_) / (100 * LibMilestone.SHARE_PRECISION);

        // get claimed
        uint256 claimed_ = LibMilestone.getInvestorClaimedVoting(_raiseId, _account);

        // return available
        return claimable_ - claimed_;
    }

    // -----------------------------------------------------------------------
    //                              Failed repair plan
    // -----------------------------------------------------------------------

    /// @dev Submit failed repair plan and reject future milestones for given raise.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Require raise that was not rejected before and has not fully unlocked shares.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: RaiseRejected(string raiseId, uint256 rejectedShares).
    /// @param _request RejectRaiseRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function rejectRaise(RequestTypes.RejectRaiseRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // validate request
        LibRequest.validateBaseRequest(_request.base);
        _validateCompletedRaise(_request.raiseId);
        _validateRejectRaiseRequest(_request);

        // eip712 encoding
        bytes memory encodedMsg_ = MilestoneEncoder.encodeRejectRaise(_request);

        // verify message
        LibSignature.verifyMessage(MilestoneConstants.EIP712_NAME, MilestoneConstants.EIP712_VERSION, keccak256(encodedMsg_), _message);

        // verify signature
        VerifySignatureMixin.verifySignature(_message, _v, _r, _s);

        // reject raise
        uint256 rejectedShares_ = LibMilestone.rejectRaise(_request.raiseId);

        // events
        emit MilestoneEvents.RaiseRejected(_request.raiseId, rejectedShares_);
    }

    // -----------------------------------------------------------------------
    //                              Claim (repair plan)
    // -----------------------------------------------------------------------

    // TODO: Temp remove cosign and bring back once we have startup management panel
    function claimRejectedStartup(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // validation
        LibRequest.validateBaseRequest(_request.base);
        _validateRaiseExists(_request.raiseId);
        _validateClaimRejectedStartup(_request.raiseId, _request.recipient);

        // get available
        uint256 available_ = _getRejectedForStartup(_request.raiseId);
        if (available_ == 0) revert MilestoneErrors.NothingToClaim(_request.raiseId, _request.recipient);

        // validate msg and sig
        _verifyClaimMsgSig(_request, _message, _v, _r, _s);

        // get erc20
        address erc20_ = LibRaise.getVestedERC20(_request.raiseId);

        // claim ERC20
        LibMilestone.claimRejectedStartup(_request.raiseId, erc20_, LibEscrow.getEscrow(_request.raiseId), _request.recipient, available_);

        // events
        emit MilestoneEvents.RaiseRejected__StartupClaimed(_request.raiseId, erc20_, _request.recipient, available_);
    }

    function claimRejectedInvestor(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // validate request
        LibRequest.validateBaseRequest(_request.base);
        _validateRaiseExists(_request.raiseId);
        _validateClaimRejectedInvestor(_request.raiseId, _request.recipient);

        // get available
        uint256 available_ = _getRejectedForInvestor(_request.raiseId, msg.sender);
        if (available_ == 0) revert MilestoneErrors.NothingToClaim(_request.raiseId, _request.recipient);

        // validate msg and sig
        _verifyClaimMsgSig(_request, _message, _v, _r, _s);

        // claim ERC20
        LibMilestone.claimRejectedInvestor(_request.raiseId, LibEscrow.getEscrow(_request.raiseId), _request.recipient, available_);

        // events
        emit MilestoneEvents.RaiseRejected__InvestorClaimed(_request.raiseId, _request.recipient, available_);
    }

    // -----------------------------------------------------------------------
    //                              Internal (repair plan)
    // -----------------------------------------------------------------------

    function _validateRejectRaiseRequest(RequestTypes.RejectRaiseRequest calldata _request) internal view {
        // Ensure raise was not rejected already
        uint256 rejected_ = LibMilestone.rejectedShares(_request.raiseId);
        if (rejected_ > 0) {
            revert MilestoneErrors.RaiseAlreadyRejected(_request.raiseId, rejected_);
        }

        // Ensure milestones are not 100%
        uint256 shares_ = LibMilestone.totalShares(_request.raiseId);
        if (shares_ >= 100 * LibMilestone.SHARE_PRECISION) {
            revert MilestoneErrors.AllMilestonesUnlocked(_request.raiseId, shares_);
        }
    }

    function _validateClaimRejectedStartup(string memory _raiseId, address _recipient) internal view {
        // TODO: Check if base asset is on this chain

        // check if sender is startup
        if (_recipient != LibRaise.getRaiseOwner(_raiseId)) {
            revert RaiseErrors.CallerNotStartup(_recipient, _raiseId);
        }

        // check if raise was rejected
        if (LibMilestone.rejectedShares(_raiseId) == 0) {
            revert MilestoneErrors.RaiseNotRejected(_raiseId);
        }

        // check if erc20 is set and deposited for claiming
        if (LibRaise.getRaiseType(_raiseId) == BaseTypes.RaiseType.EarlyStage) {
            _validateEarlyStageERC20(_raiseId);
        }
    }

    function _validateClaimRejectedInvestor(string memory _raiseId, address _recipient) internal view {
        // TODO: Check if base asset is on this chain

        // check if sender invested
        if (LibRaise.getInvestment(_raiseId, _recipient) == 0) {
            revert RaiseErrors.UserHasNotInvested(_recipient, _raiseId);
        }

        // check if raise was rejected
        if (LibMilestone.rejectedShares(_raiseId) == 0) {
            revert MilestoneErrors.RaiseNotRejected(_raiseId);
        }
    }

    // -----------------------------------------------------------------------
    //                              Get available (failed repair plan)
    // -----------------------------------------------------------------------

    function getRejectedForStartup(string memory _raiseId) external view returns (uint256) {
        // validation
        _validateCompletedRaise(_raiseId);
        _validateClaimRejectedStartup(_raiseId, msg.sender);

        // return
        return _getRejectedForStartup(_raiseId);
    }

    /// @dev Return available ERC20 to claim back for startup
    function _getRejectedForStartup(string memory _raiseId) internal view returns (uint256) {
        // get sold
        uint256 sold_ = LibRaise.getSold(_raiseId);

        // compute claimable
        uint256 claimable_ = (LibMilestone.rejectedShares(_raiseId) * sold_) / (100 * LibMilestone.SHARE_PRECISION);

        // get claimed
        uint256 claimed_ = LibMilestone.getStartupClaimedRejected(_raiseId);

        // return available
        return claimable_ - claimed_;
    }

    function getRejectedForInvestor(string memory _raiseId, address _account) external view returns (uint256) {
        // validation
        _validateCompletedRaise(_raiseId);
        _validateClaimRejectedInvestor(_raiseId, _account);

        // return
        return _getRejectedForInvestor(_raiseId, _account);
    }

    /// @dev Return available USDT to claim back for investor
    function _getRejectedForInvestor(string memory _raiseId, address _account) internal view returns (uint256) {
        // get investment
        uint256 invested_ = LibRaise.getInvestment(_raiseId, _account);

        // compute claimable
        uint256 claimable_ = (LibMilestone.rejectedShares(_raiseId) * invested_) / (100 * LibMilestone.SHARE_PRECISION);

        // get claimed
        uint256 claimed_ = LibMilestone.getInvestorClaimedRejected(_raiseId, _account);

        // return available
        return claimable_ - claimed_;
    }

    // -----------------------------------------------------------------------
    //                              Common
    // -----------------------------------------------------------------------

    function _validateRaiseExists(string memory _raiseId) internal view {
        // verify raise exists
        if (!LibRaise.raiseExists(_raiseId)) {
            revert RaiseErrors.RaiseDoesNotExists(_raiseId);
        }
    }

    function _validateCompletedRaise(string memory _raiseId) internal view {
        // verify raise exists
        _validateRaiseExists(_raiseId);

        // verify raise ended
        if (!LibRaise.isRaiseFinished(_raiseId)) {
            revert RaiseErrors.RaiseNotFinished(_raiseId);
        }

        // check if raise reach softcap
        if (!LibRaise.isSoftcapAchieved(_raiseId)) {
            revert RaiseErrors.SoftcapNotAchieved(_raiseId);
        }
    }

    function _validateEarlyStageERC20(string memory _raiseId) internal view {
        // get erc20
        address erc20_ = LibRaise.getVestedERC20(_raiseId);

        // check if erc20 address is set
        if (erc20_ == address(0)) revert RaiseErrors.TokenNotSet(_raiseId);

        // get escrow
        address escrow_ = LibEscrow.getEscrow(_raiseId);

        // check if erc20 is present on escrow for claiming
        if (IERC20(erc20_).balanceOf(escrow_) == 0) {
            revert MilestoneErrors.TokenNotOnEscrow(_raiseId);
        }
    }

    /// @dev Verify claim milestone message and signature.
    /// @dev Validation: Requires correct message with valid cosignature from AngelBlock validator to execute.
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function _verifyClaimMsgSig(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) internal view {
        // eip712 encoding
        bytes memory encodedMsg_ = MilestoneEncoder.encodeClaim(_request);

        // verify message
        LibSignature.verifyMessage(MilestoneConstants.EIP712_NAME, MilestoneConstants.EIP712_VERSION, keccak256(encodedMsg_), _message);

        // verify signature
        VerifySignatureMixin.verifySignature(_message, _v, _r, _s);
    }
}

File 2 of 37 : IERC1155Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155Upgradeable is IERC165Upgradeable {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 3 of 37 : IERC165Upgradeable.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 IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 4 of 37 : 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 5 of 37 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol)

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

File 6 of 37 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 8 of 37 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

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

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

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

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

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

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

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

File 9 of 37 : 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 10 of 37 : 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 11 of 37 : 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 12 of 37 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/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 13 of 37 : IDiamondCut.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    Diamond cut interface

    ------------------------------

    @author Nick Mudge

 **************************************/

interface IDiamondCut {
    // enum
    enum FacetCutAction {
        Add,
        Replace,
        Remove
    }

    // struct
    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    // event
    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);

    /**************************************

        Cut diamond

        ------------------------------

        @notice Add/replace/remove any number of functions and optionally execute a function with delegatecall
        @param _diamondCut Contains the facet addresses and function selectors
        @param _init The address of the contract or facet to execute _calldata
        @param _calldata A function call, including function selector and arguments, that is executed with delegatecall on _init

     **************************************/

    function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external;
}

File 14 of 37 : LibDiamond.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// Diamond imports
import { IDiamondCut } from "../interfaces/IDiamondCut.sol";

/**************************************

    Diamond library (EIP-2535)

    ------------------------------

    @author Nick Mudge

 **************************************/

/// @notice Main library with core logic for Diamond Proxy.
library LibDiamond {
    // -----------------------------------------------------------------------
    //                              Storage pointer
    // -----------------------------------------------------------------------

    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev struct holding facet address and selector position
    /// @param facetAddress address of facet
    /// @param functionSelectorPosition position in facetFunctionSelectors.functionSelectors array
    struct FacetAddressAndPosition {
        address facetAddress;
        uint16 functionSelectorPosition;
    }

    /// @dev struct holding facet selectors and address position
    /// @param functionSelectors list of function selectors for facet
    /// @param facetAddressPosition position of facetAddress in facetAddresses array
    struct FacetFunctionSelectors {
        bytes4[] functionSelectors;
        uint16 facetAddressPosition;
    }

    /// @dev diamond storage struct
    /// @param selectorToFacetAndPosition maps function selector in the facetFunctionSelectors.selectors array
    /// @param facetFunctionSelectors maps facet addresses to function selectors
    /// @param facetAddresses facet addresses
    /// @param supportedInterfaces Used to query if a contract implements an interface (ERC-165)
    /// @param contractOwner owner of the contract
    struct DiamondStorage {
        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
        address[] facetAddresses;
        mapping(bytes4 => bool) supportedInterfaces;
        address contractOwner;
    }

    // -----------------------------------------------------------------------
    //                              Events
    // -----------------------------------------------------------------------

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

    // -----------------------------------------------------------------------
    //                              Storage
    // -----------------------------------------------------------------------

    /// @dev function returning diamond storage at storage pointer slot
    /// @return ds DiamondStorage struct instance at storage pointer position
    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
        return ds;
    }

    // -----------------------------------------------------------------------
    //                              Ownership section
    // -----------------------------------------------------------------------

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsContractOwner() internal view {
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
    }

    // -----------------------------------------------------------------------
    //                              Diamond cut section
    // -----------------------------------------------------------------------

    // Internal function version of diamondCut
    function diamondCut(IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata) internal {
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else {
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // uint16 selectorCount = uint16(diamondStorage().selectors.length);
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
            ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
            ds.facetAddresses.push(_facetAddress);
        }

        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
            ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
            ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
            selectorPosition++;
        }
    }

    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
            ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
            ds.facetAddresses.push(_facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
            removeFunction(oldFacetAddress, selector);
            // add function
            ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
            ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
            selectorPosition++;
        }
    }

    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // if function does not exist then do nothing and return
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            removeFunction(oldFacetAddress, selector);
        }
    }

    function removeFunction(address _facetAddress, bytes4 _selector) internal {
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
        // an immutable function is a function defined directly in a diamond
        require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
        // replace selector with last selector, then delete last selector
        uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
        uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
        // if not the same then replace _selector with lastSelector
        if (selectorPosition != lastSelectorPosition) {
            bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
            ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
            ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint16(selectorPosition);
        }
        // delete the last selector
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
        delete ds.selectorToFacetAndPosition[_selector];

        // if no more selectors for facet address then delete the facet address
        if (lastSelectorPosition == 0) {
            // replace facet address with last facet address and delete last facet address
            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
            uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
            if (facetAddressPosition != lastFacetAddressPosition) {
                address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = uint16(facetAddressPosition);
            }
            ds.facetAddresses.pop();
            delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
        }
    }

    // -----------------------------------------------------------------------
    //                              Functions
    // -----------------------------------------------------------------------

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
        } else {
            require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
            if (_init != address(this)) {
                enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (!success) {
                if (error.length > 0) {
                    // bubble up the error
                    revert(string(error));
                } else {
                    revert("LibDiamondCut: _init function reverted");
                }
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

File 15 of 37 : MilestoneConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/// @notice Constants used in milestone facet and milestone encoder.
library MilestoneConstants {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    // versioning: "release:major:minor"
    bytes32 constant EIP712_NAME = keccak256(bytes("Fundraising:Milestone"));
    bytes32 constant EIP712_VERSION = keccak256(bytes("1:1:0"));

    // typehashes
    bytes32 constant VOTING_UNLOCK_MILESTONE_TYPEHASH = keccak256("UnlockMilestoneRequest(string raiseId,bytes milestone,bytes base)");
    bytes32 constant VOTING_REJECT_RAISE_TYPEHASH = keccak256("RejectRaiseRequest(string raiseId,bytes base)");
    bytes32 constant USER_CLAIM_TYPEHASH = keccak256("ClaimRequest(string raiseId,address recipient,bytes base)");
}

File 16 of 37 : MilestoneEncoder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// Local imports
import { MilestoneConstants } from "../constants/MilestoneConstants.sol";
import { RequestTypes } from "../structs/RequestTypes.sol";

/**************************************

    Milestone encoder

**************************************/

/// @notice Milestone encoder for EIP712 message hash.
library MilestoneEncoder {
    /// @dev Encode unlock milestone request to validate the EIP712 message.
    /// @param _request UnlockMilestoneRequest struct
    /// @return EIP712 encoded message containing request
    function encodeUnlockMilestone(RequestTypes.UnlockMilestoneRequest memory _request) internal pure returns (bytes memory) {
        // milestone
        bytes memory encodedMilestone_ = abi.encode(_request.milestone);

        // base
        bytes memory encodedBase_ = abi.encode(_request.base);

        // msg
        bytes memory encodedMsg_ = abi.encode(
            MilestoneConstants.VOTING_UNLOCK_MILESTONE_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            keccak256(encodedMilestone_),
            keccak256(encodedBase_)
        );

        // return
        return encodedMsg_;
    }

    /// @dev Encode claim milestone request to validate the EIP712 message.
    /// @param _request ClaimRequest struct
    /// @return EIP712 encoded message containing request
    function encodeClaim(RequestTypes.ClaimRequest memory _request) internal pure returns (bytes memory) {
        // base
        bytes memory encodedBase_ = abi.encode(_request.base);

        // msg
        bytes memory encodedMsg_ = abi.encode(
            MilestoneConstants.USER_CLAIM_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            _request.recipient,
            keccak256(encodedBase_)
        );

        // return
        return encodedMsg_;
    }

    /// @dev Encode reject raise request to validate the EIP712 message.
    /// @param _request RejectRaiseRequest struct
    /// @return EIP712 encoded message containing request
    function encodeRejectRaise(RequestTypes.RejectRaiseRequest memory _request) internal pure returns (bytes memory) {
        // base
        bytes memory encodedBase_ = abi.encode(_request.base);

        // msg
        bytes memory encodedMsg_ = abi.encode(
            MilestoneConstants.VOTING_REJECT_RAISE_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            keccak256(encodedBase_)
        );

        // return
        return encodedMsg_;
    }
}

File 17 of 37 : MilestoneErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/**************************************

    Milestone errors

**************************************/

/// All errors connected with milestone.
library MilestoneErrors {
    // -----------------------------------------------------------------------
    //                              Unlock
    // -----------------------------------------------------------------------

    error InvalidMilestoneNumber(uint256 milestoneNo, uint256 milestoneCount); // 0x14dc2b26
    error ZeroShare(uint256 milestoneNo); // 0xef647f82
    error ShareExceedLimit(uint256 share, uint256 existing); // 0x17e013d5

    // -----------------------------------------------------------------------
    //                              Claim
    // -----------------------------------------------------------------------

    error TokenNotOnEscrow(string raiseId); // 0x35880bf8
    error NothingToClaim(string raiseId, address account); // 0xf5709e8a

    // -----------------------------------------------------------------------
    //                              Failed repair plan
    // -----------------------------------------------------------------------

    error RaiseAlreadyRejected(string raiseId, uint256 rejected); // 0xcb1dc2af
    error AllMilestonesUnlocked(string raiseId, uint256 unlocked); // 0x731a1b87

    // -----------------------------------------------------------------------
    //                              Claim (repair plan)
    // -----------------------------------------------------------------------

    error RaiseNotRejected(string raiseId); // 0x4e9e01f8
}

File 18 of 37 : RaiseErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/**************************************

    Raise errors

**************************************/

/// All errors connected with raises.
library RaiseErrors {
    // -----------------------------------------------------------------------
    //                              Raise Creation
    // -----------------------------------------------------------------------

    error InvalidRaiseId(string raiseId); // 0xc2f9a803
    error InvalidRaiseStartEnd(uint256 start, uint256 end); // 0xb2fb4a1d
    error InvalidVestedAmount(); // 0x17329d67
    error PriceNotMatchConfiguration(uint256 price, uint256 hardcap, uint256 vested); // 0x643c0fc5
    error InvalidTokenAddress(address token); // 0x73306803

    // -----------------------------------------------------------------------
    //                              Early Stage
    // -----------------------------------------------------------------------

    error OnlyForEarlyStage(string raiseId); // 0x2e14bd97
    error CannotForEarlyStage(string raiseId); // 0x28471ed7
    error TokenAlreadySet(string raiseId); // 0x11f125e1
    error TokenNotSet(string raiseId); // 0x64d2ac41

    // -----------------------------------------------------------------------
    //                              Investing
    // -----------------------------------------------------------------------

    error IncorrectAmount(uint256 amount); // 0x88967d2f
    error OwnerCannotInvest(address sender, string raiseId); // 0x44b4eea9
    error InvestmentOverLimit(uint256 existingInvestment, uint256 newInvestment, uint256 maxTicketSize); // 0x3ebbf796
    error InvestmentOverHardcap(uint256 existingInvestment, uint256 newInvestment, uint256 hardcap); // 0xf0152bdf
    error NotEnoughBalanceForInvestment(address sender, uint256 investment); // 0xaff6db15
    error NotEnoughAllowance(address sender, address spender, uint256 amount); // 0x892e7739

    // -----------------------------------------------------------------------
    //                              Raise State
    // -----------------------------------------------------------------------

    error RaiseAlreadyExists(string raiseId); // 0xa7bb9fe0
    error RaiseDoesNotExists(string raiseId); // 0x78134459
    error RaiseNotActive(string raiseId, uint256 currentTime); // 0x251061ff
    error RaiseNotFinished(string raiseId); // 0xab91f47a

    // -----------------------------------------------------------------------
    //                              Softcap / Hardcap
    // -----------------------------------------------------------------------

    error SoftcapAchieved(string raiseId); // 0x17d74e3f
    error SoftcapNotAchieved(string raiseId); // 0x63117c7e

    // -----------------------------------------------------------------------
    //                              Reclaim
    // -----------------------------------------------------------------------

    error NothingToReclaim(string raiseId); // 0xf803caaa
    error AlreadyReclaimed(string raiseId); // 0x5ab9f7ef

    // -----------------------------------------------------------------------
    //                              Refund
    // -----------------------------------------------------------------------

    error UserHasNotInvested(address sender, string raiseId); // 0xf2ed8df2
    error CallerNotStartup(address sender, string raiseId); // 0x73810657
    error InvestorAlreadyRefunded(address sender, string raiseId); // 0x2eff5e61
    error CollateralAlreadyRefunded(string raiseId); // 0xc4543938
}

File 19 of 37 : RequestErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/**************************************

    Request errors

**************************************/

/// All errors connected with secure communication.
library RequestErrors {
    // -----------------------------------------------------------------------
    //                              Request
    // -----------------------------------------------------------------------

    error RequestExpired(address sender, uint256 expiry); // 0x8a288b92
    error NonceExpired(address sender, uint256 nonce); // 0x2b6069a9
    error IncorrectSender(address sender); // 0x7da9057e
}

File 20 of 37 : MilestoneEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

import { BaseTypes } from "../structs/BaseTypes.sol";

/**************************************

    Milestone events

**************************************/

/// All events connected with milestones.
library MilestoneEvents {
    // -----------------------------------------------------------------------
    //                              Unlock of milestone
    // -----------------------------------------------------------------------

    event MilestoneUnlocked(string raiseId, BaseTypes.Milestone milestone);
    event MilestoneUnlocked__StartupClaimed(string raiseId, address startup, uint256 claimed);
    event MilestoneUnlocked__InvestorClaimed(string raiseId, address erc20, address investor, uint256 claimed);

    // -----------------------------------------------------------------------
    //                              Failed repair plan
    // -----------------------------------------------------------------------

    event RaiseRejected(string raiseId, uint256 rejectedShares);
    event RaiseRejected__StartupClaimed(string raiseId, address erc20, address startup, uint256 claimed);
    event RaiseRejected__InvestorClaimed(string raiseId, address investor, uint256 claimed);
}

File 21 of 37 : IEscrow.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/// @notice Interface for escrow contract.
interface IEscrow {
    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Struct used in 'withdraw' and 'batchWithdraw' function to store receiver data.
    /// @param receiver Receiver address
    /// @param amount Amount to send for the given receiver
    struct ReceiverData {
        address receiver;
        uint256 amount;
    }

    // -----------------------------------------------------------------------
    //                              Events
    // -----------------------------------------------------------------------

    event Withdraw(address token, address receiver, uint256 amount);

    // -----------------------------------------------------------------------
    //                              Errors
    // -----------------------------------------------------------------------

    error InvalidSender(address sender, address expected); // 0xe1130dba
    error DataMismatch(); // 0x866c41db

    // -----------------------------------------------------------------------
    //                          External functions
    // -----------------------------------------------------------------------

    /// @dev Withdrawal of asset from escrow to user.
    /// @param _token Token to transfer
    /// @param _receiverData Receiver data (address and amount)
    function withdraw(address _token, ReceiverData calldata _receiverData) external;

    /// @dev Withdrawal of asset in batch from escrow to users.
    /// @param _token Token to transfer
    /// @param _receiverData Array of receivers data (addresses and amounts)
    function batchWithdraw(address _token, ReceiverData[] calldata _receiverData) external;
}

File 22 of 37 : IMilestoneFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// Local imports
import { RequestTypes } from "../structs/RequestTypes.sol";

/**************************************

    Milestone facet interface

**************************************/

/// @notice Interface for milestone facet.
interface IMilestoneFacet {
    // -----------------------------------------------------------------------
    //                              Unlock
    // -----------------------------------------------------------------------

    /// @dev Unlock new milestone for given raise.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Milestone data needs to have correct number and share under 100% cap in total.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: MilestoneUnlocked(string raiseId, BaseTypes.Milestone milestone).
    /// @param _request UnlockMilestoneRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function unlockMilestone(RequestTypes.UnlockMilestoneRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    // -----------------------------------------------------------------------
    //                              Claim
    // -----------------------------------------------------------------------

    /// @dev Claim milestone by startup.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: StartupClaimed(string raiseId, address startup, uint256 claimed).
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimMilestoneStartup(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    /// @dev Claim milestone by investor.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by user that invested in raise.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: InvestorClaimed(string raiseId, address erc20, address investor, uint256 claimed).
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimMilestoneInvestor(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    // -----------------------------------------------------------------------
    //                              Get available for claim
    // -----------------------------------------------------------------------

    /// @dev Get available funds to claim upon unlocked milestones by startup.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @param _raiseId ID of raise
    /// @return Amount of USDT available for claim
    function getAvailableForStartup(string memory _raiseId) external view returns (uint256);

    /// @dev Get available funds to claim upon unlocked milestones by investor.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @param _raiseId ID of raise
    /// @param _account Address of investor
    /// @return Amount of ERC20 available for claim
    function getAvailableForInvestor(string memory _raiseId, address _account) external view returns (uint256);

    // -----------------------------------------------------------------------
    //                              Reject raise
    // -----------------------------------------------------------------------

    /// @dev Reject raise for failed repair plan scenario.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: RaiseRejected(string raiseId).
    /// @param _request RejectRaiseRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function rejectRaise(RequestTypes.RejectRaiseRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    // -----------------------------------------------------------------------
    //                              Claim rejected
    // -----------------------------------------------------------------------

    /// @dev Claim rejected funds (failed repair plan) by startup.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: StartupClaimedRejected(string raiseId, address erc20, address startup, uint256 claimed).
    /// @param _request ClaimRejectedRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimRejectedStartup(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    /// @dev Claim rejected funds (failed repair plan) by investor.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by user that invested in raise.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: InvestorClaimedRejected(string raiseId, address investor, uint256 claimed).
    /// @param _request ClaimRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function claimRejectedInvestor(RequestTypes.ClaimRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    // -----------------------------------------------------------------------
    //                              Get rejected for claim
    // -----------------------------------------------------------------------

    /// @dev Get available funds to claim for not unlocked milestones in rejected repair plan by startup.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @dev Validation: Can be only called by raise owner (startup).
    /// @param _raiseId ID of raise
    /// @return Amount of USDT available for claim
    function getRejectedForStartup(string memory _raiseId) external view returns (uint256);

    /// @dev Get available funds to claim for not unlocked milestones in rejected repair plan by investor.
    /// @dev Validation: Requires raise that is finished and has reached softcap.
    /// @param _raiseId ID of raise
    /// @param _account Address of investor
    /// @return Amount of ERC20 available for claim
    function getRejectedForInvestor(string memory _raiseId, address _account) external view returns (uint256);
}

File 23 of 37 : LibAccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin imports
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";

/**************************************

    AccessControl library

    ------------------------------

    Diamond storage containing access control data

 **************************************/

/// @notice Fork of OpenZeppelin's AccessControl that fits as diamond proxy library.
library LibAccessControl {
    // -----------------------------------------------------------------------
    //                              Storage pointer
    // -----------------------------------------------------------------------

    /// @dev Access control storage pointer.
    bytes32 constant ACCESS_CONTROL_STORAGE_POSITION = keccak256("angelblock.access.control");

    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Default admin role
    bytes32 public constant ADMIN_ROLE = 0x00;

    // -----------------------------------------------------------------------
    //                                  Structs
    // -----------------------------------------------------------------------

    /// @dev Struct containing role settings.
    /// @param members Mapping of addresses, that returns True if user is a member
    /// @param adminRole Byte-encoded string of admin role for given role
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    /// @dev Access control storage struct.
    /// @param roles Mapping of byte-encoded strings of roles to RoleData struct
    /// @param initialized Used to allow and keep track of admin to be created once
    struct AccessControlStorage {
        mapping(bytes32 => RoleData) roles;
        bool initialized;
    }

    // -----------------------------------------------------------------------
    //                                  Events
    // -----------------------------------------------------------------------

    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    // -----------------------------------------------------------------------
    //                                  Errors
    // -----------------------------------------------------------------------

    error CannotSetAdminForAdmin(); // 0x625dd4af
    error CanOnlyRenounceSelf(); // 0x4b47a2fd

    // -----------------------------------------------------------------------
    //                                  Modifiers
    // -----------------------------------------------------------------------

    /// @dev Modifier that checks if caller has given role.
    /// @dev Validation: Expect caller to be a member of role.
    /// @param _role Expected role for sender to be a member of
    modifier onlyRole(bytes32 _role) {
        // check role
        if (!hasRole(_role, msg.sender)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(msg.sender),
                        " is missing role ",
                        Strings.toHexString(uint256(_role), 32)
                    )
                )
            );
        }
        _;
    }

    // -----------------------------------------------------------------------
    //                                  Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning access control storage at storage pointer slot.
    /// @return acs AccessControlStorage struct instance at storage pointer position
    function accessStorage() internal pure returns (AccessControlStorage storage acs) {
        // declare position
        bytes32 position = ACCESS_CONTROL_STORAGE_POSITION;

        // set slot to position
        assembly {
            acs.slot := position
        }

        // explicit return
        return acs;
    }

    // -----------------------------------------------------------------------
    //                              Getters / setters
    // -----------------------------------------------------------------------

    /// @dev Diamond storage getter: roles->hasRole(account).
    /// @param _role Byte-encoded role
    /// @param _account Address to check role
    /// @return True if account is member of given role
    function hasRole(bytes32 _role, address _account) internal view returns (bool) {
        // return
        return accessStorage().roles[_role].members[_account];
    }

    /// @dev Diamond storage setter: roles->setAdmin(account).
    /// @param _account Address to become an admin
    function createAdmin(address _account) internal {
        // set role
        accessStorage().roles[ADMIN_ROLE].members[_account] = true;
    }

    /// @dev Diamond storage getter: roles->getAdminRole(role).
    /// @param _role Byte-encoded role
    /// @return Admin role for given role
    function getRoleAdmin(bytes32 _role) internal view returns (bytes32) {
        // return
        return accessStorage().roles[_role].adminRole;
    }

    /// @dev Diamond storage setter: roles->setAdminRole(role).
    /// @dev Validation: Only main admin role can change admin role for given role.
    /// @dev Validation: Admin role for default admin role cannot be changed.
    /// @param _role Byte-encoded role to set admin role
    /// @param _adminRole Byte-encoded admin role for given role
    function setRoleAdmin(bytes32 _role, bytes32 _adminRole) internal onlyRole(ADMIN_ROLE) {
        // accept each role except admin
        if (_role != ADMIN_ROLE) accessStorage().roles[_role].adminRole = _adminRole;
        else revert CannotSetAdminForAdmin();
    }

    // -----------------------------------------------------------------------
    //                              Functions
    // -----------------------------------------------------------------------

    /**************************************

        Grant role

     **************************************/

    /// @dev Grant role to an account.
    /// @dev Validation: Can only be called by the admin of the role.
    /// @dev Validation: Will not grant role if account already has a desired role.
    /// @dev Events: RoleGranted(bytes32 role, address account, address sender).
    /// @param _role Byte-encoded role
    /// @param _account Address to receive a role
    function grantRole(bytes32 _role, address _account) internal onlyRole(getRoleAdmin(_role)) {
        // grant
        _grantRole(_role, _account);
    }

    /**************************************

        Revoke role

     **************************************/

    /// @dev Revoke role of account. Will not revoke role if account doesn't have it.
    /// @dev Validation: Can only be called by the admin of the role.
    /// @dev Events: RoleRevoked(bytes32 role, address account, address sender).
    /// @param _role Byte-encoded role
    /// @param _account Address of account that has role
    function revokeRole(bytes32 _role, address _account) internal onlyRole(getRoleAdmin(_role)) {
        // revoke
        _revokeRole(_role, _account);
    }

    /**************************************

        Renounce role

     **************************************/

    /// @dev Renounce role of account. Will not renounce role if account doesn't have it.
    /// @dev Validation: Can only be called by the user that has role.
    /// @dev Events: RoleRevoked(bytes32 role, address account, address sender).
    /// @param _role Byte-encoded role
    /// @param _account Address of account that has role
    function renounceRole(bytes32 _role, address _account) internal {
        // check sender
        if (_account != msg.sender) {
            revert CanOnlyRenounceSelf();
        }

        // revoke
        _revokeRole(_role, _account);
    }

    /**************************************

        Low level: grant

     **************************************/

    /// @dev Grant role to an account.
    /// @dev Validation: Will not grant role if account already has a desired role.
    /// @dev Events: RoleGranted(bytes32 role, address account, address sender).
    /// @param _role Byte-encoded role
    /// @param _account Address to receive a role
    function _grantRole(bytes32 _role, address _account) private {
        // check if not have role already
        if (!hasRole(_role, _account)) {
            // grant role
            accessStorage().roles[_role].members[_account] = true;

            // event
            emit RoleGranted(_role, _account, msg.sender);
        }
    }

    /**************************************

        Low level: revoke

     **************************************/

    /// @dev Revoke role of an account. Will not revoke role if account doesn't have it.
    /// @dev Events: RoleRevoked(bytes32 role, address account, address sender).
    /// @param _role Byte-encoded role
    /// @param _account Address of account that has role
    function _revokeRole(bytes32 _role, address _account) private {
        // check if have role
        if (hasRole(_role, _account)) {
            // revoke role
            accessStorage().roles[_role].members[_account] = false;

            // event
            emit RoleRevoked(_role, _account, msg.sender);
        }
    }
}

File 24 of 37 : LibAppStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IEquityBadge } from "../../interfaces/IEquityBadge.sol";

/**************************************

    AppStorage library

    ------------------------------

    A specialized version of Diamond Storage is AppStorage.
    This pattern is used to more conveniently and easily share state variables between facets.

 **************************************/

/// @notice AppStorage is a special type of diamond storage under slot 0.
/// @dev AppStorage is the only diamond library (with storage) that can be imported in other diamond storages.
/// @dev Used to mainly store addresses of contracts cross referenced across different modules.
library LibAppStorage {
    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev App storage struct. Special type of diamond storage with no storage pointer.
    /// @param usdt USDT token
    /// @param equityBadge Equity badge
    struct AppStorage {
        IERC20 usdt;
        IEquityBadge equityBadge;
    }

    // -----------------------------------------------------------------------
    //                              Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning app storage at 0 slot.
    /// @return s AppStorage struct instance at 0 slot
    function appStorage() internal pure returns (AppStorage storage s) {
        // set slot 0 and return
        assembly {
            s.slot := 0
        }

        // explicit return
        return s;
    }

    // -----------------------------------------------------------------------
    //                              Getters
    // -----------------------------------------------------------------------

    /**************************************

        Get USDT

     **************************************/

    /// @dev Get USDT.
    /// @return IERC20 interface of USDT address
    function getUSDT() internal view returns (IERC20) {
        // return
        return appStorage().usdt;
    }

    /**************************************

        Get badge

     **************************************/

    /// @dev Get equity badge.
    /// @return Equity badge contract instance
    function getBadge() internal view returns (IEquityBadge) {
        // return
        return appStorage().equityBadge;
    }
}

File 25 of 37 : LibEscrow.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";

// Interfaces
import { Configurable } from "../../utils/Configurable.sol";

/**************************************

    Escrow library

    ------------------------------

    Diamond storage containing escrows data.

 **************************************/

/// @notice Library containing EscrowStorage and low level functions.
library LibEscrow {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Escrow storage pointer.
    bytes32 constant ESCROW_STORAGE_POSITION = keccak256("angelblock.fundraising.escrow");

    // -----------------------------------------------------------------------
    //                              Events
    // -----------------------------------------------------------------------

    event EscrowCreated(string raiseId, address instance, address source);

    // -----------------------------------------------------------------------
    //                                  Errors
    // -----------------------------------------------------------------------

    error SourceNotSet(); // 0x5646f850

    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Escrow diamond storage.
    /// @param source Address of contract with source implementation for cloning Escrows.
    /// @param escrows Mapping of raise id to cloned Escrow instance address.
    struct EscrowStorage {
        address source;
        mapping(string => address) escrows;
    }

    // -----------------------------------------------------------------------
    //                              Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning escrow storage at storage pointer slot.
    /// @return es EscrowStorage struct instance at storage pointer position
    function escrowStorage() internal pure returns (EscrowStorage storage es) {
        // declare position
        bytes32 position = ESCROW_STORAGE_POSITION;

        // set slot to position
        assembly {
            es.slot := position
        }

        // explicit return
        return es;
    }

    // -----------------------------------------------------------------------
    //                              Source section
    // -----------------------------------------------------------------------

    /// @dev Allows to set Escrows source contract address.
    /// @param _source New Escrow source contract address.
    function setSource(address _source) internal {
        // set source address
        escrowStorage().source = _source;
    }

    // -----------------------------------------------------------------------
    //                              Escrow section
    // -----------------------------------------------------------------------

    /// @dev Allows to fetch Escrow address for the given Raise id.
    /// @param _raiseId Id of the Raise.
    /// @return Escrow address.
    function getEscrow(string memory _raiseId) internal view returns (address) {
        // get escrow address
        return escrowStorage().escrows[_raiseId];
    }

    /// @dev Allows to create new Escrow contract.
    /// @dev Events: EscrowCreated(string raiseId, address instance, address source).
    /// @param _raiseId Id of the Raise for which Escrow will be created.
    /// @return escrow_ Newly created Escrow contract address
    function createEscrow(string memory _raiseId) internal returns (address escrow_) {
        // get storage
        EscrowStorage storage es = escrowStorage();

        // get Escrow source address
        address source_ = es.source;

        // validate if source is set
        if (source_ == address(0)) {
            revert SourceNotSet();
        }

        // create new Escrow - clone
        escrow_ = Clones.clone(source_);

        // configure Escrow
        Configurable(escrow_).configure(abi.encode(address(this)));

        // assing created Escrow address for given raise id
        es.escrows[_raiseId] = escrow_;

        // emit
        emit EscrowCreated(_raiseId, escrow_, source_);
    }
}

File 26 of 37 : LibMilestone.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin imports
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Local imports
import { LibAppStorage } from "./LibAppStorage.sol";
import { BaseTypes } from "../structs/BaseTypes.sol";
import { StateTypes } from "../structs/StateTypes.sol";
import { IEscrow } from "../interfaces/IEscrow.sol";

/**************************************

    Milestone library

    ------------------------------

    Diamond storage containing milestone data

 **************************************/

/// @notice Library containing MilestoneStorage and low level functions.
library LibMilestone {
    // -----------------------------------------------------------------------
    //                              Library usage
    // -----------------------------------------------------------------------

    using SafeERC20 for IERC20;

    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Milestone storage pointer.
    bytes32 constant MILESTONE_STORAGE_POSITION = keccak256("angelblock.fundraising.milestone");
    /// @dev Precision for share calculation.
    uint256 constant SHARE_PRECISION = 1_000_000;

    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Milestone storage struct.
    /// @param shares Mapping of raise id to struct containing share data
    /// @param votingClaiming Mapping of raise id to struct used to track claims after unlocked milestone
    /// @param repairPlanClaiming Mapping of raise id to struct used to track claims after failed repair plan
    struct MilestoneStorage {
        mapping(string => StateTypes.ShareInfo) shares;
        mapping(string => StateTypes.ClaimingInfo) votingClaiming;
        mapping(string => StateTypes.ClaimingInfo) repairPlanClaiming;
    }

    // -----------------------------------------------------------------------
    //                              Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning milestone storage at storage pointer slot.
    /// @return ms MilestoneStorage struct instance at storage pointer position
    function milestoneStorage() internal pure returns (MilestoneStorage storage ms) {
        // declare position
        bytes32 position = MILESTONE_STORAGE_POSITION;

        // set slot to position
        assembly {
            ms.slot := position
        }

        // explicit return
        return ms;
    }

    // -----------------------------------------------------------------------
    //                              Getters / Setters
    // -----------------------------------------------------------------------

    /// @dev Diamond storage getter: milestones->length.
    /// @param _raiseId ID of raise
    /// @return Length of milestones
    function milestoneCount(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().shares[_raiseId].milestones.length;
    }

    /// @dev Diamond storage getter: milestones->share->sum.
    /// @param _raiseId ID of raise
    /// @return Sum of milestone shares (successful voting)
    function unlockedShares(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().shares[_raiseId].unlockedShares;
    }

    /// @dev Diamond storage getter: milestones->rejected->sum.
    /// @param _raiseId ID of raise
    /// @return Sum of rejected shares (failed repair plan)
    function rejectedShares(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().shares[_raiseId].rejectedShares;
    }

    /// @dev Diamond storage getter: milestones->share+rejected->sum.
    /// @param _raiseId ID of raise
    /// @return Sum of unlocked and rejected shares
    function totalShares(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().shares[_raiseId].totalShares;
    }

    /// @dev Diamond storage getter: investor claimed.
    /// @param _raiseId ID of raise
    /// @param _account Address of investor
    /// @return Claimed tokens by investor
    function getInvestorClaimedVoting(string memory _raiseId, address _account) internal view returns (uint256) {
        // return
        return milestoneStorage().votingClaiming[_raiseId].investorClaimed[_account];
    }

    /// @dev Diamond storage getter: startup claimed.
    /// @param _raiseId ID of raise
    /// @return Claimed base assets by investor
    function getStartupClaimedVoting(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().votingClaiming[_raiseId].startupClaimed;
    }

    /// @dev Diamond storage getter: investor claimed.
    /// @param _raiseId ID of raise
    /// @param _account Address of investor
    /// @return Claimed tokens by investor
    function getInvestorClaimedRejected(string memory _raiseId, address _account) internal view returns (uint256) {
        // return
        return milestoneStorage().repairPlanClaiming[_raiseId].investorClaimed[_account];
    }

    /// @dev Diamond storage getter: startup claimed.
    /// @param _raiseId ID of raise
    /// @return Claimed base assets by investor
    function getStartupClaimedRejected(string memory _raiseId) internal view returns (uint256) {
        // return
        return milestoneStorage().repairPlanClaiming[_raiseId].startupClaimed;
    }

    // -----------------------------------------------------------------------
    //                              Unlock
    // -----------------------------------------------------------------------

    /// @dev Unlock new milestone for raise.
    /// @param _raiseId ID of raise
    /// @param _milestone Milestone struct
    function unlockMilestone(string memory _raiseId, BaseTypes.Milestone memory _milestone) internal {
        // get shares
        StateTypes.ShareInfo storage shares_ = milestoneStorage().shares[_raiseId];

        // register new unlocked milestone
        shares_.milestones.push(_milestone);

        // increase unlocked shares
        shares_.unlockedShares += _milestone.share;

        // increase total shares
        shares_.totalShares += _milestone.share;
    }

    // -----------------------------------------------------------------------
    //                              Claim
    // -----------------------------------------------------------------------

    /// @dev Claim milestone by startup.
    /// @param _raiseId ID of raise
    /// @param _escrow Address of escrow
    /// @param _recipient Address of startup
    /// @param _amount Tokens to claim
    function claimMilestoneStartup(string memory _raiseId, address _escrow, address _recipient, uint256 _amount) internal {
        // storage update
        milestoneStorage().votingClaiming[_raiseId].startupClaimed += _amount;

        // transfer USDT
        IEscrow(_escrow).withdraw(address(LibAppStorage.getUSDT()), IEscrow.ReceiverData(_recipient, _amount));
    }

    /// @dev Claim milestone by investor.
    /// @param _raiseId ID of raise
    /// @param _erc20 Address of token to claim
    /// @param _escrow Address of escrow
    /// @param _recipient Address of investor
    /// @param _amount Tokens to claim
    function claimMilestoneInvestor(string memory _raiseId, address _erc20, address _escrow, address _recipient, uint256 _amount) internal {
        // storage update
        milestoneStorage().votingClaiming[_raiseId].investorClaimed[_recipient] += _amount;

        // transfer ERC20
        IEscrow(_escrow).withdraw(_erc20, IEscrow.ReceiverData(_recipient, _amount));
    }

    // -----------------------------------------------------------------------
    //                              Reject raise
    // -----------------------------------------------------------------------

    /// @dev Reject raise to revert the rest of locked shares.
    /// @param _raiseId ID of raise
    /// @return Amount of rejected shares
    function rejectRaise(string memory _raiseId) internal returns (uint256) {
        // get existing unlocked and rejected shares
        uint256 existing_ = totalShares(_raiseId);

        // calculate still locked shares
        uint256 remaining_ = 100 * SHARE_PRECISION - existing_;

        // set rejected shares
        milestoneStorage().shares[_raiseId].rejectedShares += remaining_;

        // set total shares
        milestoneStorage().shares[_raiseId].totalShares += remaining_;

        // return
        return remaining_;
    }

    // -----------------------------------------------------------------------
    //                              Claim (failed repair plan)
    // -----------------------------------------------------------------------

    /// @dev Claim rejected repair plan funds by startup.
    /// @param _raiseId ID of raise
    /// @param _erc20 Address of token to claim
    /// @param _escrow Address of escrow
    /// @param _recipient Address of startup
    /// @param _amount Tokens to claim
    function claimRejectedStartup(string memory _raiseId, address _erc20, address _escrow, address _recipient, uint256 _amount) internal {
        // storage update
        milestoneStorage().repairPlanClaiming[_raiseId].startupClaimed += _amount;

        // transfer ERC20
        IEscrow(_escrow).withdraw(_erc20, IEscrow.ReceiverData(_recipient, _amount));
    }

    /// @dev Claim rejected repair plan funds by investor.
    /// @param _raiseId ID of raise
    /// @param _escrow Address of escrow
    /// @param _recipient Address of investor
    /// @param _amount Tokens to claim
    function claimRejectedInvestor(string memory _raiseId, address _escrow, address _recipient, uint256 _amount) internal {
        // storage update
        milestoneStorage().repairPlanClaiming[_raiseId].investorClaimed[_recipient] += _amount;

        // transfer USDT
        IEscrow(_escrow).withdraw(address(LibAppStorage.getUSDT()), IEscrow.ReceiverData(_recipient, _amount));
    }
}

File 27 of 37 : LibNonce.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/**************************************

    Nonce library

    ------------------------------

    Diamond storage containing nonces

 **************************************/

/// @notice Library implementing NonceStorage and functions.
library LibNonce {
    // -----------------------------------------------------------------------
    //                              Storage pointer
    // -----------------------------------------------------------------------

    /// @dev Storage pointer.
    bytes32 constant NONCE_STORAGE_POSITION = keccak256("angelblock.fundraising.nonce");

    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Nonce diamond storage.
    /// @param nonces Mapping of address to nonce information.
    struct NonceStorage {
        mapping(address => uint256) nonces;
    }

    // -----------------------------------------------------------------------
    //                              Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning nonce storage at storage pointer slot.
    /// @return ns NonceStorage struct instance at storage pointer position
    function nonceStorage() internal pure returns (NonceStorage storage ns) {
        // declare position
        bytes32 position = NONCE_STORAGE_POSITION;

        // set slot to position
        assembly {
            ns.slot := position
        }

        // explicit return
        return ns;
    }

    // -----------------------------------------------------------------------
    //                              Nonce section
    // -----------------------------------------------------------------------

    /// @dev Diamond storage getter: nonce per account.
    /// @param _account Address for which nonce should be checked
    /// @return Current nonce of account
    function getLastNonce(address _account) internal view returns (uint256) {
        // return
        return nonceStorage().nonces[_account];
    }

    /// @dev Diamond storage setter: nonce per account.
    /// @param _account Address for which nonce should be set
    /// @param _nonce New value for nonce
    function setNonce(address _account, uint256 _nonce) internal {
        // get storage
        NonceStorage storage ns = nonceStorage();

        // set nonce
        ns.nonces[_account] = _nonce;
    }
}

File 28 of 37 : LibRaise.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin imports
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Local imports
import { LibAppStorage } from "./LibAppStorage.sol";
import { IEscrow } from "../interfaces/IEscrow.sol";
import { IEquityBadge } from "../../interfaces/IEquityBadge.sol";
import { BaseTypes } from "../structs/BaseTypes.sol";
import { StateTypes } from "../structs/StateTypes.sol";
import { RaiseErrors } from "../errors/RaiseErrors.sol";

/**************************************

    Raise library

    ------------------------------

    Diamond storage containing raise data

 **************************************/

/// @notice Library containing RaiseStorage and low level functions.
library LibRaise {
    // -----------------------------------------------------------------------
    //                              Library usage
    // -----------------------------------------------------------------------

    using SafeERC20 for IERC20;

    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Raise storage pointer.
    bytes32 constant RAISE_STORAGE_POSITION = keccak256("angelblock.fundraising.raise");
    /// @dev Precision for reclaim calculations.
    uint256 constant PRICE_PRECISION = 10 ** 18;

    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Raise storage struct.
    /// @param raises Mapping of raise id to particular raise struct
    /// @param vested Mapping of raise id to vested token information
    /// @param investInfo Mapping of raise id to raise state information
    struct RaiseStorage {
        mapping(string => BaseTypes.Raise) raises;
        mapping(string => BaseTypes.Vested) vested;
        mapping(string => StateTypes.ProjectInvestInfo) investInfo;
    }

    // -----------------------------------------------------------------------
    //                              Diamond storage
    // -----------------------------------------------------------------------

    /// @dev Function returning raise storage at storage pointer slot.
    /// @return rs RaiseStorage struct instance at storage pointer position
    function raiseStorage() internal pure returns (RaiseStorage storage rs) {
        // declare position
        bytes32 position = RAISE_STORAGE_POSITION;

        // set slot to position
        assembly {
            rs.slot := position
        }

        // explicit return
        return rs;
    }

    // -----------------------------------------------------------------------
    //                              Getters / Setters
    // -----------------------------------------------------------------------

    /// @dev Diamond storage getter: raises->raiseType.
    /// @param _raiseId ID of raise
    /// @return Type of raise {Standard, EarlyStage}
    function getRaiseType(string memory _raiseId) internal view returns (BaseTypes.RaiseType) {
        return raiseStorage().raises[_raiseId].raiseType;
    }

    /// @dev Diamond storage getter: raises->owner.
    /// @param _raiseId ID of raise
    /// @return Owner of raise
    function getRaiseOwner(string memory _raiseId) internal view returns (address) {
        // return
        return raiseStorage().raises[_raiseId].owner;
    }

    /// @dev Diamond storage getter: hardcap.
    /// @param _raiseId ID of raise
    /// @return Hardcap of raise
    function getHardCap(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raises[_raiseId].raiseDetails.hardcap;
    }

    /// @dev Diamond storage getter: vested->erc20.
    /// @param _raiseId ID of raise
    /// @return ERC20 address of raise
    function getVestedERC20(string memory _raiseId) internal view returns (address) {
        // return
        return raiseStorage().vested[_raiseId].erc20;
    }

    /// @dev Diamond storage getter: vested->amount.
    /// @param _raiseId ID of raise
    /// @return Amount of vested ERC20 of raise
    function getVestedAmount(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().vested[_raiseId].amount;
    }

    /// @dev Diamond storage setter: vested->erc20.
    /// @param _raiseId ID of raise
    /// @param _token Address of ERC20
    function setVestedERC20(string memory _raiseId, address _token) internal {
        raiseStorage().vested[_raiseId].erc20 = _token;
    }

    /// @dev Diamond storage setter: raise.
    /// @param _raiseId ID of raise
    /// @param _raise Raise to save
    /// @param _vested Vested currency and amount to save for raise
    function saveRaise(string memory _raiseId, BaseTypes.Raise memory _raise, BaseTypes.Vested memory _vested) internal {
        // get storage
        RaiseStorage storage rs = raiseStorage();

        // save raise
        rs.raises[_raiseId] = _raise;
        rs.vested[_raiseId] = _vested;
    }

    /// @dev Diamond storage setter: investment.
    /// @param _raiseId ID of raise
    /// @param _investment Invested amount to save
    function saveInvestment(string memory _raiseId, uint256 _investment) internal {
        // tx.members
        address sender_ = msg.sender;

        // get storage
        RaiseStorage storage rs = raiseStorage();

        // save investment
        rs.investInfo[_raiseId].raised += _investment;
        rs.investInfo[_raiseId].invested[sender_] += _investment;
    }

    /// @dev Diamond storage getter: investment.
    /// @param _raiseId ID of raise
    /// @param _account Address to check investment for
    /// @return Amount of investment
    function getInvestment(string memory _raiseId, address _account) internal view returns (uint256) {
        // return
        return raiseStorage().investInfo[_raiseId].invested[_account];
    }

    /// @dev Diamond storage getter: total investment.
    /// @param _raiseId ID of raise
    /// @return Sum of all investments in raise
    function getTotalInvestment(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().investInfo[_raiseId].raised;
    }

    // -----------------------------------------------------------------------
    //                              Badge module
    // -----------------------------------------------------------------------

    /**************************************

        Convert raise id to badge id

     **************************************/

    /// @dev Convert raise to badge.
    /// @param _raiseId ID of raise
    /// @return ID of badge (derived from hash of raise ID)
    function convertRaiseToBadge(string memory _raiseId) internal pure returns (uint256) {
        // return
        return uint256(keccak256(abi.encode(_raiseId)));
    }

    /**************************************

        Mint badge

     **************************************/

    /// @dev Mint badge.
    /// @param _badgeId ID of badge
    /// @param _investment Amount of badges to mint is proportional to investment amount
    function mintBadge(uint256 _badgeId, uint256 _investment) internal {
        // tx.members
        address sender_ = msg.sender;

        // get badge
        IEquityBadge badge = LibAppStorage.getBadge();

        // erc1155 bytes conversion
        bytes memory data_ = abi.encode(_badgeId);

        // mint equity badge
        badge.mint(sender_, _badgeId, _investment, data_);
    }

    /**************************************

        Set token URI

     **************************************/

    /// @dev Set badge URI.
    /// @param _badgeId ID of badge
    /// @param _uri URI to set
    function setUri(uint256 _badgeId, string memory _uri) internal {
        // set uri
        LibAppStorage.getBadge().setURI(_badgeId, _uri);
    }

    // -----------------------------------------------------------------------
    //                              Raise module
    // -----------------------------------------------------------------------

    /**************************************

        Collect vested ERC20

     **************************************/

    /// @dev Collect vested ERC20 to start a raise.
    /// @dev Validation: Requires startup to have enough ERC20 and provide allowance.
    /// @dev Events: Transfer(address from, address to, uint256 value).
    /// @param _token Address of ERC20
    /// @param _sender Address of startup to withdraw ERC20 from
    /// @param _escrow Address of cloned Escrow instance for raise
    /// @param _amount Amount of ERC20 to collect
    function collectVestedToken(address _token, address _sender, address _escrow, uint256 _amount) internal {
        // tx.members
        address self_ = address(this);

        // erc20
        IERC20 erc20_ = IERC20(_token);

        // allowance check
        uint256 allowance_ = erc20_.allowance(_sender, self_);
        if (allowance_ < _amount) {
            revert RaiseErrors.NotEnoughAllowance(_sender, self_, allowance_);
        }

        // vest erc20
        erc20_.safeTransferFrom(_sender, _escrow, _amount);
    }

    /**************************************

        Collect USDT for investment

     **************************************/

    /// @dev Collect USDT from investor.
    /// @dev Validation: Requires investor to have assets and provide enough allowance.
    /// @dev Events: Transfer(address from, address to, uint256 value).
    /// @param _sender Address of investor
    /// @param _investment Amount of investment
    /// @param _escrow Address of escrow
    function collectUSDT(address _sender, uint256 _investment, address _escrow) internal {
        // get USDT contract
        IERC20 usdt_ = LibAppStorage.getUSDT();

        // check balance
        if (usdt_.balanceOf(_sender) < _investment) {
            revert RaiseErrors.NotEnoughBalanceForInvestment(_sender, _investment);
        }

        // check approval
        if (usdt_.allowance(_sender, address(this)) < _investment) {
            revert RaiseErrors.NotEnoughAllowance(_sender, address(this), _investment);
        }

        // transfer
        usdt_.safeTransferFrom(_sender, _escrow, _investment);
    }

    /**************************************

        Raise exists

     **************************************/

    /// @dev Check if raise exists.
    /// @param _raiseId ID of raise
    /// @return True if fundraising exists
    function raiseExists(string memory _raiseId) internal view returns (bool) {
        // return
        return bytes(raiseStorage().raises[_raiseId].raiseId).length != 0;
    }

    /**************************************

        Check if given raise is still active

     **************************************/

    /// @dev Check if raise is active.
    /// @param _raiseId ID of raise
    /// @return True if investment round is ongoing
    function isRaiseActive(string memory _raiseId) internal view returns (bool) {
        // tx.members
        uint256 now_ = block.timestamp;

        // get raise
        BaseTypes.Raise storage raise_ = raiseStorage().raises[_raiseId];

        // final check
        return raise_.raiseDetails.start <= now_ && now_ <= raise_.raiseDetails.end;
    }

    /**************************************

        Check if given raise finished already

     **************************************/

    /// @dev Check if raise is finished.
    /// @param _raiseId ID of raise
    /// @return True if investment round is finished
    function isRaiseFinished(string memory _raiseId) internal view returns (bool) {
        return raiseStorage().raises[_raiseId].raiseDetails.end < block.timestamp;
    }

    /**************************************

        Check if given raise achieved softcap

     **************************************/

    /// @dev Check if softcap was achieved.
    /// @param _raiseId ID of raise
    /// @return True if softcap was achieved
    function isSoftcapAchieved(string memory _raiseId) internal view returns (bool) {
        RaiseStorage storage rs = raiseStorage();
        return rs.raises[_raiseId].raiseDetails.softcap <= rs.investInfo[_raiseId].raised;
    }

    // -----------------------------------------------------------------------
    //                              Refund module
    // -----------------------------------------------------------------------

    /// @dev Check if USDT was refunded to investor.
    /// @param _raiseId ID of raise
    /// @param _account Address of investor
    /// @return True if investor was refunded
    function investmentRefunded(string memory _raiseId, address _account) internal view returns (bool) {
        return raiseStorage().investInfo[_raiseId].investmentRefunded[_account];
    }

    /// @dev Check if collateral was refunded to startup.
    /// @param _raiseId ID of raise
    /// @return True if startup was refunded
    function collateralRefunded(string memory _raiseId) internal view returns (bool) {
        return raiseStorage().investInfo[_raiseId].collateralRefunded;
    }

    /**************************************

        Make raise refund for given wallet

     **************************************/

    /// @dev Refund USDT to investor.
    /// @dev Events: Escrow.Withdraw(address token, address receiver, uint256 amount).
    /// @param _sender Address of receiver
    /// @param _escrow Address of escrow
    /// @param _raiseId ID of raise
    /// @param _investment Amount of invested USDT
    function refundUSDT(address _sender, address _escrow, string memory _raiseId, uint256 _investment) internal {
        // prepare for transfer
        RaiseStorage storage rs = raiseStorage();
        rs.investInfo[_raiseId].investmentRefunded[_sender] = true;

        // get USDT token address
        address usdt_ = address(LibAppStorage.getUSDT());

        // prepare Escrow 'ReceiverData'
        IEscrow.ReceiverData memory receiverData_ = IEscrow.ReceiverData({ receiver: _sender, amount: _investment });

        // transfer
        IEscrow(_escrow).withdraw(usdt_, receiverData_);
    }

    /**************************************

        Refund startup

     **************************************/

    /// @dev Refund collateral to startup.
    /// @dev Events: Escrow.Withdraw(address token, address receiver, uint256 amount).
    /// @param _sender Address of recipient
    /// @param _escrow Address of escrow
    /// @param _raiseId ID of raise
    /// @param _collateral Amount of deposited ERC20
    function refundCollateral(address _sender, address _escrow, string memory _raiseId, uint256 _collateral) internal {
        // load storage
        RaiseStorage storage rs = raiseStorage();

        // prepare for transfer
        rs.investInfo[_raiseId].collateralRefunded = true;

        // get vested token address
        address vestedToken_ = getVestedERC20(_raiseId);

        // prepare Escrow 'ReceiverData'
        IEscrow.ReceiverData memory receiverData_ = IEscrow.ReceiverData({ receiver: _sender, amount: _collateral });

        // transfer
        IEscrow(_escrow).withdraw(vestedToken_, receiverData_);
    }

    // -----------------------------------------------------------------------
    //                              Reclaim module
    // -----------------------------------------------------------------------

    /**************************************

        Get sold tokens

     **************************************/

    /// @dev Get amount of sold tokens.
    /// @param _raiseId ID of raise
    /// @return Amount of tokens to claim by investor
    function getSold(string memory _raiseId) internal view returns (uint256) {
        // load storage
        RaiseStorage storage rs = raiseStorage();

        // get price (ratio of 1 wei of base asset to wei of token)
        BaseTypes.Price memory price_ = rs.raises[_raiseId].raiseDetails.price;

        // get raised
        uint256 raised_ = rs.investInfo[_raiseId].raised;

        // calculate how much tokens are sold
        return (price_.tokensPerBaseAsset * raised_) / PRICE_PRECISION;
    }

    /**************************************

        Get unsold tokens

     **************************************/

    /// @dev Get amount of unsold tokens.
    /// @param _raiseId ID of raise
    /// @return Amount of tokens to reclaim by startup
    function getUnsold(string memory _raiseId) internal view returns (uint256) {
        // load storage
        RaiseStorage storage rs = raiseStorage();

        // get all vested tokens
        uint256 vested_ = rs.vested[_raiseId].amount;

        // get sold tokens
        uint256 sold_ = getSold(_raiseId);

        // return
        return vested_ - sold_;
    }

    /**************************************

        Reclaim unsold tokens

     **************************************/

    /// @dev Reclaim unsold tokens.
    /// @dev Events: Escrow.Withdraw(address token, address receiver, uint256 amount).
    /// @param _escrow Escrow address
    /// @param _sender Receiver address
    /// @param _raiseId ID of raise
    /// @param _unsold Amount of tokens to reclaim
    function reclaimUnsold(address _escrow, address _sender, string memory _raiseId, uint256 _unsold) internal {
        // get erc20
        address erc20_ = raiseStorage().vested[_raiseId].erc20;

        // prepare data
        IEscrow.ReceiverData memory receiverData_ = IEscrow.ReceiverData({ receiver: _sender, amount: _unsold });

        // send tokens
        IEscrow(_escrow).withdraw(erc20_, receiverData_);
    }
}

File 29 of 37 : LibRequest.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// Local imports
import { LibNonce } from "./LibNonce.sol";
import { RequestTypes } from "../structs/RequestTypes.sol";
import { RequestErrors } from "../errors/RequestErrors.sol";

/**************************************

    Request library

**************************************/

library LibRequest {
    // -----------------------------------------------------------------------
    //                              Internal
    // -----------------------------------------------------------------------

    function validateBaseRequest(RequestTypes.BaseRequest memory _baseRequest) internal view {
        // tx.members
        address sender_ = msg.sender;
        uint256 now_ = block.timestamp;

        // check replay attack
        uint256 nonce_ = _baseRequest.nonce;
        if (nonce_ <= LibNonce.getLastNonce(sender_)) {
            revert RequestErrors.NonceExpired(sender_, nonce_);
        }

        // check request expiration
        if (now_ > _baseRequest.expiry) {
            revert RequestErrors.RequestExpired(sender_, _baseRequest.expiry);
        }

        // check request sender
        if (sender_ != _baseRequest.sender) {
            revert RequestErrors.IncorrectSender(sender_);
        }
    }
}

File 30 of 37 : VerifySignatureMixin.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// Local imports
import { AccessTypes } from "../structs/AccessTypes.sol";
import { LibAccessControl } from "../libraries/LibAccessControl.sol";
import { LibSignature } from "../../libraries/LibSignature.sol";

/**************************************

    Verify signature mixin

**************************************/

/// @notice Mixin that injects signature verification into facets.
library VerifySignatureMixin {
    // -----------------------------------------------------------------------
    //                              Errors
    // -----------------------------------------------------------------------

    error IncorrectSigner(address signer); // 0x33ffff9b

    // -----------------------------------------------------------------------
    //                              Functions
    // -----------------------------------------------------------------------

    /// @dev Verify signature.
    /// @dev Validation: Fails if message is signed by account without signer role.
    /// @param _message Hash of message
    /// @param _v Part of signature
    /// @param _r Part of signature
    /// @param _s Part of signature
    function verifySignature(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) internal view {
        // signer of message
        address signer_ = LibSignature.recoverSigner(_message, _v, _r, _s);

        // validate signer
        if (!LibAccessControl.hasRole(AccessTypes.SIGNER_ROLE, signer_)) {
            revert IncorrectSigner(signer_);
        }
    }
}

File 31 of 37 : AccessTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/// @notice Library containing role definition for access management.
library AccessTypes {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev AngelBlock validator role
    bytes32 constant SIGNER_ROLE = keccak256("IS SIGNER");
}

File 32 of 37 : BaseTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/// @notice Library with core types definition.
library BaseTypes {
    // -----------------------------------------------------------------------
    //                              Enums
    // -----------------------------------------------------------------------

    /// @dev Definition of base asset for investment.
    enum Asset {
        USDT,
        AZERO
    }

    /// @dev Definition of supported types of raises.
    enum RaiseType {
        Standard,
        EarlyStage
    }

    // -----------------------------------------------------------------------
    //                              Enums
    // -----------------------------------------------------------------------

    /// @dev Struct containing price information.
    /// @param tokensPerBaseAsset Ratio of how much tokens is worth 1 unit of base asset (vested * precision / hardcap)
    /// @param asset Supported base asset for investment
    struct Price {
        uint256 tokensPerBaseAsset;
        Asset asset;
    }

    /// @dev Struct containing detailed info about raise.
    /// @param price Struct containing price information
    /// @param hardcap Max amount of base asset to collect during a raise
    /// @param softcap Min amount of base asset to collect during a raise
    /// @param start Start date of raise
    /// @param end End date of raise
    /// @param badgeUri IPFS URI that initializes equity badge for the raise
    struct RaiseDetails {
        Price price;
        uint256 hardcap;
        uint256 softcap;
        uint256 start;
        uint256 end;
        string badgeUri;
    }

    /// @dev Struct containing all information about the raise.
    /// @param raiseId UUID of raise
    /// @param raiseType Type of raise
    /// @param raiseDetails Struct containing detailed info about raise
    /// @param owner Address of startup
    struct Raise {
        string raiseId;
        RaiseType raiseType;
        RaiseDetails raiseDetails;
        address owner;
    }

    /// @dev Struct containing info about vested token accredited for investing.
    /// @param erc20 Address of vested token
    /// @param amount Amount of vested ERC20
    struct Vested {
        address erc20;
        uint256 amount;
    }

    /// @dev Struct containing info about milestone and shares it's unlocking.
    /// @param milestoneId UUID of milestone
    /// @param milestoneNo Index of milestone (counted from 1)
    /// @param share % of unlocked tokens (12.5% = 12.5 * 1_000_000)
    struct Milestone {
        string milestoneId;
        uint256 milestoneNo;
        uint256 share;
    }
}

File 33 of 37 : RequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

import { BaseTypes } from "./BaseTypes.sol";

/// @notice Library that defines requests sent from frontend to smart contracts.
library RequestTypes {
    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Struct defining low level data for any request.
    /// @param sender Address of account executing tx
    /// @param expiry Deadline on which request expires
    /// @param nonce Number used only once used to prevent tx reply or out of order execution
    struct BaseRequest {
        address sender;
        uint256 expiry;
        uint256 nonce;
    }

    /// @dev Struct used to create a raise.
    /// @param raise Struct containing info about raise
    /// @param vested Struct containing info about vested ERC20
    /// @param base Struct defining low level data for a request
    struct CreateRaiseRequest {
        BaseTypes.Raise raise;
        BaseTypes.Vested vested;
        BaseRequest base;
    }

    /// @dev Struct used to set a token for an early stage raise.
    /// @param raiseId UUID of raise
    /// @param token Address of ERC20
    /// @param base Struct defining low level data for a request
    struct SetTokenRequest {
        string raiseId;
        address token;
        BaseRequest base;
    }

    /// @dev Struct used to invest into raise.
    /// @param raiseId UUID of raise
    /// @param investment Amount of base asset used to invest
    /// @param maxTicketSize Individual limit of investment for validation
    /// @param base Struct defining low level data for a request
    struct InvestRequest {
        string raiseId;
        uint256 investment;
        uint256 maxTicketSize;
        BaseRequest base;
    }

    /// @dev Struct used to unlock milestone
    /// @param raiseId UUID of raise
    /// @param milestone Struct containing info about unlocked milestone
    /// @param base Struct defining low level data for a request
    struct UnlockMilestoneRequest {
        string raiseId;
        BaseTypes.Milestone milestone;
        BaseRequest base;
    }

    /// @dev Struct used to submit failed repair plan
    /// @param raiseId UUID of raise
    /// @param base Struct defining low level data for a request
    struct RejectRaiseRequest {
        string raiseId;
        BaseRequest base;
    }

    /// @dev Struct used to claim a tokens from milestone
    /// @param raiseId UUID of raise
    /// @param recipient Account claiming funds
    /// @param base Struct defining low level data for a request
    struct ClaimRequest {
        string raiseId;
        address recipient;
        BaseRequest base;
    }
}

File 34 of 37 : StateTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

import { BaseTypes } from "./BaseTypes.sol";

/// @notice Library that defines state related data.
library StateTypes {
    // -----------------------------------------------------------------------
    //                              Structs
    // -----------------------------------------------------------------------

    /// @dev Struct containing info about project state and investment data.
    /// @param raised Amount of raised base asset for fundraising
    /// @param invested Mapping that stores how much given address invested
    /// @param investmentRefunded Mapping that tracks if user was refunded
    /// @param collateralRefunded Boolean describing if startup was refunded
    /// @param reclaimed Boolean that shows if startup reclaimed unsold tokens
    struct ProjectInvestInfo {
        uint256 raised;
        mapping(address => uint256) invested;
        mapping(address => bool) investmentRefunded;
        bool collateralRefunded;
        bool reclaimed;
    }

    /// @dev Struct containing milestones and share data.
    /// @param milestones Ordered list of unlocked milestones containing all their details
    /// @param unlockedShares Sum of shares from all submitted milestones
    /// @param rejectedShares Amount of shares reverted back due to failed repair plan
    /// @param totalShares Sum of all unlocked and rejected shares (should not exceed 100%)
    struct ShareInfo {
        BaseTypes.Milestone[] milestones;
        uint256 unlockedShares;
        uint256 rejectedShares;
        uint256 totalShares;
    }

    /// @dev Struct containing frequently used storage for claiming purposes.
    /// @param investorClaimed Mapping that stores amount claimed of each investor
    /// @param startupClaimed Amount of claimed assets by startup owner
    struct ClaimingInfo {
        mapping(address => uint256) investorClaimed;
        uint256 startupClaimed;
    }
}

File 35 of 37 : IEquityBadge.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

import { IERC1155Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";

/**************************************

    EquityBadge interface

 **************************************/

/// @notice Equity badge interface
interface IEquityBadge is IERC1155Upgradeable {
    // -----------------------------------------------------------------------
    //                              Errors
    // -----------------------------------------------------------------------

    error BadgeTransferNotYetPossible(); // 0xab99d45e
    error InvalidURI(uint256 badgeId); // 0x2e0740e9

    // -----------------------------------------------------------------------
    //                              Functions
    // -----------------------------------------------------------------------

    /// @dev Mint amount of ERC1155 badges to given user account.
    /// @param _sender Address of badge recipient
    /// @param _badgeId Number of badge (derived from project uuid)
    /// @param _amount Quantity of badges to mint
    /// @param _data Additional data for transfer hooks
    function mint(address _sender, uint256 _badgeId, uint256 _amount, bytes memory _data) external;

    /// @dev Set URI for badge id.
    /// @param _badgeId Id of badge
    /// @param _uri IPFS uri to JSON depicting badge
    function setURI(uint256 _badgeId, string memory _uri) external;
}

File 36 of 37 : LibSignature.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

// OpenZeppelin
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

/**************************************

    Signature library

**************************************/

library LibSignature {
    // const
    bytes32 private constant EIP712_DOMAIN_TYPEHASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // errors
    error InvalidMessage(bytes32 verify, bytes32 message); // 0xeeba4d9c

    /**************************************

        Verify message

     **************************************/

    function verifyMessage(bytes32 _nameHash, bytes32 _versionHash, bytes32 _rawMessage, bytes32 _message) internal view {
        // compute hash from message
        bytes32 toVerify_ = hashToMessage(_nameHash, _versionHash, _rawMessage);

        // verify computation against original
        if (toVerify_ != _message) {
            revert InvalidMessage(toVerify_, _message);
        }
    }

    /**************************************

        Hash to message

     **************************************/

    function hashToMessage(bytes32 _nameHash, bytes32 _versionHash, bytes32 _rawMessage) internal view returns (bytes32) {
        // return
        return hashToMessage(_nameHash, _versionHash, _rawMessage, address(this));
    }

    function hashToMessage(
        bytes32 _nameHash,
        bytes32 _versionHash,
        bytes32 _rawMessage,
        address _contractAddress
    ) internal view returns (bytes32) {
        // build domain separator
        bytes32 domainSeparatorV4_ = keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, _nameHash, _versionHash, block.chainid, _contractAddress));

        // construct EIP712 message
        return ECDSA.toTypedDataHash(domainSeparatorV4_, _rawMessage);
    }

    /**************************************

        Recover signer

     **************************************/

    function recoverSigner(bytes32 _data, uint8 _v, bytes32 _r, bytes32 _s) internal pure returns (address) {
        // recover EIP712 signer using provided vrs
        address signer_ = ECDSA.recover(_data, _v, _r, _s);

        // return signer
        return signer_;
    }
}

File 37 of 37 : Configurable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**************************************

    security-contact:
    - [email protected]

    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]

    contributors:
    - [email protected]

**************************************/

/// @notice This contract is an abstract configurable utility, that can be inherited in contracts needed 1-time setup.
abstract contract Configurable {
    // -----------------------------------------------------------------------
    //                              Enums
    // -----------------------------------------------------------------------

    /// @dev State definition (before or after setup).
    enum State {
        UNCONFIGURED,
        CONFIGURED
    }

    // -----------------------------------------------------------------------
    //                              State variables
    // -----------------------------------------------------------------------

    /// @dev Storage of current state of contract.
    State public state;

    // -----------------------------------------------------------------------
    //                              Events
    // -----------------------------------------------------------------------

    event Initialised(bytes args);
    event Configured(bytes args);

    // -----------------------------------------------------------------------
    //                              Errors
    // -----------------------------------------------------------------------

    error InvalidState(State state, State expected);

    // -----------------------------------------------------------------------
    //                              Modifiers
    // -----------------------------------------------------------------------

    /// @dev Ensures contract is in correct state.
    /// @param _state Current state of contract
    modifier onlyInState(State _state) {
        // check state
        if (state != _state) {
            revert InvalidState(state, _state);
        }

        // enter function
        _;
    }

    // -----------------------------------------------------------------------
    //                              External functions
    // -----------------------------------------------------------------------

    /// @dev Function to implement in inheriting contract, that will use byte encoded args for setup.
    /// @param _arguments Byte-encoded user-defined arguments
    function configure(bytes calldata _arguments) external virtual;
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"uint256","name":"unlocked","type":"uint256"}],"name":"AllMilestonesUnlocked","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"raiseId","type":"string"}],"name":"CallerNotStartup","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"IncorrectSender","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"IncorrectSigner","type":"error"},{"inputs":[{"internalType":"bytes32","name":"verify","type":"bytes32"},{"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"InvalidMessage","type":"error"},{"inputs":[{"internalType":"uint256","name":"milestoneNo","type":"uint256"},{"internalType":"uint256","name":"milestoneCount","type":"uint256"}],"name":"InvalidMilestoneNumber","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceExpired","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"address","name":"account","type":"address"}],"name":"NothingToClaim","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"uint256","name":"rejected","type":"uint256"}],"name":"RaiseAlreadyRejected","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"RaiseDoesNotExists","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"RaiseNotFinished","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"RaiseNotRejected","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"RequestExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"uint256","name":"existing","type":"uint256"}],"name":"ShareExceedLimit","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"SoftcapNotAchieved","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"TokenNotOnEscrow","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"TokenNotSet","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"raiseId","type":"string"}],"name":"UserHasNotInvested","type":"error"},{"inputs":[{"internalType":"uint256","name":"milestoneNo","type":"uint256"}],"name":"ZeroShare","type":"error"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.ClaimRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"claimMilestoneInvestor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.ClaimRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"claimMilestoneStartup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.ClaimRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"claimRejectedInvestor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.ClaimRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"claimRejectedStartup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_raiseId","type":"string"},{"internalType":"address","name":"_account","type":"address"}],"name":"getAvailableForInvestor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_raiseId","type":"string"}],"name":"getAvailableForStartup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_raiseId","type":"string"},{"internalType":"address","name":"_account","type":"address"}],"name":"getRejectedForInvestor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_raiseId","type":"string"}],"name":"getRejectedForStartup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.RejectRaiseRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"rejectRaise","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"components":[{"internalType":"string","name":"milestoneId","type":"string"},{"internalType":"uint256","name":"milestoneNo","type":"uint256"},{"internalType":"uint256","name":"share","type":"uint256"}],"internalType":"struct BaseTypes.Milestone","name":"milestone","type":"tuple"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct RequestTypes.BaseRequest","name":"base","type":"tuple"}],"internalType":"struct RequestTypes.UnlockMilestoneRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"unlockMilestone","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x6040608081526004908136101561001557600080fd5b600091823560e01c908163102bd00e1461103557816346f58d8014610feb578163aaa7c60414610e55578163bc60b2aa14610b24578163c07e038114610afa578163e1437bf314610aa8578163e6361baa146108b1578163f553a48a14610305578163f807ada2146100c9575063fabd2a801461009157600080fd5b346100c5576020906100be6100a5366113a3565b906100af816119f4565b6100b982826116f5565b6117b1565b9051908152f35b5080fd5b919050346103015761013c906100de3661122a565b916100f66100f1989498368888016113e4565b611f44565b61011261010d610106878061141d565b369161132b565b611992565b61011c858061141d565b6020870198916101379061012f8b61159c565b92369161132b565b6118d6565b61015c61015761014c878061141d565b91903392369161132b565b611942565b9788156102cc5791899493916101729387611b98565b61017c838061141d565b6101ad6101c66101cb610192888097969761141d565b6001600160a01b039485949285926101b2929136919061132b565b611ce2565b5416966101be8c61159c565b95369161132b565b611d27565b92169182600052602052866000206101e48a825461163d565b9055845416928651916101f683611275565b8252886020830152803b156102be5786516318c0bbe560e01b81526001600160a01b039485169381019384528251909416602080850191909152909101516040830152839183919082908490829060600103925af180156102c2576102a4575b509261029e857f7bd9bff1ef8128cbb753755077e1fc045c3527f0427e862b8cc8b148ccdf9f8e9461028b856102939661141d565b95909461159c565b9051948594856115d9565b0390a180f35b6102b0909493946112a6565b6102be578438939293610256565b8480fd5b84513d84823e3d90fd5b87856102fd896102e76102df8b8061141d565b91909561159c565b9151637ab84f4560e11b815294859485016115b0565b0390fd5b8280fd5b905034610301576103153661122a565b928685979395969296019061032d6100f136846113e4565b61034261033d6101068a8061141d565b6119f4565b6103576103526101068a8061141d565b611db1565b5490602095868a01988761036b8b8d61151e565b0135936001948582019081831161089e570361087457508661038d8b8d61151e565b01351561085057896305f5e1006103c68d8a6103bf6103b76103b2610106858061141d565b611e5c565b95869361151e565b013561163d565b11610826575060a08b360312610822578651986103e28a6112b9565b6001600160401b03998c358b811161081e578d61040191369101611371565b81528b358b811161081e578d86913691019061041c9161144f565b978b83019889523661042d916113e4565b978a830198895251918a5192838d8d8183019382855280518285016060905260a0850161045991611577565b9281015160608501520151608083015203601f1981810186529a9061047e908661130a565b51908d8d519384828101946104b69086919091604080606083019460018060a01b038151168452602081015160208501520151910152565b038d810186526104c6908661130a565b5190815191012094519020915190208b51918d8301947f8b8f4cd980bb25257a6ec495a48359d02aa26010ef221b1e8d680cc53bcd82b186528d840152606083015260808201526080815261051a816112ef565b61052261148c565b9261052b6114dd565b915190209061053993612067565b61054293611ff6565b848061054e8a8061141d565b929061055a8b8d61151e565b9336906105669261132b565b92366105719161144f565b928751928382819351928391019161058892611554565b81016000805160206122d58339815191528152030190209384546801000000000000000081101561080b578381018087558110156107f857858c526003888d209102019382518051928a84116107e5575090879392918d8a6105ea8954611e93565b91601f831161077d575b915050508d8a92601f851160011461070e5750938361064d946003989461065a9a989460029892610703575b5050600019828a1b1c191690841b1786555b8a81015183870155019384519384910155860191825461163d565b905551920191825461163d565b905561068461067461066c878061141d565b96909761151e565b9582519583875283870191611533565b90848203838601528535601e19873603018112156106ff5786019383853595019085116106ff5784360381136106ff577f6dd2c0c8ff7a7a5bfb2a3c510339033e857a9b09a5b44daeb0904a9737716527966106eb83928897606087526060870191611533565b94808201359085015201359101520390a180f35b8780fd5b015190503880610620565b8493929193168884528b8420935b8c8282106107665750509684819461065a9a98946002989461064d9860039c1061074e575b505050811b018655610632565b0151600019838c1b60f8161c19169055388080610741565b8484015186558c985094890194938401930161071c565b909192939495965088815220601f850160051c8101918b86106107db575b8f8b979695949392601f8a930160051c0192905b8382106107c05790508c91506105f4565b90809293949596979850550190868f928b97969594936107af565b909150819061079b565b634e487b7160e01b8e526041905260248dfd5b634e487b7160e01b8c526032825260248cfd5b634e487b7160e01b8c526041825260248cfd5b8e80fd5b8b80fd5b8660449189808f8f6108379161151e565b01359051926317e013d560e01b84528301526024820152fd5b5060248587896108608d8f61151e565b01359051916377b23fc160e11b8352820152fd5b86604491898b8f8f6108859161151e565b0135905192630a6e159360e11b84528301526024820152fd5b634e487b7160e01b8f526011895260248ffd5b9050346103015761090b906108c53661122a565b916108d96100f196959496368a87016113e4565b6108e961010d610106868061141d565b6108f3848061141d565b6020860198916109069061012f8b61159c565b6116f5565b61091b6100b961014c868061141d565b958615610a95579061092f93929185611b98565b8561093a828061141d565b6001600160a01b039182916109599161095491369161132b565b611c9d565b541693610966848061141d565b90926109986109938261097f6101ad6101068b8061141d565b54169561098b8c61159c565b94369161132b565b611d6c565b91169081600052602052886000206109b188825461163d565b90558851906109bf82611275565b8152866020820152823b15610a915788516318c0bbe560e01b81526001600160a01b0380881693820193845282511660208085019190915290910151604083015291839183919082908490829060600103925af18015610a8757610a67575b507f910f09ada9d8d255eaba6ece2c660c387a133f744c622838a2bd436d3341f8b0610a5c8661029e878a88610a54898061141d565b96909561159c565b915195869586611607565b610a759095949293956112a6565b610a83579192908538610a1e565b8580fd5b87513d84823e3d90fd5b8380fd5b87866102fd8b6102e76102df8a8061141d565b828434610af7576020366003190112610af7578235906001600160401b038211610af75750610adf6020936100be92369101611371565b610ae8816119f4565b610af23382611870565b611916565b80fd5b5050346100c5576020906100be610b10366113a3565b90610b1a816119f4565b61015782826118d6565b905034610301576003199060a036830112610a91578035916001600160401b0391828411610a83576080848201928536030112610a8357602435936044359060ff82168203610e50576024810191610b7f6100f136856113e4565b610b8f61033d610106878061141d565b610b9c610106868061141d565b9688519360028951610bb381886020809e01611554565b8601958a816000805160206122d58339815191529889815203019020015480610e245750610be76103b2610106898061141d565b976305f5e1009889811015610dee57508a5190610c0382611275565b8835908111610dea57610c738b8593610c818f94610ce697610c30610cf39c8f610c399436920101611371565b845236906113e4565b828401819052855181516001600160a01b031694810194855260208083015190860152604091820151918501919091529384906060850190565b03601f19810185528461130a565b518d8151910120915190208251918d8301937f3c1aa39443f2abe979e93e8b5e91e397b2ea1746ac38100837c79fd2505270aa8552830152606082015260608152610ccb816112d4565b610cd361148c565b91610cdc6114dd565b9151902091612067565b6084359160643591611ff6565b610d00610106848061141d565b8651926003825194888181860197610d1981838b611554565b81018781520301902001548603958611610dd55750926003610d9c87899795610db995610dcb9a9860027fe76048b029adafaf8b982d8843e61ae66f2e16d04b06f3ecb4df6dcfb14577eb9d5185818451610d7581838a611554565b81018681520301902001610d8a8a825461163d565b90558a51948593849251928391611554565b82019081520301902001610db184825461163d565b90558061141d565b94908451958587968752860191611533565b918301520390a180f35b601190634e487b7160e01b6000525260246000fd5b8c80fd5b878c91610e1a610dfe8c8061141d565b855195869563731a1b8760e01b87528601526044850191611533565b9060248301520390fd5b868b91610e1a610e348b8061141d565b855195869563cb1dc2af60e01b87528601526044850191611533565b600080fd5b9190503461030157610eaf90610e6a3661122a565b91610e7d6100f1989498368888016113e4565b610e8d61010d610106878061141d565b610e97858061141d565b602087019891610eaa9061012f8b61159c565b611695565b610ec4610ebf610106878061141d565b611776565b9788156102cc5792899492610edd926109939588611b98565b610ee7848061141d565b906001610f1c610ef7888061141d565b610f106101ad858060a09b959b1b03998a93369161132b565b5416936101be8c61159c565b01610f288a825461163d565b90558385541693875192610f3b84611275565b168252886020830152803b156102be5786516318c0bbe560e01b81526001600160a01b039485169381019384528251909416602080850191909152909101516040830152839183919082908490829060600103925af180156102c257610fd1575b509261029e857fe20c2e7d8ca26219b98c89881c7aa03453943cea9db432cc61ea34a0190a62409461028b856102939661141d565b610fdd909493946112a6565b6102be578438939293610f9c565b828434610af7576020366003190112610af7578235906001600160401b038211610af757506110226020936100be92369101611371565b61102b816119f4565b610ebf3382611695565b9050346103015761108e916110493661122a565b9161105c6100f1979497368888016113e4565b61106c61010d610106878061141d565b611076858061141d565b6020870199916110899061012f8c61159c565b611870565b61109e610af2610106878061141d565b9687156112175791859493916110b5938a97611b98565b866101066110c3848061141d565b6001600160a01b03969187916110de9161095491369161132b565b54169560016111176101c68861110f856111076101ad6110fe858061141d565b9b90958061141d565b54169661159c565b96369161132b565b016111238a825461163d565b905587519261113184611275565b168252876020830152803b156103015786516318c0bbe560e01b81526001600160a01b03808816958201958652835116602080870191909152909201516040850152909283919082908490829060600103925af1801561120d576111c6575b50927f34fcf0acad9fb4089949a99bfce8e3c0ac29d630222174c68f49bfe60cc4aa60949261029e92610a5486610a5c9761141d565b9261029e92610a54610a5c9693986111ff7f34fcf0acad9fb4089949a99bfce8e3c0ac29d630222174c68f49bfe60cc4aa6099976112a6565b989396505092509294611190565b84513d89823e3d90fd5b88856102fd896102e76102df8b8061141d565b6003199060a081830112610e5057600435916001600160401b038311610e50578260a092030112610e5057600401906024359060443560ff81168103610e5057906064359060843590565b604081019081106001600160401b0382111761129057604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161129057604052565b606081019081106001600160401b0382111761129057604052565b608081019081106001600160401b0382111761129057604052565b60a081019081106001600160401b0382111761129057604052565b90601f801991011681019081106001600160401b0382111761129057604052565b9291926001600160401b0382116112905760405191611354601f8201601f19166020018461130a565b829481845281830111610e50578281602093846000960137010152565b9080601f83011215610e505781602061138c9335910161132b565b90565b35906001600160a01b0382168203610e5057565b6040600319820112610e5057600435906001600160401b038211610e50576113cd91600401611371565b906024356001600160a01b0381168103610e505790565b9190826060910312610e50576040516113fc816112b9565b604080829461140a8161138f565b8452602081013560208501520135910152565b903590601e1981360301821215610e5057018035906001600160401b038211610e5057602001918136038313610e5057565b919091606081840312610e505760405190611469826112b9565b81938135916001600160401b038311610e505761140a6040939284938301611371565b7446756e6472616973696e673a4d696c6573746f6e6560581b60206040516114b381611275565b6015815201527f8b7bf121a4925c079594e9c05e9a8a973e9640c48e4905971b36414abc2cb56790565b640313a313a360dc1b60206040516114f481611275565b6005815201527fbca4955973d0d9578cb9c4c1e55b98408b37031f7c2afd5b7187858082bca18c90565b903590605e1981360301821215610e50570190565b908060209392818452848401376000828201840152601f01601f1916010190565b60005b8381106115675750506000910152565b8181015183820152602001611557565b9060209161159081518092818552858086019101611554565b601f01601f1916010190565b356001600160a01b0381168103610e505790565b916020916115c991959495604085526040850191611533565b6001600160a01b03909416910152565b906115f39060409396959496606084526060840191611533565b6001600160a01b0390951660208201520152565b91606093916116229197969597608085526080850191611533565b6001600160a01b039182166020840152951660408201520152565b9190820180921161164a57565b634e487b7160e01b600052601160045260246000fd5b8181029291811591840414171561164a57565b6001600160a01b03909116815260406020820181905261138c92910190611577565b906001600160a01b038060096116aa85611de4565b015416908216036116b9575050565b6102fd604051928392637381065760e01b845260048401611673565b600211156116df57565b634e487b7160e01b600052602160045260246000fd5b90600161170183611e17565b6001600160a01b0383166000908152910160205260409020541561174d5750600160ff8161172e84611de4565b01541661173a816116d5565b146117425750565b61174b90611ab9565b565b6102fd604051928392637976c6f960e11b845260048401611673565b9190820391821161164a57565b61138c9060016117a96305f5e1006117a261179085611e17565b548461179b87611db1565b0154611660565b0492611d6c565b015490611769565b91909160016117bf82611e17565b019260018060a01b031660009381855260205260408420546117e083611e17565b5490620f4240918282029180830484149015171561185c578015611848576305f5e10061183361138c9798946118276040979561183a956118208b611ecd565b9104611660565b04600161179b89611db1565b0494611d6c565b908252602052205490611769565b634e487b7160e01b87526012600452602487fd5b634e487b7160e01b87526011600452602487fd5b906001600160a01b0380600961188585611de4565b015416908216036116b95750600261189c82611db1565b0154156118b157600160ff8161172e84611de4565b6040516309d3c03f60e31b8152602060048201529081906102fd906024830190611577565b9060016118e283611e17565b6001600160a01b0383166000908152910160205260409020541561174d5750600261190c82611db1565b0154156118b15750565b61138c9060016117a96305f5e10061193b61193085611ecd565b600261179b87611db1565b0492611d27565b61138c91600161195183611e17565b019060018060a01b0316908160005260205261197f6305f5e10061193b604060002054600261179b87611db1565b9060005260205260406000205490611769565b6119c760405160208184516119aa8183858901611554565b81016000805160206122b583398151915281520301902054611e93565b156119cf5750565b604051637813445960e01b8152602060048201529081906102fd906024830190611577565b6119fd81611992565b60405181519060076020840192611a15818486611554565b8201916020816000805160206122b583398151915294858152030190200154421115611a97576020600592611a5592604051809481938851928391611554565b8201908152030190200154611a6982611e17565b5410611a725750565b604051633188be3f60e11b8152602060048201529081906102fd906024830190611577565b6040516355c8fa3d60e11b815260206004820152806102fd6024820186611577565b6001600160a01b0380611acb83611c9d565b5416908115611b7657602090611ae084611ce2565b54166024604051809481936370a0823160e01b835260048301525afa908115611b6a57600091611b39575b5015611b145750565b6040516306b1017f60e31b8152602060048201529081906102fd906024830190611577565b906020823d8211611b62575b81611b526020938361130a565b81010312610af757505138611b0b565b3d9150611b45565b6040513d6000823e3d90fd5b6040516364d2ac4160e01b815260206004820152806102fd6024820186611577565b9392919060a085360312610e50576040805190611bb4826112b9565b8635906001600160401b038211610e505761174b97611c9893611bdb869436908401611371565b8152611bfd611bec6020840161138f565b9260208301938452843691016113e4565b818401819052835181516001600160a01b0316602080830191825283015160408084019190915290920151606082015291611c3b8360808101610c73565b51602081519101209260018060a01b03905116915190209083519260208401947fce351a3b056833ac1ae0832767a76fcde7300ee0585123f24a354610dbd0d9bd86528401526060830152608082015260808152610ccb816112ef565b611ff6565b6020611cb6918160405193828580945193849201611554565b81017f228bc91c6dc5c6510e58d93832d0f81930ec0fa3cc1daf883210434d77859f3a81520301902090565b6020611cfb918160405193828580945193849201611554565b81017fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d708718881520301902090565b6020611d40918160405193828580945193849201611554565b81017f863e98553d473a330f13570b828238eab81d26cbf5ccc0856a5fcff7a8742b5881520301902090565b6020611d85918160405193828580945193849201611554565b81017f863e98553d473a330f13570b828238eab81d26cbf5ccc0856a5fcff7a8742b5781520301902090565b6020611dca918160405193828580945193849201611554565b81016000805160206122d583398151915281520301902090565b6020611dfd918160405193828580945193849201611554565b81016000805160206122b583398151915281520301902090565b6020611e30918160405193828580945193849201611554565b81017f228bc91c6dc5c6510e58d93832d0f81930ec0fa3cc1daf883210434d77859f3b81520301902090565b611e7760206003928160405193828580945193849201611554565b81016000805160206122d5833981519152815203019020015490565b90600182811c92168015611ec3575b6020831014611ead57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611ea2565b611f40670de0b6b3a764000091611f386040516020818451611ef28183858901611554565b81016000805160206122b58339815191528152030190209160ff600360405194611f1b86611275565b60028101548652015416611f2e816116d5565b6020840152611e17565b549051611660565b0490565b6040810151336000527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f602052604060002054811115611fd657506020810151804211611fb65750516001600160a01b03163303611f9e57565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048201526024810191909152604490fd5b604051632b6069a960e01b81523360048201526024810191909152604490fd5b9161200d939161200593612225565b919091612121565b6001600160a01b031660008181527ff99dac35d4c04cf62531c589d43ecfd87ca6ae92fd3fae21943930c2156dcee8602052604090205460ff161561204f5750565b602490604051906333ffff9b60e01b82526004820152fd5b90916040519260208401927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604085015260608401524660808401523060a084015260a0835260c08301918383106001600160401b03841117611290576101029083604052845190209360e081019461190160f01b865260e28201520152604281526120f4816112d4565b51902090808203612103575050565b6044925060405191633bae936760e21b835260048301526024820152fd5b60058110156116df57806121325750565b6001810361217f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036121cc5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b6003146121d557565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116122a85791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa1561229b5781516001600160a01b03811615612295579190565b50600190565b50604051903d90823e3d90fd5b5050505060009060039056fe228bc91c6dc5c6510e58d93832d0f81930ec0fa3cc1daf883210434d77859f39863e98553d473a330f13570b828238eab81d26cbf5ccc0856a5fcff7a8742b56a26469706673582212203af59f7094c070c1d60690093ea907f7f536cf5b442a65b51f932803fea4353a64736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.