ETH Price: $2,150.99 (+0.87%)

Contract

0xE8213C25E66Ab25b8Eb0DF42e48D1476DB0BbD2F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Method Block
From
To
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
RescheduleClaimingFacet

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - constants, encoders, events, errors, structs
import { MilestoneConstants } from "../../constants/MilestoneConstants.sol";
import { MilestoneEncoder } from "../../encoders/MilestoneEncoder.sol";
import { MilestoneEvents } from "../../events/MilestoneEvents.sol";
import { CrossChainErrors } from "../../errors/cross-chain/CrossChainErrors.sol";
import { RequestTypes } from "../../structs/RequestTypes.sol";
import { CrossChainRequestTypes } from "../../structs/CrossChainRequestTypes.sol";
import { EnumTypes } from "../../structs/EnumTypes.sol";

// Local imports - interfaces
import { IRescheduleClaimingFacet } from "../../interfaces/milestone/IRescheduleClaimingFacet.sol";

// Local imports - servies
import { RequestService } from "../../libraries/services/utils/RequestService.sol";
import { SignatureService } from "../../libraries/services/utils/SignatureService.sol";
import { RescheduleClaimingService } from "../../libraries/services/milestone/RescheduleClaimingService.sol";
import { ERC20AssetService } from "../../libraries/services/assets/internal/ERC20AssetService.sol";
import { LayerZeroSenderService } from "../../libraries/services/cross-chain/layer-zero/LayerZeroSenderService.sol";

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

    RescheduleClaiming facet

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

contract RescheduleClaimingFacet is IRescheduleClaimingFacet {
    /// @dev Reschedule claimings and send cross chain message if needed to reschedule claimings on the other chain.
    /// @dev Events: ClaimingsRescheduled(
    ///                 string raiseId,
    ///                 string milestoneId,
    ///                 StorageTypes.ClaimingSchedule[] claimingSchedules,
    ///             )
    /// @param _request RequestTypes.RescheduleClaimingRequest 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
    /// @param _crossChainData RequestTypes.CrossChainData struct with data for cross chain communication
    function rescheduleClaimings(
        RequestTypes.RescheduleClaimingRequest calldata _request,
        bytes32 _message,
        uint8 _v,
        bytes32 _r,
        bytes32 _s,
        CrossChainRequestTypes.CrossChainData calldata _crossChainData
    ) external payable {
        // tx.members
        address sender_ = msg.sender;

        // validate base request
        RequestService.validateBaseRequest(_request.base);

        // validate request
        uint256 claimingSchedulesFromThePastLength_ = RescheduleClaimingService.validateRescheduleClaimingsRequest(
            _request.raiseId,
            _request.milestoneId,
            _request.claimingSchedules
        );

        // EIP-712 encoding
        bytes memory encodedMsg_ = MilestoneEncoder.encodeRescheduleClaiming(_request);

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

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

        // save claiming schedules in the storage
        RescheduleClaimingService.setClaimingScheduleData(
            sender_,
            _request.base.nonce,
            _request.milestoneId,
            _request.claimingSchedules,
            claimingSchedulesFromThePastLength_
        );

        // get cross chain id
        uint256 crossChainId_ = ERC20AssetService.getERC20AssetChainId(_request.raiseId);

        // handle cross chain request
        if (crossChainId_ != block.chainid) {
            if (_crossChainData.provider == EnumTypes.CrossChainProvider.LayerZero) {
                // send message through LayerZero
                LayerZeroSenderService.sendCrossChainMessage(_crossChainData.data, crossChainId_);
            } else {
                // revert if provider unsupported
                revert CrossChainErrors.UnsupportedProvider();
            }
        }

        // emit
        emit MilestoneEvents.ClaimingsRescheduled(_request.raiseId, _request.milestoneId, _request.claimingSchedules);
    }
}

File 2 of 46 : MilestoneConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    /// @dev EIP712 name
    bytes32 internal constant EIP712_NAME = keccak256(bytes("Fundraising:Milestone"));
    /// @dev EIP712 versioning: "release:major:minor"
    bytes32 internal constant EIP712_VERSION = keccak256(bytes("2:2:0"));

    // typehashes
    bytes32 internal constant VOTING_UNLOCK_MILESTONE_TYPEHASH = keccak256("UnlockMilestoneRequest(string raiseId,bytes milestone,bytes base)");
    bytes32 internal constant VOTING_UNLOCK_MILESTONE_RECEIVER_TYPEHASH =
        keccak256("UnlockMilestoneReceiverRequest(string raiseId,bytes milestone,bytes crossChainBase)");
    bytes32 internal constant VOTING_REJECT_RAISE_TYPEHASH = keccak256("RejectRaiseRequest(string raiseId,bytes base)");
    bytes32 internal constant VOTING_REJECT_RAISE_RECEIVER_TYPEHASH =
        keccak256("RejectRaiseReceiverRequest(string raiseId,bytes crossChainBase)");
    bytes32 internal constant INVESTOR_CLAIM_TYPEHASH =
        keccak256("InvestorClaimRequest(string raiseId,uint256 investment,bytes32[] proofs,bytes base)");
    bytes32 internal constant STARTUP_CLAIM_TYPEHASH = keccak256("StartupClaimRequest(string raiseId,bytes base)");
    bytes32 internal constant SUBMIT_CLAIMING_TYPEHASH =
        keccak256("SubmitClaimingRequest(string raiseId,string milestoneId,bytes claimingSchedules,bytes base)");
    bytes32 internal constant SUBMIT_CLAIMING_RECEIVER_TYPEHASH =
        keccak256("SubmitClaimingReceiverRequest(string raiseId,string milestoneId,bytes claimingSchedules,bytes crossChainBase)");
    bytes32 internal constant RESCHEDULE_CLAIMING_TYPEHASH =
        keccak256("RescheduleClaimingRequest(string raiseId,string milestoneId,bytes claimingSchedules,bytes base)");
    bytes32 internal constant RESCHEDULE_CLAIMING_RECEIVER_TYPEHASH =
        keccak256("RescheduleClaimingReceiverRequest(string raiseId,string milestoneId,bytes claimingSchedules,bytes crossChainBase)");
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// 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 unlock milestone receiver request to validate the EIP712 message.
    /// @param _request UnlockMilestoneReceiverRequest struct
    /// @return EIP712 encoded message containing request
    function encodeUnlockMilestoneReceiver(RequestTypes.UnlockMilestoneReceiverRequest memory _request) internal pure returns (bytes memory) {
        // milestone
        bytes memory encodedMilestone_ = abi.encode(_request.milestone);

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

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

        // return
        return encodedMsg_;
    }

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

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

        // return
        return encodedMsg_;
    }

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

        // msg
        bytes memory encodedMsg_ = abi.encode(
            MilestoneConstants.STARTUP_CLAIM_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            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_;
    }

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

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

        // return
        return encodedMsg_;
    }

    /// @dev Encode submit claiming schedule request to validate the EIP 712 message.
    /// @param _request SubmitClaimingRequest struct
    /// @return EIP712 encoded message containing request
    function encodeSubmitClaiming(RequestTypes.SubmitClaimingRequest memory _request) internal pure returns (bytes memory) {
        // base
        bytes memory encodedBase_ = abi.encode(_request.base);

        // claiming schedule array
        bytes memory encodedClaimingSchedules_ = abi.encode(_request.claimingSchedules);

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

        // return
        return encodedMsg_;
    }

    /// @dev Encode submit claiming schedule receiver request to validate the EIP 712 message.
    /// @param _request SubmitClaimingReceiverRequest struct
    /// @return EIP712 encoded message containing request
    function encodeSubmitClaimingReceiver(RequestTypes.SubmitClaimingReceiverRequest memory _request) internal pure returns (bytes memory) {
        // base
        bytes memory encodedCrossChainBase_ = abi.encode(_request.crossChainBase);

        // claiming schedule array
        bytes memory encodedClaimingSchedules_ = abi.encode(_request.claimingSchedules);

        // msg
        bytes memory encodedMsg_ = abi.encode(
            MilestoneConstants.SUBMIT_CLAIMING_RECEIVER_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            keccak256(bytes(_request.milestoneId)),
            keccak256(encodedClaimingSchedules_),
            keccak256(encodedCrossChainBase_)
        );

        // return
        return encodedMsg_;
    }

    /// @dev Encode reschedule claimings request to validate the EIP 712 message.
    /// @param _request RescheduleClaimingRequest struct
    /// @return EIP712 encoded message containing request
    function encodeRescheduleClaiming(RequestTypes.RescheduleClaimingRequest memory _request) internal pure returns (bytes memory) {
        // base
        bytes memory encodedBase_ = abi.encode(_request.base);

        // claiming schedule array
        bytes memory encodedClaimingSchedules_ = abi.encode(_request.claimingSchedules);

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

        // return
        return encodedMsg_;
    }

    /// @dev Encode reschedule claimings request to validate the EIP 712 message.
    /// @param _request RescheduleClaimingRequest struct
    /// @return EIP712 encoded message containing request
    function encodeRescheduleClaimingReceiver(
        RequestTypes.RescheduleClaimingReceiverRequest memory _request
    ) internal pure returns (bytes memory) {
        // base
        bytes memory encodedBase_ = abi.encode(_request.crossChainBase);

        // claiming schedule array
        bytes memory encodedClaimingSchedules_ = abi.encode(_request.claimingSchedules);

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

        // return
        return encodedMsg_;
    }
}

File 4 of 46 : MilestoneEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

    Milestone events

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

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

    event MilestoneUnlocked(string raiseId, StorageTypes.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);

    // -----------------------------------------------------------------------
    //                              Claimings
    // -----------------------------------------------------------------------

    event ClaimingScheduleSubmitted(string raiseId, string milestoneId, StorageTypes.ClaimingSchedule[] claimingSchedules);
    event ClaimingsRescheduled(string raiseId, string milestoneId, StorageTypes.ClaimingSchedule[] claimingSchedules);
}

File 5 of 46 : CrossChainErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import "../../structs/EnumTypes.sol";

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

    Cross-chain errors
    
**************************************/

/// @dev All errors used in cross chain communication
library CrossChainErrors {
    // -----------------------------------------------------------------------
    //                              Chain id & Provider
    // -----------------------------------------------------------------------

    error InvalidChainId(uint256 current, uint256 expected); // 0x9fba672f
    error UnsupportedChainId(uint256 chainId); // 0xa5dab5fe
    error ProviderChainIdMismatch(EnumTypes.CrossChainProvider provider, uint256 requestChainId, uint256 blockChainId); // 0x72c80f07
    error UnsupportedProvider(); // 0x7f4d001d
    error NotCrossChainRequest(); // 0x5a64c0eb

    // -----------------------------------------------------------------------
    //                              Payload
    // -----------------------------------------------------------------------

    error EmptyPayload(); // 0x2e3f1f34
}

File 6 of 46 : RequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports
import { CrossChainRequestTypes } from "./CrossChainRequestTypes.sol";
import { StorageTypes } from "./StorageTypes.sol";

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

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

    // -----------------------------------------------------------------------
    //                              Raise
    // -----------------------------------------------------------------------

    /// @dev Struct used to create a raise.
    /// @param raise Struct containing info about raise
    /// @param raiseDetails Mapping of raise id to vested token information
    /// @param erc20Asset Struct containing info about vested ERC20
    /// @param baseAsset Struct containing info about asset used for investment
    /// @param badgeUri IPFS URI that initializes equity badge for the raise
    /// @param base Struct defining low level data for a request
    struct CreateRaiseRequest {
        StorageTypes.Raise raise;
        StorageTypes.RaiseDetails raiseDetails;
        StorageTypes.ERC20Asset erc20Asset;
        StorageTypes.BaseAsset baseAsset;
        string badgeUri;
        BaseRequest base;
    }

    /// @dev Struct used to create a raise.
    /// @param raise Struct containing info about raise
    /// @param raiseDetails Mapping of raise id to vested token information
    /// @param erc20Asset Struct containing info about vested ERC20
    /// @param baseAsset Struct containing info about asset used for investment
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct RegisterRaiseRequest {
        StorageTypes.Raise raise;
        StorageTypes.RaiseDetails raiseDetails;
        StorageTypes.ERC20Asset erc20Asset;
        StorageTypes.BaseAsset baseAsset;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    /// @dev Struct used to create a raise for Substrate-based chains.
    /// @param raise Struct containing info about raise
    /// @param raiseDetails Mapping of raise id to vested token information
    /// @param psp22Asset Struct containing info about vested ERC20
    /// @param baseAsset Struct containing info about asset used for investment
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct SubstrateRegisterRaiseRequest {
        StorageTypes.SubstrateRaise raise;
        StorageTypes.RaiseDetails raiseDetails;
        StorageTypes.PSP22Asset psp22Asset;
        StorageTypes.SubstrateBaseAsset baseAsset;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    /// @dev Struct Used to finish a raise.
    /// @param raiseId Id of finished raise
    /// @param raised Number of collected tokens
    /// @param merkleRoot Root value of merkle tree build from investments
    /// @param base Struct defining low level data for a request
    struct FinishRaiseRequest {
        string raiseId;
        uint256 raised;
        bytes32 merkleRoot;
        BaseRequest base;
    }

    /// @dev Struct used to finish a raise in receiver
    /// @param raiseId Id of finished raise
    /// @param raised Number of collected tokens
    /// @param merkleRoot Root value of merkle tree build from investments
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct FinishRaiseReceiverRequest {
        string raiseId;
        uint256 raised;
        bytes32 merkleRoot;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    // -----------------------------------------------------------------------
    //                              Set token
    // -----------------------------------------------------------------------

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

    // -----------------------------------------------------------------------
    //                              Invest
    // -----------------------------------------------------------------------

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

    // -----------------------------------------------------------------------
    //                              Voting
    // -----------------------------------------------------------------------

    /// @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;
        StorageTypes.Milestone milestone;
        BaseRequest base;
    }

    /// @dev Struct used to unlock milestone for receiver
    /// @param raiseId UUID of raise
    /// @param milestone Struct containing info about unlocked milestone
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct UnlockMilestoneReceiverRequest {
        string raiseId;
        StorageTypes.Milestone milestone;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    /// @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 submit failed repair plan for receiver
    /// @param raiseId UUID of raise
    /// @param crossChainBase Struct defining low level data for a cross-chain request
    struct RejectRaiseReceiverRequest {
        string raiseId;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    // -----------------------------------------------------------------------
    //                              Claiming
    // -----------------------------------------------------------------------

    /// @dev Struct used to submit claiming schedule
    /// @param raiseId UUID of raise
    /// @param milestoneId UUID of milestone
    /// @param claimingSchedules Array of ClaimingSchedule structs
    /// @param base Struct defining low level data for a request
    struct SubmitClaimingRequest {
        string raiseId;
        string milestoneId;
        StorageTypes.ClaimingSchedule[] claimingSchedules;
        BaseRequest base;
    }

    /// @dev Struct used to submit claiming schedule
    /// @param raiseId UUID of raise
    /// @param milestoneId UUID of milestone
    /// @param claimingSchedules Array of ClaimingSchedule structs
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct SubmitClaimingReceiverRequest {
        string raiseId;
        string milestoneId;
        StorageTypes.ClaimingSchedule[] claimingSchedules;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }

    /// @dev Struct used to claim tokens by investor
    /// @param raiseId UUID of raise
    /// @param investment Investment of msg.sender
    /// @param proofs Merkle proofs for msg.sender
    /// @param base Struct defining low level data for a request
    struct InvestorClaimRequest {
        string raiseId;
        uint256 investment;
        bytes32[] proofs;
        BaseRequest base;
    }

    /// @dev Struct used to claim tokens by startup
    /// @param raiseId UUID of raise
    /// @param base Struct defining low level data for a request
    struct StartupClaimRequest {
        string raiseId;
        BaseRequest base;
    }

    /// @dev Struct used to reschedule claiming schedule
    /// @param milestoneId UUID of milestone
    /// @param claimingSchedules Array of ClaimingSchedule structs
    /// @param base Struct defining low level data for a request
    struct RescheduleClaimingRequest {
        string raiseId;
        string milestoneId;
        StorageTypes.ClaimingSchedule[] claimingSchedules;
        BaseRequest base;
    }

    /// @dev Struct used to reschedule claimings
    /// @param raiseId UUID of raise
    /// @param milestoneId UUID of milestone
    /// @param claimingSchedules Array of ClaimingSchedule structs
    /// @param crossChainBase Struct defining low level data for a cross-chain requests
    struct RescheduleClaimingReceiverRequest {
        string raiseId;
        string milestoneId;
        StorageTypes.ClaimingSchedule[] claimingSchedules;
        CrossChainRequestTypes.CrossChainBase crossChainBase;
    }
}

File 7 of 46 : CrossChainRequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - Structs
import { StorageTypes } from "./StorageTypes.sol";
import { EnumTypes } from "./EnumTypes.sol";

/// @notice Library that defines requests sent from frontend to smart contracts.
library CrossChainRequestTypes {
    // -----------------------------------------------------------------------
    //                              Cross chain
    // -----------------------------------------------------------------------

    /// @dev Struct containing chosen cross-chain provider and encoded data.
    /// @param provider Cross chain provider
    /// @param data Data encoding message in format for specific provider
    struct CrossChainData {
        EnumTypes.CrossChainProvider provider;
        bytes data;
    }

    /// @dev Struct containing base for cross-chain message.
    /// @param sender Address of sender
    /// @param nonce Nonce of cross-chain message
    struct CrossChainBase {
        address sender;
        uint256 nonce;
    }

    // -----------------------------------------------------------------------
    //                              LayerZero
    // -----------------------------------------------------------------------

    /// @dev Struct containing cross chain message in LayerZero format
    /// @param payload Encoded cross-chain call with data
    /// @param additionalParams Additional parameters for LayerZero
    /// @param fee Fee covering execution cost
    struct LayerZeroData {
        bytes payload;
        bytes additionalParams;
        uint256 fee;
    }

    // -----------------------------------------------------------------------
    //                              AlephZero
    // -----------------------------------------------------------------------

    /// @dev Struct containing cross chain message in AlephZero format
    /// @param nonce Cross chain nonce of tx
    /// @param fee Unused fee if we would like to publish Bridge
    /// @param selector Byte-encoded substrate function to call
    /// @param args Byte-encoded cross-chain arguments for function
    /// @param options Byte-encoded cross chain settings for Bridge tx
    /// @param metadata Byte-encoded metadata in Scale format for Bridge
    struct AlephZeroData {
        uint256 nonce;
        uint256 fee;
        bytes4 selector;
        bytes args;
        bytes options;
        bytes metadata;
    }
}

File 8 of 46 : EnumTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Library with core types definition.
library EnumTypes {
    // -----------------------------------------------------------------------
    //                              Raise
    // -----------------------------------------------------------------------

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

    /// @dev Definition of raise statuses.
    enum RaiseStatus {
        RaiseCreated,
        RaiseFailed,
        RaiseSucceed
    }

    // -----------------------------------------------------------------------
    //                              Cross chain
    // -----------------------------------------------------------------------

    /// @dev Definition of supported cross chain providers.
    enum CrossChainProvider {
        None,
        LayerZero,
        AlephZero
    }

    // -----------------------------------------------------------------------
    //                              Milestone
    // -----------------------------------------------------------------------

    /// @dev Definiction of action to perform for reschedule claimings
    enum RescheduleActionType {
        UpdateAndCreate,
        OnlyUpdate,
        UpdateAndDelete
    }
}

File 9 of 46 : IRescheduleClaimingFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

interface IRescheduleClaimingFacet {
    /// @dev Reschedule claimings and send cross chain message if needed to reschedule claimings on the other chain.
    /// @param _request RequestTypes.RescheduleClaimingRequest 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
    /// @param _crossChainData RequestTypes.CrossChainData struct with data for cross chain communication
    function rescheduleClaimings(
        RequestTypes.RescheduleClaimingRequest calldata _request,
        bytes32 _message,
        uint8 _v,
        bytes32 _r,
        bytes32 _s,
        CrossChainRequestTypes.CrossChainData calldata _crossChainData
    ) external payable;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - constants, encoders, events, errors, structs
import { RequestErrors } from "../../../errors/RequestErrors.sol";
import { RequestTypes } from "../../../structs/RequestTypes.sol";
import { CrossChainRequestTypes } from "../../../structs/CrossChainRequestTypes.sol";

// Local imports - storages
import { LibNonce } from "../../../libraries/storage/utils/LibNonce.sol";

library RequestService {
    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_);
        }
    }

    function validateCcBaseRequest(CrossChainRequestTypes.CrossChainBase memory _baseRequest) internal view {
        if (_baseRequest.nonce <= LibNonce.getLastNonce(_baseRequest.sender)) {
            revert RequestErrors.NonceExpired(_baseRequest.sender, _baseRequest.nonce);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

// Local imports - constants, encoders, events, errors, structs
import { SignatureConstants } from "../../../constants/SignatureConstants.sol";
import { SignatureErrors } from "../../../errors/SignatureErrors.sol";
import { AccessTypes } from "../../../structs/AccessTypes.sol";

// Local imports - storages
import { LibAccessControl } from "../../storage/utils/LibAccessControl.sol";

// A0: cut out from scope
// import {Blake2bAB} from "../../../../utils/Blake2bAB.sol";

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

    /// @dev Verify if given signature is signed by correct signer.
    /// @param _message Hash message
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function verifySignature(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) internal view {
        // signer of message
        address signer_ = recoverSigner(_message, _v, _r, _s);

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

    /// @dev Verify EIP-712 message sent.
    /// @param _nameHash Hash EIP-712 name
    /// @param _versionHash Hash EIP-712 version
    /// @param _rawMessage Hash message calculated "on-the-fly"
    /// @param _message Message sent in request
    function verifyMessage(bytes32 _nameHash, bytes32 _versionHash, bytes32 _rawMessage, bytes32 _message) internal view {
        // build domain separator
        bytes32 domainSeparatorV4_ = keccak256(
            abi.encode(SignatureConstants.EIP712_DOMAIN_TYPEHASH, _nameHash, _versionHash, block.chainid, address(this))
        );

        // construct EIP712 message
        bytes32 toVerify_ = ECDSA.toTypedDataHash(domainSeparatorV4_, _rawMessage);

        // verify computation against original
        if (toVerify_ != _message) {
            revert SignatureErrors.InvalidMessage(toVerify_, _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);
    }

    // A0: cut out from scope
    // function hashBlake2b(bytes memory _payload) internal pure returns (bytes32) {
    //        // return Blake2b 256-bit hash
    //        return Blake2bAB.blake2b_256(_payload);
    //    }

    /// @dev Allows to return signer of the signature.
    /// @param _data Message sent in request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    /// @return Signer of the message
    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_;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - constants, encoders, events, errors, structs
import { MilestoneErrors } from "../../../errors/MilestoneErrors.sol";
import { StorageTypes } from "../../../structs/StorageTypes.sol";
import { EnumTypes } from "../../../structs/EnumTypes.sol";

// Local imports - storages
import { LibMilestone } from "../../storage/milestone/LibMilestone.sol";
import { LibClaimingSchedule } from "../../storage/milestone/LibClaimingSchedule.sol";
import { LibNonce } from "../../storage/utils/LibNonce.sol";

/// @notice Service for reschedule claiming
library RescheduleClaimingService {
    /// @dev Save claiming schedule data and marked nonce as used
    /// @param _sender msg.sender
    /// @param _nonce nonce used in message
    /// @param _milestoneId UUID of the milestone
    /// @param _claimingSchedules Claiming schedule struct array
    /// @param _claimingSchedulesFromThePastLength Amount of claiming schedules from the past
    function setClaimingScheduleData(
        address _sender,
        uint256 _nonce,
        string memory _milestoneId,
        StorageTypes.ClaimingSchedule[] memory _claimingSchedules,
        uint256 _claimingSchedulesFromThePastLength
    ) internal {
        // calculate length of claiming schedules
        uint256 claimingSchedulesLength_ = _claimingSchedules.length;

        // calculate claiming schedules length from storage
        uint256 storageClaimingSchedulesLength_ = LibClaimingSchedule.claimingScheduleCount(_milestoneId);

        // calculate amount of claiming schedules from the future to remove
        uint256 claimingSchedulesToRemove_ = storageClaimingSchedulesLength_ - _claimingSchedulesFromThePastLength;

        // verify if any claiming schedule is to remove
        if (claimingSchedulesToRemove_ > 0) {
            // delete claiming schedules
            LibClaimingSchedule.deleteClaimingSchedules(_milestoneId, claimingSchedulesToRemove_);
        }

        // calculate claiming schedules length from storage after remove
        uint256 storageClaimingSchedulesAfterRemoveLength_ = LibClaimingSchedule.claimingScheduleCount(_milestoneId);

        // verify if any claiming schedule is to add
        if (claimingSchedulesLength_ > storageClaimingSchedulesAfterRemoveLength_) {
            for (uint i = storageClaimingSchedulesAfterRemoveLength_; i < claimingSchedulesLength_; i++) {
                // create claiming schedule
                LibClaimingSchedule.createClaimingSchedule(_claimingSchedules[i]);
            }
        }

        // set nonce as used to storage
        LibNonce.setNonce(_sender, _nonce);
    }

    /// @dev Validate reschedule claiming request
    /// @param _raiseId UUID of the raise
    /// @param _milestoneId UUID of the milestone
    /// @param _claimingSchedules Claiming schedule struct array
    /// @return Amount of claiming schedules from the past
    function validateRescheduleClaimingsRequest(
        string memory _raiseId,
        string memory _milestoneId,
        StorageTypes.ClaimingSchedule[] memory _claimingSchedules
    ) internal view returns (uint256) {
        // validate if milestone exists
        (bool isMilestoneExists_, uint256 milestoneIndex_) = LibMilestone.milestoneExists(_raiseId, _milestoneId);

        // revert if milestone not exists
        if (!isMilestoneExists_) {
            revert MilestoneErrors.MilestoneNotExists(_milestoneId);
        }

        // calculate claiming schedules length from request and revert if it equal to zero
        uint256 _requestClaimingSchedulesLength = _claimingSchedules.length;

        if (_requestClaimingSchedulesLength == 0) {
            revert MilestoneErrors.EmptyClaimingSchedules();
        }

        // get milestone share
        uint256 milestoneShare_ = LibMilestone.getMilestoneShare(_raiseId, milestoneIndex_);

        // calculate claiming schedules length from storage
        uint256 storageClaimingSchedulesLength_ = LibClaimingSchedule.claimingScheduleCount(_milestoneId);

        // calculate claimings from the past
        uint256 claimingSchedulesFromThePastLength_ = getPastSchedulesAmount(storageClaimingSchedulesLength_, _milestoneId);

        if (_requestClaimingSchedulesLength < claimingSchedulesFromThePastLength_) {
            revert MilestoneErrors.CannotDeletePastSchedule();
        }

        // validate reschedule claimings
        validateRescheduleClaimings(
            _milestoneId,
            storageClaimingSchedulesLength_,
            _requestClaimingSchedulesLength,
            milestoneShare_,
            _claimingSchedules
        );

        // return
        return claimingSchedulesFromThePastLength_;
    }

    /// @dev Validate reschedule claimings with data in storage and verify unlock timestamps and shares
    /// @param _milestoneId UUID of the milestone
    /// @param _storageClaimingSchedulesLength Amount of claiming schedules in storage for given milestone
    /// @param _requestClaimingSchedulesLength Amount of claiming schedules in request
    /// @param _milestoneShare Milestone shares
    /// @param _claimingSchedules Claiming schedules from request
    function validateRescheduleClaimings(
        string memory _milestoneId,
        uint256 _storageClaimingSchedulesLength,
        uint256 _requestClaimingSchedulesLength,
        uint256 _milestoneShare,
        StorageTypes.ClaimingSchedule[] memory _claimingSchedules
    ) internal view {
        // value to calculate all claming schedule shares for given milestone
        uint256 claimingSchedulesShares_ = 0;

        for (uint i = 0; i < _requestClaimingSchedulesLength; i++) {
            // set currently validated claiming schedule from request
            StorageTypes.ClaimingSchedule memory requestClaimingSchedule_ = _claimingSchedules[i];

            if (i < _storageClaimingSchedulesLength) {
                // validate existing claiming schedules
                validateExistingClaimingSchedule(requestClaimingSchedule_, _milestoneId, i);
            }

            // increase claiming schedule shares
            claimingSchedulesShares_ += requestClaimingSchedule_.partialShare;
        }

        // validate claiming schedule shares with milestone shares
        if (claimingSchedulesShares_ != _milestoneShare) {
            revert MilestoneErrors.RescheduledSharesMustEqualMilestoneShare(_milestoneId, _milestoneShare, claimingSchedulesShares_);
        }
    }

    /// @dev Internal function to validate existed claiming schedules
    /// @param requestClaimingSchedule_ Claiming schedules from request
    /// @param _milestoneId UUID of the milestone
    /// @param _claimingScheduleIndex Claiming schedule index in the storage array
    function validateExistingClaimingSchedule(
        StorageTypes.ClaimingSchedule memory requestClaimingSchedule_,
        string memory _milestoneId,
        uint256 _claimingScheduleIndex
    ) internal view {
        // fetch claiming schedule from storage
        StorageTypes.ClaimingSchedule memory storageClaimingSchedule_ = LibClaimingSchedule.getClaimingScheduleForIndex(
            _milestoneId,
            _claimingScheduleIndex
        );

        // validate if user doesn't want to change milestone id
        if (
            keccak256(abi.encodePacked(requestClaimingSchedule_.milestoneId)) !=
            keccak256(abi.encodePacked(storageClaimingSchedule_.milestoneId))
        ) {
            revert MilestoneErrors.CannotChangeMilestoneId(
                requestClaimingSchedule_.claimingId,
                requestClaimingSchedule_.milestoneId,
                storageClaimingSchedule_.milestoneId
            );
        }

        if (storageClaimingSchedule_.unlockTimestamp <= block.timestamp) {
            // validate if user doesn't want to change claiming id
            if (
                keccak256(abi.encodePacked(requestClaimingSchedule_.claimingId)) !=
                keccak256(abi.encodePacked(storageClaimingSchedule_.claimingId))
            ) {
                revert MilestoneErrors.CannotChangeClaimingId(requestClaimingSchedule_.claimingId, storageClaimingSchedule_.claimingId);
            }

            // validate if user doesn't want to change partial share and unlock timestamp for claiming schedule from the past
            if (
                storageClaimingSchedule_.partialShare != requestClaimingSchedule_.partialShare ||
                storageClaimingSchedule_.unlockTimestamp != requestClaimingSchedule_.unlockTimestamp
            ) {
                revert MilestoneErrors.CannotChangePastClaimingSchedule(requestClaimingSchedule_.claimingId, block.timestamp);
            }
        }
    }

    /// @dev Internal function to iterate over schedules to calculate past claimings
    /// @param _storageClaimingSchedulesLength Amount of claiming schedules in the storage for given milestone
    /// @param _milestoneId UUID of the milestone
    /// @return Amount of claiming schedules from the past
    function getPastSchedulesAmount(uint256 _storageClaimingSchedulesLength, string memory _milestoneId) private view returns (uint256) {
        uint256 claimingSchedulesFromThePastLength_ = 0;

        // loop for calculating claiming schedules from the past
        for (uint i = 0; i < _storageClaimingSchedulesLength; i++) {
            StorageTypes.ClaimingSchedule memory storageClaimingSchedule_ = LibClaimingSchedule.getClaimingScheduleForIndex(_milestoneId, i);

            // verify if claiming schedules is from the past
            if (storageClaimingSchedule_.unlockTimestamp <= block.timestamp) {
                claimingSchedulesFromThePastLength_++;
            }
        }

        // return
        return claimingSchedulesFromThePastLength_;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

// Local imports - constants, encoders, events, errors, structs
import { RaiseErrors } from "../../../../errors/RaiseErrors.sol";
import { MilestoneErrors } from "../../../../errors/MilestoneErrors.sol";

// Local imports - storages
import { LibERC20Asset } from "../../../storage/assets/LibERC20Asset.sol";
import { LibEscrow } from "../../../storage/assets/LibEscrow.sol";
import { LibRaise } from "../../../storage/raise/LibRaise.sol";

// Local imports - services
import { RaiseService } from "../../raise/internal/RaiseService.sol";

library ERC20AssetService {
    using SafeERC20 for IERC20;

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

        // validate if allowance greater or equal amount
        if (allowance_ < _amount) {
            revert RaiseErrors.NotEnoughAllowance(_sender, self_, allowance_);
        }

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

    /// @dev Get ERC20 asset chain id.
    /// @param _raiseId Raise id
    /// @return ERC20Asset chain id
    function getERC20AssetChainId(string memory _raiseId) internal view returns (uint256) {
        return LibERC20Asset.getChainId(_raiseId);
    }

    /// @dev Validate an early stage raise.
    /// @param _raiseId Raise id
    function validateERC20(string memory _raiseId) internal view {
        // get erc20
        address erc20_ = LibERC20Asset.getAddress(_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 Check if all sold tokens are on escrow
    /// @param _raiseId Raise id
    function validateSoldTokensOnEscrow(string memory _raiseId) internal view {
        // get erc20
        address erc20_ = LibERC20Asset.getAddress(_raiseId);

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

        // get escrow balance
        uint256 balance_ = IERC20(erc20_).balanceOf(escrow_);

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

        // check if sold tokens are on escrow
        if (sold_ != balance_) {
            revert MilestoneErrors.NotEnoughTokensOnEscrow(balance_);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// LayerZero imports
import { ILayerZeroEndpoint } from "layer-zero/contracts/interfaces/ILayerZeroEndpoint.sol";

// Local imports - constants, encoders, events, errors, structs
import { CrossChainEncoder } from "../../../../encoders/CrossChainEncoder.sol";
import { CrossChainErrors } from "../../../../errors/cross-chain/CrossChainErrors.sol";
import { LayerZeroErrors } from "../../../../errors/cross-chain/LayerZeroErrors.sol";
import { RequestTypes } from "../../../../structs/RequestTypes.sol";
import { CrossChainRequestTypes } from "../../../../structs/CrossChainRequestTypes.sol";

// Local imports - storages
import { LibCrossChainEvmConfiguration } from "../../../storage/cross-chain/LibCrossChainEvmConfiguration.sol";
import { LibLayerZeroBase } from "../../../storage/cross-chain/layer-zero/LibLayerZeroBase.sol";
import { LibLayerZeroSender } from "../../../storage/cross-chain/layer-zero/LibLayerZeroSender.sol";

/// @notice Service responsible for sending cross-chain messages through LayerZero
library LayerZeroSenderService {
    // -----------------------------------------------------------------------
    //                              Send message
    // -----------------------------------------------------------------------

    /// @dev Send cross-chain message.
    /// @param _crossChainData Encoded data to send
    /// @param _nativeChainId Destination chain native id
    function sendCrossChainMessage(bytes calldata _crossChainData, uint256 _nativeChainId) internal {
        // decode LayerZero params
        CrossChainRequestTypes.LayerZeroData memory lzData_ = CrossChainEncoder.decodeLayerZeroData(_crossChainData);

        // validate data
        validateLayerZeroSendData(lzData_, _nativeChainId);

        // get LayerZero chain id
        uint16 lzChainId_ = LibLayerZeroSender.getNetwork(_nativeChainId);

        // get LayerZero endpoint
        address lzEndpoint_ = LibLayerZeroBase.getCrossChainEndpoint();

        // get destination fundraising address
        address destination_ = LibCrossChainEvmConfiguration.getFundraising(_nativeChainId);

        // get address needed to potential refund
        address payable refundAddress_ = payable(LibLayerZeroSender.getRefundAddress());

        // calculate LayerZero trusted remote
        bytes memory trustedRemote_ = abi.encodePacked(destination_, address(this));

        // send cross-chain message
        ILayerZeroEndpoint(lzEndpoint_).send{ value: lzData_.fee }(
            lzChainId_,
            trustedRemote_,
            lzData_.payload,
            refundAddress_,
            address(0), // Parameter which will be used by LayerZero in the future when they'll have their token, right now hardcoded
            lzData_.additionalParams
        );
    }

    // -----------------------------------------------------------------------
    //                              Validation
    // -----------------------------------------------------------------------

    /// @dev Validate LayerZero data before send.
    /// @param _lzData RequestTypes.LayerZeroData struct
    /// @param _chainId Destination chain native id
    function validateLayerZeroSendData(CrossChainRequestTypes.LayerZeroData memory _lzData, uint256 _chainId) internal view {
        // validate if payload is not empty
        if (_lzData.payload.length == 0) {
            revert CrossChainErrors.EmptyPayload();
        }

        // validate if destination chain is supported
        if (LibLayerZeroSender.getNetwork(_chainId) == 0) {
            revert LayerZeroErrors.UnsupportedLayerZeroChain(_chainId);
        }

        // validate if function to perform is supported
        bytes4 functionToCall_ = bytes4(_lzData.payload);
        if (!LibCrossChainEvmConfiguration.getSupportedFunction(_chainId, functionToCall_)) {
            revert LayerZeroErrors.UnsupportedFunction(_chainId, functionToCall_);
        }

        // validate if LayerZero fee is not equal 0
        if (_lzData.fee == 0) {
            revert LayerZeroErrors.InvalidLayerZeroFee();
        }

        // validate if sent native tokens is at least the same like LayerZero fee
        if (msg.value < _lzData.fee) {
            revert LayerZeroErrors.InvalidNativeSent(msg.value, _lzData.fee);
        }
    }
}

File 15 of 46 : StorageTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports
import { EnumTypes } from "./EnumTypes.sol";

/// @notice Library with core storage structs definition.
library StorageTypes {
    // -----------------------------------------------------------------------
    //                              Raise
    // -----------------------------------------------------------------------

    /// @dev Struct containing main information about the raise.
    /// @param raiseId UUID of raise
    /// @param raiseType Type of raise
    /// @param owner Address of startup
    struct Raise {
        string raiseId;
        EnumTypes.RaiseType raiseType;
        address owner;
    }

    /// @dev Struct containing main information about the raise for Substrate-based chains.
    /// @param raiseId UUID of raise
    /// @param raiseType Type of raise
    /// @param owner Substrate address of startup
    struct SubstrateRaise {
        string raiseId;
        EnumTypes.RaiseType raiseType;
        string owner;
    }

    /// @dev Struct containing detailed info about raise.
    /// @param tokensPerBaseAsset Ratio of how much tokens is worth 1 unit of base asset (erc20 * precision / hardcap)
    /// @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
    struct RaiseDetails {
        uint256 tokensPerBaseAsset;
        uint256 hardcap;
        uint256 softcap;
        uint256 start;
        uint256 end;
    }

    /// @dev Struct containing information about the raise shared across chains.
    /// @param raised Amount of raised base asset for fundraising
    /// @param merkleRoot Merkle root compressing all information about investors and their investments
    struct RaiseDataCC {
        uint256 raised;
        bytes32 merkleRoot;
    }

    // -----------------------------------------------------------------------
    //                              ERC-20 Asset
    // -----------------------------------------------------------------------

    /// @dev Struct defining ERC20 offered by startup for investments.
    /// @param erc20 Address of ERC20 token
    /// @param chainId ID of network that asset exists
    /// @param amount Total amount of ERC20 used in vesting
    struct ERC20Asset {
        address erc20;
        uint256 chainId;
        uint256 amount;
    }

    /// @dev Struct defining PSP22 offered by startup for investments for Substrate-based chains.
    /// @param psp22 Address of PSP22 token
    /// @param chainId ID of network that asset exists
    /// @param amount Total amount of PSP22 used in vesting
    struct PSP22Asset {
        string psp22;
        uint256 chainId;
        uint256 amount;
    }

    // -----------------------------------------------------------------------
    //                              Base Asset
    // -----------------------------------------------------------------------

    /// @dev Struct defining base asset used for investment on particular chain.
    /// @param base Address of base asset
    /// @param chainId ID of network that asset exists
    struct BaseAsset {
        address base;
        uint256 chainId;
    }

    /// @dev Struct defining base asset used for investment on particular chain.
    /// @param ethBase Address of eth base asset
    /// @param azBase Address of substrate base asset
    /// @param chainId ID of network that asset exists
    struct SubstrateBaseAsset {
        address ethBase;
        string azBase;
        uint256 chainId;
    }

    // -----------------------------------------------------------------------
    //                              Investor Funds Info
    // -----------------------------------------------------------------------

    /// @dev Struct containing info about state of investor funds.
    /// @param invested Mapping that stores how much given address invested
    /// @param investmentRefunded Mapping that tracks if user was refunded
    struct InvestorFundsInfo {
        mapping(address => uint256) invested;
        mapping(address => bool) investmentRefunded;
    }

    // -----------------------------------------------------------------------
    //                              Startup Funds Info
    // -----------------------------------------------------------------------

    /// @dev Struct containing info about state of startup funds.
    /// @param collateralRefunded Boolean describing if startup was refunded
    /// @param reclaimed Boolean that shows if startup reclaimed unsold tokens
    struct StartupFundsInfo {
        bool collateralRefunded;
        bool reclaimed;
    }

    // -----------------------------------------------------------------------
    //                              Milestone
    // -----------------------------------------------------------------------

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

    /// @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 {
        Milestone[] milestones;
        uint256 unlockedShares;
        uint256 rejectedShares;
        uint256 totalShares;
    }

    // -----------------------------------------------------------------------
    //                              Claiming
    // -----------------------------------------------------------------------

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

    /// @dev Struct containing informations about claiming schedules for investors.
    /// @param claimingId UUID of claiming
    /// @param milestoneId UUID of milestone
    /// @param partialShare Share of milestone tokens which are unlocked in the given claiming
    /// @param unlockTimestamp Timestamp on which tokens are unlocked
    struct ClaimingSchedule {
        string claimingId;
        string milestoneId;
        uint256 partialShare;
        uint256 unlockTimestamp;
    }
}

File 16 of 46 : RequestErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

    Request errors

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

/// @dev 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
    error RaiseCannotBeFinishedYet(string raiseId, uint256 endTimestamp); // 0x7ae96774
    error BadgeUriEmpty(); // 0xb03cfc55
    error MerkleRootSet(uint256 raised, uint256 softcap, bytes32 merkleRoot); // 0x77242f66
    error MerkleRootNotSet(uint256 raised, uint256 softcap, bytes32 merkleRoot); // 0xfe60e7d0
    error InvalidMerkleProofs(string raiseId, address user, uint256 investment, bytes32[] proofs, bytes32 root, bytes32 leaf); // 0xa112d454
    error InvalidRaisedAmount(string raiseId, uint256 providedRaised, uint256 correctRaised); // 0x2d6d8be6
    error RaiseFinishedAlready(string raiseId); // 0xdef0e29b
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    Nonce library

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

    Diamond storage containing nonces

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

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

    /// @dev Storage pointer.
    bytes32 internal 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;
    }

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

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

// 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 19 of 46 : SignatureConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Constants used in signature verification.
library SignatureConstants {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev EIP-712 typehash
    bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
}

File 20 of 46 : SignatureErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    Signature errors
    
**************************************/

/// @dev All errors used in the signature verification
library SignatureErrors {
    error IncorrectSigner(address signer); // 0x33ffff9b
    error InvalidMessage(bytes32 verify, bytes32 message); // 0xeeba4d9c
}

File 21 of 46 : AccessTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    /// @dev AngelBlock validator role
    bytes32 internal constant SIGNER_ROLE = keccak256("IS SIGNER");
    /// @dev LayerZero receiver's admin role
    bytes32 internal constant LZ_RECEIVER_ADMIN_ROLE = keccak256("LZ RECEIVER ADMIN");
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// 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 internal constant ACCESS_CONTROL_STORAGE_POSITION = keccak256("angelblock.access.control");

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

    /// @dev Default admin role
    bytes32 internal 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 23 of 46 : MilestoneErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    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
    error NotEnoughTokensOnEscrow(uint256 balance); // 0xe60fdbcf
    error OtcMilestoneMustUnlockAllShares(); // 0x6f42ad6b

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

    error NoMilestoneUnlocked(string raiseId); // 0x335b87f2
    error NoClaimingSchedule(string raiseId); // 0xcb6d4142
    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

    // -----------------------------------------------------------------------
    //                      Submit claiming schedule
    // -----------------------------------------------------------------------

    error MilestoneNotExists(string milestoneId); // 0x269afc46
    error ClaimingScheduleAlreadyExists(string claimingScheduleId); // 0xe8616ede
    error UnlockedShareLimitExceeded(string milestoneId); // 0xf877f9b6
    error SharesAlreadySubmitted(string milestoneId); // 0x8e7ee80d
    error SubmittedSharesMustEqualMilestoneShare(string milestoneId, uint256 milestoneShare, uint256 submittedShares); // 0x2c64027e

    // -----------------------------------------------------------------------
    //                      Reschedule claimings
    // -----------------------------------------------------------------------

    error CannotChangePastClaimingSchedule(string claimingScheduleId, uint256 unlockTimestamp); // 0x30905127
    error CannotChangeMilestoneId(string claimingScheduleId, string requestMilestoneId, string storageMilestoneId); // 0xd39ab080
    error CannotChangeClaimingId(string requestClaimingScheduleId, string storageClaimingScheduleId); // 0xe3d6928c
    error RescheduledSharesMustEqualMilestoneShare(string milestoneId, uint256 milestoneShare, uint256 rescheduledShares); // 0x881cdd8c
    error UnlockedTimestampMustBeLater(string claimingScheduleId, uint256 requestUnlockTimestamp, uint256 previousUnlockTimestamp); // 0xb94a1b80
    error EmptyClaimingSchedules(); // 0xcc393bbb
    error CannotDeletePastSchedule(); // 0x79f36780
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

// Local imports
import { LibBaseAsset } from "../assets/LibBaseAsset.sol";
import { StorageTypes } from "../../../structs/StorageTypes.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 internal constant MILESTONE_STORAGE_POSITION = keccak256("angelblock.fundraising.milestone");
    /// @dev Precision for share calculation.
    uint256 internal 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 => StorageTypes.ShareInfo) shares;
        mapping(string => StorageTypes.ClaimingInfo) votingClaiming;
        mapping(string => StorageTypes.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 extensions function: verify if milestone exists
    /// @param _raiseId ID of raise
    /// @param _milestoneId ID of milestone
    /// @return Struct with given params : 1. Is milestone exists, 2. Index of the milestone in the storage array
    function milestoneExists(string memory _raiseId, string memory _milestoneId) internal view returns (bool, uint256) {
        // Fetch all milestone for given raise id from the storage
        StorageTypes.Milestone[] memory milestones_ = milestoneStorage().shares[_raiseId].milestones;

        // check all milestone in the storage
        for (uint i = 0; i < milestones_.length; i++) {
            string memory storageMilestoneId_ = milestones_[i].milestoneId;

            // verify milestone ids
            if (keccak256(abi.encodePacked(storageMilestoneId_)) == keccak256(abi.encodePacked(_milestoneId))) {
                // return when milestone exists
                return (true, i);
            }
        }

        // return when milestone not exists
        return (false, 0);
    }

    /// @dev Diamond storage getter: milestone
    /// @param _raiseId ID of raise
    /// @param _milestoneIndex Index of the milestone in the storage array
    /// @return Milestone struct
    function getMilestone(string memory _raiseId, uint256 _milestoneIndex) internal view returns (StorageTypes.Milestone memory) {
        return milestoneStorage().shares[_raiseId].milestones[_milestoneIndex];
    }

    /// @dev Diamond storage getter: milestone->id
    /// @param _raiseId ID of raise
    /// @param _milestoneIndex Index of the milestone in the storage array
    /// @return Id of the milestone
    function getMilestoneId(string memory _raiseId, uint256 _milestoneIndex) internal view returns (string memory) {
        return milestoneStorage().shares[_raiseId].milestones[_milestoneIndex].milestoneId;
    }

    /// @dev Diamond storage getter: milestone->share
    /// @param _raiseId ID of raise
    /// @param _milestoneIndex Index of the milestone in the storage array
    /// @return Share of the milestone
    function getMilestoneShare(string memory _raiseId, uint256 _milestoneIndex) internal view returns (uint256) {
        return milestoneStorage().shares[_raiseId].milestones[_milestoneIndex].share;
    }

    /// @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, StorageTypes.Milestone memory _milestone) internal {
        // get shares
        StorageTypes.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(LibBaseAsset.getAddress(_raiseId), 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(LibBaseAsset.getAddress(_raiseId), IEscrow.ReceiverData(_recipient, _amount));
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

    Claiming schedule library

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

    Diamond storage containing claiming schedule data

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

/// @notice Library containing ClaimingScheduleStorage and low level functions.
library LibClaimingSchedule {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Claiming schedule storage pointer.
    bytes32 private constant CLAIMING_SCHEDULES_STORAGE_POSITION = keccak256("angelblock.fundraising.claiming.schedule");

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

    /// @dev Claiming schedule storage struct.
    /// @param claimingScheduleIds Ids of claiming schedules for given milestone id
    /// @param claimingSchedules Mapping of claiming schedules
    struct ClaimingScheduleStorage {
        mapping(string => string[]) claimingScheduleIds;
        mapping(string => mapping(string => StorageTypes.ClaimingSchedule)) claimingSchedules;
    }

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

    /// @dev Function returning claiming schedule storage at storage pointer slot.
    /// @return css ClaimingScheduleStorage struct instance at storage pointer position
    function claimingScheduleStorage() private pure returns (ClaimingScheduleStorage storage css) {
        // declare position
        bytes32 position = CLAIMING_SCHEDULES_STORAGE_POSITION;

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

        // explicit return
        return css;
    }

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

    /// @dev Diamond storage getter: claiming schedules -> length.
    /// @param _milestoneId ID of milestone
    /// @return Length of claiming schedules
    function claimingScheduleCount(string memory _milestoneId) internal view returns (uint256) {
        return claimingScheduleStorage().claimingScheduleIds[_milestoneId].length;
    }

    /// @dev Diamond storage getter: claiming schedule ids.
    /// @param _milestoneId ID of milestone
    /// @return Array of claiming schedule ids
    function getClaimingScheduleIds(string memory _milestoneId) internal view returns (string[] memory) {
        return claimingScheduleStorage().claimingScheduleIds[_milestoneId];
    }

    /// @dev Diamond storage getter: claiming schedule.
    /// @param _milestoneId ID of milestone
    /// @param _claimingScheduleId ID of claiming schedule
    /// @return Claiming schedule struct
    function getClaimingSchedule(
        string memory _milestoneId,
        string memory _claimingScheduleId
    ) internal view returns (StorageTypes.ClaimingSchedule memory) {
        return claimingScheduleStorage().claimingSchedules[_milestoneId][_claimingScheduleId];
    }

    /// @dev Diamond storage getter: claiming schedule for given index in the storage array
    /// @param _milestoneId ID of milestone
    /// @param _index Claiming schedule index in the storage array
    function getClaimingScheduleForIndex(
        string memory _milestoneId,
        uint256 _index
    ) internal view returns (StorageTypes.ClaimingSchedule memory) {
        ClaimingScheduleStorage storage css = claimingScheduleStorage();
        return css.claimingSchedules[_milestoneId][css.claimingScheduleIds[_milestoneId][_index]];
    }

    /// @dev Diamond storage getter: claiming schedule -> partial share
    /// @param _milestoneId ID of milestone
    /// @param _claimingScheduleId ID of claiming schedule
    /// @return Claiming schedule partial share
    function getPartialShare(string memory _milestoneId, string memory _claimingScheduleId) internal view returns (uint256) {
        return claimingScheduleStorage().claimingSchedules[_milestoneId][_claimingScheduleId].partialShare;
    }

    /// @dev Diamond storage getter: claiming schedule -> unlock timestamp
    /// @param _milestoneId ID of milestone
    /// @param _claimingScheduleId ID of claiming schedule
    /// @return Claiming schedule unlock timestamp
    function getUnlockTimestamp(string memory _milestoneId, string memory _claimingScheduleId) internal view returns (uint256) {
        return claimingScheduleStorage().claimingSchedules[_milestoneId][_claimingScheduleId].unlockTimestamp;
    }

    /// @dev Diamond storage setter: add claiming schedule.
    /// @param _claimingSchedule Claiming schedule to add
    function createClaimingSchedule(StorageTypes.ClaimingSchedule memory _claimingSchedule) internal {
        // add claiming schedule id to ids in storage
        claimingScheduleStorage().claimingScheduleIds[_claimingSchedule.milestoneId].push(_claimingSchedule.claimingId);

        // set claiming schedule
        claimingScheduleStorage().claimingSchedules[_claimingSchedule.milestoneId][_claimingSchedule.claimingId] = _claimingSchedule;
    }

    /// @dev Diamond storage setter: update claiming schedule.
    /// @param _claimingSchedule Claiming schedule to update
    function updateClaimingSchedule(StorageTypes.ClaimingSchedule memory _claimingSchedule) internal {
        // set claiming schedule
        claimingScheduleStorage().claimingSchedules[_claimingSchedule.milestoneId][_claimingSchedule.claimingId] = _claimingSchedule;
    }

    /// @dev Diamond storage setter: delete claiming schedules.
    /// @param _milestoneId ID of milestone
    /// @param _amountsToRemove Amount of claiming schedules to delete
    function deleteClaimingSchedules(string memory _milestoneId, uint256 _amountsToRemove) internal {
        ClaimingScheduleStorage storage css = claimingScheduleStorage();

        for (uint i = 0; i < _amountsToRemove; i++) {
            // calculdate current amount of claming schedules
            uint256 claimingSchedulesLength_ = claimingScheduleCount(_milestoneId);

            // fetch last claiming schedule id
            string memory claimingScheduleId_ = css.claimingScheduleIds[_milestoneId][claimingSchedulesLength_ - 1];

            // remove last value from claiming schedule ids array
            css.claimingScheduleIds[_milestoneId].pop();
            // set default values for given claiming schedule id in the storage
            css.claimingSchedules[_milestoneId][claimingScheduleId_] = StorageTypes.ClaimingSchedule({
                claimingId: "",
                milestoneId: "",
                partialShare: 0,
                unlockTimestamp: 0
            });
        }
    }

    /// @dev Diamond storage setter: set claiming schedule unlock timestamp.
    /// @param _milestoneId ID of milestone
    /// @param _claimingScheduleId ID of claiming schedule
    /// @param _newUnlockTimestamp New unlock timestamp
    function setUnlockTimestamp(string memory _milestoneId, string memory _claimingScheduleId, uint256 _newUnlockTimestamp) internal {
        // set claiming schedule unlock timestamp
        claimingScheduleStorage().claimingSchedules[_milestoneId][_claimingScheduleId].unlockTimestamp = _newUnlockTimestamp;
    }
}

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

// 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 28 of 46 : RaiseErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    Raise errors

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

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

    error InvalidRaiseId(string raiseId); // 0xc2f9a803
    error InvalidRaiseStartEnd(uint256 start, uint256 end); // 0xb2fb4a1d
    error StartDateInPast(uint256 start); // 0x28b25bae
    error HardcapLessThanSoftcap(uint256 hardcap, uint256 softcap); // 0xa13f495f
    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
    error OnlyForStandard(string raiseId); // 0x493e93f0

    // -----------------------------------------------------------------------
    //                                 OTC
    // -----------------------------------------------------------------------

    error CannotForOTC(string raiseId); // 0x886ebb60

    // -----------------------------------------------------------------------
    //                              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 RaiseNotFailed(string raiseId); // 0x1e45b786
    error RaiseNotSucceed(string raiseId); // 0x3925f3e4
    error RaiseAlreadyFinished(string raiseId); // 0x0287eafc

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

    error HardcapAchieved(string raiseId); // 0x8e144f11

    // -----------------------------------------------------------------------
    //                              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
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - Structs
import { StorageTypes } from "../../../structs/StorageTypes.sol";

/// @dev Library containing ERC-20 asset storage with getters and setters
library LibERC20Asset {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev ERC-20 asset storage pointer.
    bytes32 internal constant ERC20_ASSET_STORAGE_POSITION = keccak256("angelblock.fundraising.erc20");

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

    /// @dev ERC-20 asset storage struct.
    /// @param erc20 Mapping of raise id to ERC-20 asset struct
    struct ERC20AssetStorage {
        mapping(string => StorageTypes.ERC20Asset) erc20;
    }

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

    /// @dev Function returning ERC-20 asset storage at storage pointer slot.
    /// @return eas ERC20AssetStorage struct instance at storage pointer position
    function erc20AssetStorage() internal pure returns (ERC20AssetStorage storage eas) {
        // declare position
        bytes32 position = ERC20_ASSET_STORAGE_POSITION;

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

        // explicit return
        return eas;
    }

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

    /// @dev Diamond storage getter: ERC-20 asset address.
    /// @param _raiseId ID of the raise
    /// @return Address of the ERC-20 asset
    function getAddress(string memory _raiseId) internal view returns (address) {
        return erc20AssetStorage().erc20[_raiseId].erc20;
    }

    /// @dev Diamond storage getter: ERC-20 asset chain id.
    /// @param _raiseId ID of the raise
    /// @return Id of the chain
    function getChainId(string memory _raiseId) internal view returns (uint256) {
        // return
        return erc20AssetStorage().erc20[_raiseId].chainId;
    }

    /// @dev Diamond storage setter: ERC-20 asset chain id.
    /// @param _raiseId ID of the raise
    /// @param _chainId Id of the chain
    function setChainId(string memory _raiseId, uint256 _chainId) internal {
        erc20AssetStorage().erc20[_raiseId].chainId = _chainId;
    }

    /// @dev Diamond storage getter: ERC-20 asset vested amount.
    /// @param _raiseId ID of the raise
    /// @return Amount of vested ERC-20 tokens
    function getAmount(string memory _raiseId) internal view returns (uint256) {
        return erc20AssetStorage().erc20[_raiseId].amount;
    }

    /// @dev Diamond storage setter: ERC-20 asset vested amount.
    /// @param _raiseId ID of the raise
    /// @param _amount Amount of vested ERC-20 tokens
    function setAmount(string memory _raiseId, uint256 _amount) internal {
        erc20AssetStorage().erc20[_raiseId].amount = _amount;
    }

    /// @dev Diamond storage setter: ERC-20 asset
    /// @param _raiseId ID of the raise
    /// @param _erc20Asset StorageTypes.ERC20Asset struct
    function setERC20Asset(string memory _raiseId, StorageTypes.ERC20Asset memory _erc20Asset) internal {
        erc20AssetStorage().erc20[_raiseId] = _erc20Asset;
    }

    /// @dev Diamond storage setter: ERC-20 asset address.
    /// @param _raiseId ID of the raise
    /// @param _erc20 Address of the ERC-20 asset
    function setERC20Address(string memory _raiseId, address _erc20) internal {
        erc20AssetStorage().erc20[_raiseId].erc20 = _erc20;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Library containing Escrow storage with getters and setters.
library LibEscrow {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

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

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

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

    /// @dev Diamond storage getter: Escrow source address.
    /// @return Escrow source address.
    function getSource() internal view returns (address) {
        return escrowStorage().source;
    }

    /// @dev Diamond storage getter: Escrow address.
    /// @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 Diamond storage setter: Escrow source.
    /// @param _source Address of the source
    function setSource(address _source) internal {
        // set source address
        escrowStorage().source = _source;
    }

    /// @dev Diamond storage setter: Escrow address for raise.
    /// @param _raiseId Id of the Raise.
    /// @param _escrow Address of the escrow
    function setEscrow(string memory _raiseId, address _escrow) internal {
        // set Escrow
        escrowStorage().escrows[_raiseId] = _escrow;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - Structs
import { StorageTypes } from "../../../structs/StorageTypes.sol";
import { EnumTypes } from "../../../structs/EnumTypes.sol";

/// @notice Library containing raise storage with getters and setters.
library LibRaise {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Raise storage pointer.
    bytes32 internal constant RAISE_STORAGE_POSITION = keccak256("angelblock.fundraising.storage.raise");
    /// @dev Precision used in price calculation
    uint256 internal constant PRICE_PRECISION = 10 ** 18;

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

    /// @dev Raise storage struct.
    /// @param raises Mapping of raise id to particular raise struct
    /// @param raiseDetails Mapping of raise id to vested token information
    /// @param raiseDataCrosschains Mapping of raise id to raise state information
    /// @param raiseStatus Status of raise
    struct RaiseStorage {
        mapping(string => StorageTypes.Raise) raises;
        mapping(string => StorageTypes.RaiseDetails) raiseDetails;
        mapping(string => StorageTypes.RaiseDataCC) raiseDataCrosschains;
        mapping(string => EnumTypes.RaiseStatus) raiseStatus;
    }

    // diamond storage getter
    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: raise id.
    /// @param _raiseId Requested raise id
    /// @return Existing raise id
    function getId(string memory _raiseId) internal view returns (string memory) {
        // return
        return raiseStorage().raises[_raiseId].raiseId;
    }

    /// @dev Diamond storage getter: raise type.
    /// @param _raiseId Raise id
    /// @return Raise type
    function getType(string memory _raiseId) internal view returns (EnumTypes.RaiseType) {
        // return
        return raiseStorage().raises[_raiseId].raiseType;
    }

    /// @dev Diamond storage getter: raise owner.
    /// @param _raiseId Raise id
    /// @return Raise owner
    function getOwner(string memory _raiseId) internal view returns (address) {
        // return
        return raiseStorage().raises[_raiseId].owner;
    }

    /// @dev Diamond storage getter: tokens per base asset.
    /// @param _raiseId Raise id
    /// @return Tokens per base asset
    function getTokensPerBaseAsset(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDetails[_raiseId].tokensPerBaseAsset;
    }

    /// @dev Diamond storage setter: tokens per base asset.
    /// @param _raiseId Raise id
    /// @param _tokensPerBaseAsset Tokens per base asset
    function setTokensPerBaseAsset(string memory _raiseId, uint256 _tokensPerBaseAsset) internal {
        raiseStorage().raiseDetails[_raiseId].tokensPerBaseAsset = _tokensPerBaseAsset;
    }

    /// @dev Diamond storage getter: hardcap.
    /// @param _raiseId Raise id
    /// @return Hardcap
    function getHardcap(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDetails[_raiseId].hardcap;
    }

    /// @dev Diamond storage getter: softcap.
    /// @param _raiseId Raise id
    /// @return Softcap
    function getSoftcap(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDetails[_raiseId].softcap;
    }

    /// @dev Diamond storage getter: raise start.
    /// @param _raiseId Raise id
    /// @return Start date of raise
    function getStart(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDetails[_raiseId].start;
    }

    /// @dev Diamond storage getter: raise end.
    /// @param _raiseId Raise id
    /// @return End date of raise
    function getEnd(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDetails[_raiseId].end;
    }

    /// @dev Diamond storage getter: raised.
    /// @param _raiseId Raise id
    /// @return Raised amount
    function getRaised(string memory _raiseId) internal view returns (uint256) {
        // return
        return raiseStorage().raiseDataCrosschains[_raiseId].raised;
    }

    /// @dev Diamond storage getter: merkle root.
    /// @param _raiseId Raise id
    /// @return Merkle root
    function getMerkleRoot(string memory _raiseId) internal view returns (bytes32) {
        return raiseStorage().raiseDataCrosschains[_raiseId].merkleRoot;
    }

    /// @dev Diamond storage getter: raise status.
    /// @param _raiseId Raise id
    /// @return Status of raise with provided id
    function getRaiseStatus(string memory _raiseId) internal view returns (EnumTypes.RaiseStatus) {
        return raiseStorage().raiseStatus[_raiseId];
    }

    /// @dev Diamond storage setter: set raise.
    /// @param _raiseId Raise id
    /// @param _raise Raise struct
    function setRaise(string memory _raiseId, StorageTypes.Raise memory _raise) internal {
        // set raise
        raiseStorage().raises[_raiseId] = _raise;
    }

    /// @dev Diamond storage setter: set raise details.
    /// @param _raiseId Raise id
    /// @param _raiseDetails Raise details struct
    function setRaiseDetails(string memory _raiseId, StorageTypes.RaiseDetails memory _raiseDetails) internal {
        // set raise details
        raiseStorage().raiseDetails[_raiseId] = _raiseDetails;
    }

    /// @dev Diamond storage setter: set raise cross-chain data.
    /// @param _raiseId Raise id
    /// @param _raiseDataCC Raise cross-chain data struct
    function setRaiseDataCrosschain(string memory _raiseId, StorageTypes.RaiseDataCC memory _raiseDataCC) internal {
        // set cross-chain raise data
        raiseStorage().raiseDataCrosschains[_raiseId] = _raiseDataCC;
    }

    /// @dev Diamond storage setter: raise status.
    /// @param _raiseId Raise id
    /// @param _status Raise enum status
    function setRaiseStatus(string memory _raiseId, EnumTypes.RaiseStatus _status) internal {
        raiseStorage().raiseStatus[_raiseId] = _status;
    }

    /// @dev Diamond storage setter: set end.
    /// @param _raiseId Raise id
    /// @param _end End date of fundraising
    function setEnd(string memory _raiseId, uint256 _end) internal {
        // set raise end date
        raiseStorage().raiseDetails[_raiseId].end = _end;
    }

    /// @dev Diamond storage setter: increase raised amount.
    /// @param _raiseId Raise id
    /// @param _amount Raised increment of amount
    function increaseRaised(string memory _raiseId, uint256 _amount) internal {
        raiseStorage().raiseDataCrosschains[_raiseId].raised += _amount;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - constants, encoders, events, errors, structs
import { RequestErrors } from "../../../../errors/RequestErrors.sol";
import { RaiseErrors } from "../../../../errors/RaiseErrors.sol";
import { CrossChainErrors } from "../../../../errors/cross-chain/CrossChainErrors.sol";
import { StorageTypes } from "../../../../structs/StorageTypes.sol";
import { EnumTypes } from "../../../../structs/EnumTypes.sol";

// Local imports - storages
import { LibRaise } from "../../../storage/raise/LibRaise.sol";
import { LibERC20Asset } from "../../../storage/assets/LibERC20Asset.sol";
import { LibBaseAsset } from "../../../storage/assets/LibBaseAsset.sol";
import { LibNonce } from "../../../storage/utils/LibNonce.sol";

library RaiseService {
    /**************************************

        Create raise

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

    /// @dev Set to storage all raise and assets data.
    /// @param _raiseId ID of the raise
    /// @param _sender Message sender
    /// @param _nonce Used nonce
    /// @param _raise StorageTypes.Raise struct
    /// @param _raiseDetails StorageTypes.RaiseDetails struct
    /// @param _erc20Asset StorageTypes.ERC20Asset struct
    /// @param _baseAsset StorageTypes.BaseAsset struct
    function setRaiseCreationData(
        string memory _raiseId,
        address _sender,
        uint256 _nonce,
        StorageTypes.Raise memory _raise,
        StorageTypes.RaiseDetails memory _raiseDetails,
        StorageTypes.ERC20Asset memory _erc20Asset,
        StorageTypes.BaseAsset memory _baseAsset
    ) internal {
        // set raise to storage
        LibRaise.setRaise(_raiseId, _raise);
        // set raise details to storage
        LibRaise.setRaiseDetails(_raiseId, _raiseDetails);
        // set ERC-20 asset to storage
        LibERC20Asset.setERC20Asset(_raiseId, _erc20Asset);
        // set base asset to storage
        LibBaseAsset.setBaseAsset(_raiseId, _baseAsset);
        // set status
        LibRaise.setRaiseStatus(_raiseId, EnumTypes.RaiseStatus.RaiseCreated);
        // set nonce as used to storage
        LibNonce.setNonce(_sender, _nonce);
    }

    function validateCreationRequest(
        StorageTypes.Raise memory _raise,
        StorageTypes.RaiseDetails memory _raiseDetails,
        StorageTypes.ERC20Asset memory _erc20Asset,
        address _sender,
        uint256 _nonce
    ) internal view {
        if (_nonce <= LibNonce.getLastNonce(_sender)) {
            revert RequestErrors.NonceExpired(_sender, _nonce);
        }

        // check raise id
        if (bytes(_raise.raiseId).length == 0) {
            revert RaiseErrors.InvalidRaiseId(_raise.raiseId);
        }

        // verify if raise does not exist
        if (isRaiseExists(_raise.raiseId)) {
            revert RaiseErrors.RaiseAlreadyExists(_raise.raiseId);
        }

        // check start and end date
        if (_raiseDetails.start >= _raiseDetails.end) {
            revert RaiseErrors.InvalidRaiseStartEnd(_raiseDetails.start, _raiseDetails.end);
        }

        // start date and end date can be in present or future
        if (_raiseDetails.start < block.timestamp) {
            revert RaiseErrors.StartDateInPast(_raiseDetails.start);
        }

        // check hardcap and softcap
        if (_raiseDetails.hardcap < _raiseDetails.softcap) {
            revert RaiseErrors.HardcapLessThanSoftcap(_raiseDetails.hardcap, _raiseDetails.softcap);
        }

        // check if tokens are vested
        if (_erc20Asset.amount == 0) {
            revert RaiseErrors.InvalidVestedAmount();
        }

        // validate price per token == vested / hardcap
        if (_raiseDetails.tokensPerBaseAsset != (_erc20Asset.amount * LibRaise.PRICE_PRECISION) / _raiseDetails.hardcap) {
            revert RaiseErrors.PriceNotMatchConfiguration(_raiseDetails.tokensPerBaseAsset, _raiseDetails.hardcap, _erc20Asset.amount);
        }

        // validate token address for Early Stage type
        // TODO: Add support for AZ PSP22 here
        if (_raise.raiseType != EnumTypes.RaiseType.EarlyStage && _erc20Asset.erc20 == address(0)) {
            revert RaiseErrors.InvalidTokenAddress(_erc20Asset.erc20);
        }
    }

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

        Finish raise

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

    /// @dev Set finish raise
    /// @param _raiseId ID of the raise
    /// @param _raised uint256 raised funds
    /// @param _merkleRoot bytes32 merkle root
    function setFinishRaiseData(string memory _raiseId, uint256 _raised, bytes32 _merkleRoot) internal {
        StorageTypes.RaiseDataCC memory raiseDataCC_ = StorageTypes.RaiseDataCC({ raised: _raised, merkleRoot: _merkleRoot });
        LibRaise.setRaiseDataCrosschain(_raiseId, raiseDataCC_);

        if (isSoftcapAchieved(_raiseId)) {
            LibRaise.setRaiseStatus(_raiseId, EnumTypes.RaiseStatus.RaiseSucceed);
        } else {
            LibRaise.setRaiseStatus(_raiseId, EnumTypes.RaiseStatus.RaiseFailed);
        }
    }

    /// @dev Used for both: sender and receiver
    /// @param _raiseId ID of the raise
    /// @param _sender Message sender
    /// @param _nonce Used nonce
    function validateFinishRaiseRequest(string memory _raiseId, address _sender, uint256 _nonce) internal view {
        if (_nonce <= LibNonce.getLastNonce(_sender)) {
            revert RequestErrors.NonceExpired(_sender, _nonce);
        }

        if (LibRaise.getMerkleRoot(_raiseId) != 0) {
            revert RaiseErrors.RaiseAlreadyFinished(_raiseId);
        }
    }

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

        Sold / unsold

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

    /// @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) {
        // get tokens per base asset
        uint256 tokensPerBaseAsset_ = LibRaise.getTokensPerBaseAsset(_raiseId);

        // get raised
        uint256 raised_ = LibRaise.getRaised(_raiseId);

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

    /// @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) {
        // get all vested tokens
        uint256 vested_ = LibERC20Asset.getAmount(_raiseId);

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

        // return
        return vested_ - sold_;
    }

    /// @dev Get amount of unsold tokens.
    /// @param _raiseId ID of raise
    /// @param _diff Amount of unsold base asset
    /// @return Amount of tokens to reclaim by startup
    function calculateUnsold(string memory _raiseId, uint256 _diff) internal view returns (uint256) {
        // calculate how much tokens are unsold
        return (LibRaise.getTokensPerBaseAsset(_raiseId) * _diff) / LibRaise.PRICE_PRECISION;
    }

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

        Getters

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

    /// @dev Get amount of raised funds.
    /// @param _raiseId ID of raise
    /// @return Amount of collected funds in fundraising
    function getRaised(string memory _raiseId) internal view returns (uint256) {
        return LibRaise.getRaised(_raiseId);
    }

    /// @dev Get softcap limit.
    /// @param _raiseId ID of raise
    /// @return Softcap limit
    function getSoftcap(string memory _raiseId) internal view returns (uint256) {
        return LibRaise.getSoftcap(_raiseId);
    }

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

        Checks

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

    /// @dev Check if raise for given id exists.
    /// @param _raiseId ID of the raise
    /// @return True if raise exists
    function isRaiseExists(string memory _raiseId) internal view returns (bool) {
        // return
        return bytes(LibRaise.getId(_raiseId)).length != 0;
    }

    /// @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 start time
        uint256 start_ = LibRaise.getStart(_raiseId);
        // get raise end time
        uint256 end_ = LibRaise.getEnd(_raiseId);

        // final check
        return start_ <= now_ && now_ <= end_;
    }

    /// @dev Validation if raise was completed.
    /// @param _raiseId ID of raise
    function validateCompletedRaise(string memory _raiseId) internal view {
        // verify raise exists
        if (!isRaiseExists(_raiseId)) {
            revert RaiseErrors.RaiseDoesNotExists(_raiseId);
        }

        // check if raise failed already
        if (LibRaise.getRaiseStatus(_raiseId) != EnumTypes.RaiseStatus.RaiseSucceed) {
            revert RaiseErrors.RaiseNotSucceed(_raiseId);
        }
    }

    /// @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) {
        // return
        return LibRaise.getSoftcap(_raiseId) <= LibRaise.getRaised(_raiseId);
    }
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

import "./ILayerZeroUserApplicationConfig.sol";

interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
    // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
    // @param _dstChainId - the destination chain identifier
    // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
    // @param _payload - a custom bytes payload to send to the destination contract
    // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
    // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
    // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
    function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;

    // @notice used by the messaging library to publish verified payload
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source contract (as bytes) at the source chain
    // @param _dstAddress - the address on destination chain
    // @param _nonce - the unbound message ordering nonce
    // @param _gasLimit - the gas limit for external contract execution
    // @param _payload - verified payload to send to the destination contract
    function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;

    // @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);

    // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
    // @param _srcAddress - the source chain contract address
    function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);

    // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
    // @param _dstChainId - the destination chain identifier
    // @param _userApplication - the user app address on this EVM chain
    // @param _payload - the custom message to send over LayerZero
    // @param _payInZRO - if false, user app pays the protocol fee in native token
    // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
    function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);

    // @notice get this Endpoint's immutable source identifier
    function getChainId() external view returns (uint16);

    // @notice the interface to retry failed message on this Endpoint destination
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    // @param _payload - the payload to be retried
    function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;

    // @notice query if any STORED payload (message blocking) at the endpoint.
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    // @notice query if the _libraryAddress is valid for sending msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getSendLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the _libraryAddress is valid for receiving msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getReceiveLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the non-reentrancy guard for send() is on
    // @return true if the guard is on. false otherwise
    function isSendingPayload() external view returns (bool);

    // @notice query if the non-reentrancy guard for receive() is on
    // @return true if the guard is on. false otherwise
    function isReceivingPayload() external view returns (bool);

    // @notice get the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _userApplication - the contract address of the user application
    // @param _configType - type of configuration. every messaging library has its own convention.
    function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);

    // @notice get the send() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getSendVersion(address _userApplication) external view returns (uint16);

    // @notice get the lzReceive() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getReceiveVersion(address _userApplication) external view returns (uint16);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

    Raise encoder

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

/// @notice Raise encoder for EIP712 message hash.
library CrossChainEncoder {
    /// @dev Decode request data for raise registration.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.RegisterRaiseRequest struct
    function decodeRegisterRaisePayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.RegisterRaiseRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.RegisterRaiseRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode request data for raise finalization.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.FinishRaiseReceiverRequest struct
    function decodeFinishRaiseReceiverPayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.FinishRaiseReceiverRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.FinishRaiseReceiverRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode request data for unlocking new milestone.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.SubmitClaimingReceiverRequest struct
    function decodeUnlockMilestonePayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.UnlockMilestoneReceiverRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.UnlockMilestoneReceiverRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode request data for submitting claiming schedule.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.SubmitClaimingReceiverRequest struct
    function decodeSubmitClaimingPayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.SubmitClaimingReceiverRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.SubmitClaimingReceiverRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode request data for reschedule claimings.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.RescheduleClaimingReceiverRequest struct
    function decodeRescheduleClaimingsPayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.RescheduleClaimingReceiverRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.RescheduleClaimingReceiverRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode request data for submitting failed repair plan.
    /// @param _payload Byte-encoded payload
    /// @return Decoded RequestTypes.RejectRaiseReceiverRequest struct
    function decodeRejectRaisePayload(
        bytes calldata _payload
    ) internal pure returns (RequestTypes.RejectRaiseReceiverRequest memory, bytes32, uint8, bytes32, bytes32) {
        // return
        return abi.decode(_payload, (RequestTypes.RejectRaiseReceiverRequest, bytes32, uint8, bytes32, bytes32));
    }

    /// @dev Decode LayerZero data needed to send cross-chain message
    /// @param _crossChainData Encoded data to send
    /// @return Decoded RequestTypes.LayerZeroData struct
    function decodeLayerZeroData(bytes calldata _crossChainData) internal pure returns (CrossChainRequestTypes.LayerZeroData memory) {
        // decode and return
        return abi.decode(_crossChainData, (CrossChainRequestTypes.LayerZeroData));
    }

    /// @dev Decode AlephZero data needed to send cross-chain message
    /// @param _crossChainData Encoded data to send
    /// @return Decoded RequestTypes.AlephZeroData struct
    function decodeAlephZeroData(bytes calldata _crossChainData) internal pure returns (CrossChainRequestTypes.AlephZeroData memory) {
        // decode and return
        return abi.decode(_crossChainData, (CrossChainRequestTypes.AlephZeroData));
    }
}

File 35 of 46 : LayerZeroErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

    LayerZero errors
    
**************************************/

/// @dev All errors used in LayerZero cross chain communication
library LayerZeroErrors {
    // -----------------------------------------------------------------------
    //                              Send
    // -----------------------------------------------------------------------

    error UnsupportedLayerZeroChain(uint256 chainId); // 0x9e90d5d0
    error InvalidLayerZeroFee(); // 0x6142d241
    error InvalidNativeSent(uint256 value, uint256 fee); // 0x7166d3ed

    // -----------------------------------------------------------------------
    //                              Receive
    // -----------------------------------------------------------------------

    error ChainNotSupported(uint16 chainId); // 0xec2a2f0f
    error UntrustedRemote(bytes remote); // 0xd39d950e
    error NonceExpired(uint16 chainId, uint256 nativeChainId, bytes srcAddress, uint64 nonce); // 0x286d7ff2
    error UnsupportedFunction(uint256 chainId, bytes4 functionSelector); // 0x4f1e4a6d

    // -----------------------------------------------------------------------
    //                              Retry
    // -----------------------------------------------------------------------

    error MessageNotExists(uint16 srcChainId, bytes srcAddress, uint64 nonce); // 0x2e4f65fa
    error InvalidPayload(bytes32 storedPayload, bytes32 sentPayload); // 0xca89b547
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Library containing cross-chain EVM configuration
library LibCrossChainEvmConfiguration {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Cross-chain EVM configuration storage pointer.
    bytes32 internal constant CC_EVM_CONFIG_STORAGE_POSITION = keccak256("angelblock.cc.evm.config");

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

    /// @dev Cross-chain EVM configuration storage struct.
    /// @param fundraisings Mapping of native chain id to fundraising address on the given chain
    /// @param supportedFunctions Mapping of native chain id to supported 4 byte signature of function
    struct EvmConfigurationStorage {
        mapping(uint256 => address) fundraisings;
        mapping(uint256 => mapping(bytes4 => bool)) supportedFunctions;
    }

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

    /// @dev Function returning cross-chain evm configuration storage at storage pointer slot.
    /// @return ecs EvmConfigurationStorage struct instance at storage pointer position
    function evmConfigurationStorage() internal pure returns (EvmConfigurationStorage storage ecs) {
        // declare position
        bytes32 position = CC_EVM_CONFIG_STORAGE_POSITION;

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

        // explicit return
        return ecs;
    }

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

    /// @dev Diamond storage getter: Fundraising address.
    /// @param _nativeChainId ID of the chain
    /// @return Address of the fundraising
    function getFundraising(uint256 _nativeChainId) internal view returns (address) {
        // return
        return evmConfigurationStorage().fundraisings[_nativeChainId];
    }

    /// @dev Diamond storage getter: Supported function.
    /// @param _nativeChainId ID of the chain
    /// @param _supportedFunctionSelector Selector of function
    /// @return True if function is supported
    function getSupportedFunction(uint256 _nativeChainId, bytes4 _supportedFunctionSelector) internal view returns (bool) {
        // return
        return evmConfigurationStorage().supportedFunctions[_nativeChainId][_supportedFunctionSelector];
    }

    // -----------------------------------------------------------------------
    //                              Setters
    // -----------------------------------------------------------------------

    /// @dev Diamond storage setter: Fundraising address.
    /// @param _nativeChainId ID of the chain
    /// @param _fundraising Address of the fundraising
    function setFundraising(uint256 _nativeChainId, address _fundraising) internal {
        // set fundraising
        evmConfigurationStorage().fundraisings[_nativeChainId] = _fundraising;
    }

    /// @dev Diamond storage setter: Supported function.
    /// @param _nativeChainId ID of the chain
    /// @param _supportedFunctionSelector Selector of function
    /// @param _isSupported Boolean if function is supported
    function setSupportedFunction(uint256 _nativeChainId, bytes4 _supportedFunctionSelector, bool _isSupported) internal {
        // set supported function
        evmConfigurationStorage().supportedFunctions[_nativeChainId][_supportedFunctionSelector] = _isSupported;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Library containing investor funds info storage with getters and setters.
library LibLayerZeroBase {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev LayerZero base storage pointer.
    bytes32 internal constant CROSS_CHAIN_LAYER_ZERO_BASE_STORAGE_POSITION = keccak256("angelblock.cc.lz.base");

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

    /// @dev LayerZero base storage struct.
    /// @param crossChainEndpoint LayerZero endpoint address
    struct LayerZeroBaseStorage {
        address crossChainEndpoint;
    }

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

    /// @dev Function returning LayerZero base storage at storage pointer slot.
    /// @return lzbs LayerZeroBaseStorage struct instance at storage pointer position
    function layerZeroBaseStorage() internal pure returns (LayerZeroBaseStorage storage lzbs) {
        // declare position
        bytes32 position = CROSS_CHAIN_LAYER_ZERO_BASE_STORAGE_POSITION;

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

        // explicit return
        return lzbs;
    }

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

    /// @dev Diamond storage getter: LayerZero endpoint.
    /// @return LayerZero endpoint address
    function getCrossChainEndpoint() internal view returns (address) {
        return layerZeroBaseStorage().crossChainEndpoint;
    }

    /// @dev Diamond storage setter: LayerZero endpoint.
    /// @param _crossChainEndpoint LayerZero endpoint address
    function setCrossChainEndpoint(address _crossChainEndpoint) internal {
        layerZeroBaseStorage().crossChainEndpoint = _crossChainEndpoint;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

/// @notice Library containing necessary information for sending messages via LayerZero
library LibLayerZeroSender {
    // -----------------------------------------------------------------------
    //                              Storage pointer
    // -----------------------------------------------------------------------

    /// @dev Raise storage pointer.
    bytes32 internal constant LZ_SENDER_STORAGE_POSITION = keccak256("angelblock.cc.lz.sender");

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

    /// @dev LayerZero sender struct.
    /// @param refundAddress Refund address
    /// @param networks Mapping of native network id to LZ network id for supported networks
    struct LayerZeroSenderStorage {
        address refundAddress;
        mapping(uint256 => uint16) networks;
    }

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

    // diamond storage getter
    function lzSenderStorage() internal pure returns (LayerZeroSenderStorage storage lzs) {
        // declare position
        bytes32 position = LZ_SENDER_STORAGE_POSITION;

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

        // explicit return
        return lzs;
    }

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

    /// @dev Diamond storage getter: refund address.
    /// @return Refund address
    function getRefundAddress() internal view returns (address) {
        // return
        return lzSenderStorage().refundAddress;
    }

    /// @dev Diamond storage getter: network.
    /// @param _nativeChainId Native chain id for given network
    /// @return LayerZero network id
    function getNetwork(uint256 _nativeChainId) internal view returns (uint16) {
        // return
        return lzSenderStorage().networks[_nativeChainId];
    }

    /// @dev Diamond storage setter: refund address.
    /// @param _refundAddress New refund address for LayerZero calls
    function setRefundAddress(address _refundAddress) internal {
        lzSenderStorage().refundAddress = _refundAddress;
    }

    /// @dev Diamond storage setter: network.
    /// @param _nativeChainId Native chain id
    /// @param _layerZeroChainId Network chain id in LayerZero format
    function setNetwork(uint256 _nativeChainId, uint16 _layerZeroChainId) internal {
        lzSenderStorage().networks[_nativeChainId] = _layerZeroChainId;
    }
}

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

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

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

// Local imports - Structs
import { StorageTypes } from "../../../structs/StorageTypes.sol";

/// @dev Library containing base asset storage with getters and setters
library LibBaseAsset {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

    /// @dev Base asset storage pointer.
    bytes32 internal constant BASE_ASSET_STORAGE_POSITION = keccak256("angelblock.fundraising.baseAsset");

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

    /// @dev Base asset storage struct.
    /// @param base Mapping of raise id to base asset struct
    struct BaseAssetStorage {
        mapping(string => StorageTypes.BaseAsset) base;
    }

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

    /// @dev Function returning base asset storage at storage pointer slot.
    /// @return bas BaseAssetStorage struct instance at storage pointer position
    function baseAssetStorage() internal pure returns (BaseAssetStorage storage bas) {
        // declare position
        bytes32 position = BASE_ASSET_STORAGE_POSITION;

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

        // explicit return
        return bas;
    }

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

    /// @dev Diamond storage getter: Base asset address.
    /// @param _raiseId ID of the raise
    /// @return Address of the base asset
    function getAddress(string memory _raiseId) internal view returns (address) {
        // return
        return baseAssetStorage().base[_raiseId].base;
    }

    /// @dev Diamond storage getter: Base asset chain id.
    /// @param _raiseId ID of the raise
    /// @return Id of the chain
    function getChainId(string memory _raiseId) internal view returns (uint256) {
        // return
        return baseAssetStorage().base[_raiseId].chainId;
    }

    /// @dev Diamond storage setter: Base asset
    /// @param _raiseId ID of the raise
    /// @param _baseAsset StorageTypes.BaseAsset struct
    function setBaseAsset(string memory _raiseId, StorageTypes.BaseAsset memory _baseAsset) internal {
        // set base asset
        baseAssetStorage().base[_raiseId] = _baseAsset;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - security@angelblock.io

    maintainers:
    - marcin@angelblock.io
    - piotr@angelblock.io
    - mikolaj@angelblock.io
    - sebastian@angelblock.io

    contributors:
    - domenico@angelblock.io

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

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

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

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

// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroUserApplicationConfig {
    // @notice set the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _configType - type of configuration. every messaging library has its own convention.
    // @param _config - configuration in the bytes. can encode arbitrary content.
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;

    // @notice set the send() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setSendVersion(uint16 _version) external;

    // @notice set the lzReceive() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setReceiveVersion(uint16 _version) external;

    // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
    // @param _srcChainId - the chainId of the source chain
    // @param _srcAddress - the contract address of the source contract at the source chain
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

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

Settings
{
  "remappings": [
    "@openzeppelin/=src/fundraising/node_modules/@openzeppelin/",
    "ds-test/=src/fundraising/node_modules/ds-test/src/",
    "forge-std/=src/fundraising/node_modules/forge-std/src/",
    "layer-zero/=src/fundraising/node_modules/layer-zero/",
    "ethereum-xcm-v3/=src/fundraising/node_modules/ethereum-xcm-v3/",
    "base58-solidity/=src/fundraising/node_modules/base58-solidity/",
    "murky/=src/fundraising/node_modules/murky/",
    "stringutils/=node_modules/stringutils/src/",
    "permit2/=node_modules/permit2/src/",
    "hardhat/=src/fundraising/node_modules/hardhat/",
    "openzeppelin-contracts/=src/fundraising/node_modules/murky/lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200,
    "details": {
      "yul": true
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"string","name":"requestClaimingScheduleId","type":"string"},{"internalType":"string","name":"storageClaimingScheduleId","type":"string"}],"name":"CannotChangeClaimingId","type":"error"},{"inputs":[{"internalType":"string","name":"claimingScheduleId","type":"string"},{"internalType":"string","name":"requestMilestoneId","type":"string"},{"internalType":"string","name":"storageMilestoneId","type":"string"}],"name":"CannotChangeMilestoneId","type":"error"},{"inputs":[{"internalType":"string","name":"claimingScheduleId","type":"string"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"}],"name":"CannotChangePastClaimingSchedule","type":"error"},{"inputs":[],"name":"CannotDeletePastSchedule","type":"error"},{"inputs":[],"name":"EmptyClaimingSchedules","type":"error"},{"inputs":[],"name":"EmptyPayload","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":[],"name":"InvalidLayerZeroFee","type":"error"},{"inputs":[{"internalType":"bytes32","name":"verify","type":"bytes32"},{"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"InvalidMessage","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"InvalidNativeSent","type":"error"},{"inputs":[{"internalType":"string","name":"milestoneId","type":"string"}],"name":"MilestoneNotExists","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceExpired","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"RequestExpired","type":"error"},{"inputs":[{"internalType":"string","name":"milestoneId","type":"string"},{"internalType":"uint256","name":"milestoneShare","type":"uint256"},{"internalType":"uint256","name":"rescheduledShares","type":"uint256"}],"name":"RescheduledSharesMustEqualMilestoneShare","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bytes4","name":"functionSelector","type":"bytes4"}],"name":"UnsupportedFunction","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"UnsupportedLayerZeroChain","type":"error"},{"inputs":[],"name":"UnsupportedProvider","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"raiseId","type":"string"},{"indexed":false,"internalType":"string","name":"milestoneId","type":"string"},{"components":[{"internalType":"string","name":"claimingId","type":"string"},{"internalType":"string","name":"milestoneId","type":"string"},{"internalType":"uint256","name":"partialShare","type":"uint256"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"}],"indexed":false,"internalType":"struct StorageTypes.ClaimingSchedule[]","name":"claimingSchedules","type":"tuple[]"}],"name":"ClaimingsRescheduled","type":"event"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"string","name":"milestoneId","type":"string"},{"components":[{"internalType":"string","name":"claimingId","type":"string"},{"internalType":"string","name":"milestoneId","type":"string"},{"internalType":"uint256","name":"partialShare","type":"uint256"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"}],"internalType":"struct StorageTypes.ClaimingSchedule[]","name":"claimingSchedules","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.RescheduleClaimingRequest","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"},{"components":[{"internalType":"enum EnumTypes.CrossChainProvider","name":"provider","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct CrossChainRequestTypes.CrossChainData","name":"_crossChainData","type":"tuple"}],"name":"rescheduleClaimings","outputs":[],"stateMutability":"payable","type":"function"}]

60808060405234601557611bfa908161001b8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c63d0c86e3e1461002857600080fd5b60c0366003190112611170576001600160401b03600435116111705760c0600435360360031901126111705760ff6044351660443503611170576001600160401b0360a4351161117057604060a435360360031901126111705761009136606460043501611231565b6040818101513360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020529190912054811115611150575060208101518042116111305750516001600160a01b03163303611118576101416101496100ff60048035018061127b565b61011660246004949394350160043560040161127b565b949061013961012f6044600435016004356004016112ad565b96909436916112e2565b9536916112e2565b92369161135d565b61015382846116b9565b90156110f65781519384156110e45761016b906114e5565b80548210156110d057855260208520600390910201600201549061018e8361152a565b54938594865b81811061108b575085821061107a579190869287925b828410610e755750505050818103610e40575050506040516101cb81611173565b600435600401356001600160401b038111610b2e576101f190600436918135010161133f565b8152602460043501356001600160401b038111610b2e5761021990600436918135010161133f565b6020820152604460043501356001600160401b038111610b2e576004350136602382011215610b2e5761025690369060246004820135910161135d565b604082015261026a36606460043501611231565b806060830152604080519160018060a01b03815116602084015260208101518284015201516060820152606081526102a181611173565b6040820151906040519182604081019160208083015280518093526060820192602060608260051b85010192019389905b828210610de1575050506102f19250601f198282030182520383611210565b60208351818151910120930151602081519101209160208151910120906020815191012091604051937f9ced5b44a2b3af08ce74be3ad81d6ad5addaf8756d8e783d649054a5c4a8ed04602086015260408501526060840152608083015260a082015260a08152610361816111bf565b7446756e6472616973696e673a4d696c6573746f6e6560581b6020604051610388816111da565b601581520152640323a323a360dc1b60206040516103a5816111da565b6005815201526020815191012060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f8b7bf121a4925c079594e9c05e9a8a973e9640c48e4905971b36414abc2cb56760408201527fca700de3093aaca17d95eed97350d2947040c19695a3b3744da22c72e3050f8b60608201524660808201523060a082015260a08152610442816111bf565b5190209060405190602082019261190160f01b8452602283015260428201526042815261046e81611173565b5190206024358103610dc1575061049a610492608435606435604435602435611a28565b919091611aaa565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b03169081845260205260ff60408420541615610da9575061053e61051a60246004350160043560040161127b565b6101416105346044600495949535016004356004016112ad565b94909236916112e2565b9081519261054b8261152a565b54908181810311610d9557808203610c15575b50506105699061152a565b54808311610b48575b50503360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a4013591505560016105de60206105cb6105c460048035018061127b565b36916112e2565b8160405193828580945193849201611473565b7f9d245c8905a41e40b5d7d8d225eabcef70dc5100963a988bf7a9d7b6a0cd4a7481830152810103019020015490468203610751575b905061062460048035018061127b565b61066a61067861064160246004969596350160043560040161127b565b6106556044600435016004356004016112ad565b94909760405196606088526060880191611421565b918583036020870152611421565b938285036040840152818552602085019160208160051b870101958286915b8383106106c857877f65cebc1b121235e152b12f6f8be0a2c605c91bcbd76e6abab932c553ffc38379888b0389a180f35b909192939497601f198282030189528535607e198436030181121561074d576020600192858293019060608061072b6107126107048680611442565b608087526080870191611421565b61071e87870187611442565b9086830389880152611421565b9360408101356040850152013591015297019901930191909793929497610697565b8880fd5b60a435600401356003811015610b4457600103610b325761077c602460a4350160a43560040161127b565b826040809593955161078d816111a4565b60608152606060208201520152830192602081850312610b2a578035906001600160401b038211610b2e5701606081850312610b2a57604051936107d0856111a4565b81356001600160401b038111610b2657816107ec91840161133f565b855260208201356001600160401b038111610b26578291610810916040940161133f565b60208601520135604084015282515115610b14578082527fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3ea60205261ffff60408320541615610afc57825180516020909101516001600160e01b03198116919060048210610adc575b50508183527ff6d13f7412e547870332b41e12245afcb7d558e215b48ce696ab1c680af6a774602052604083209063ffffffff60e01b169081845260205260ff60408420541615610abe5750604083015115610aac576040830151803410610a8e575081527fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3ea60209081526040808320547fe76a1a8cc2a93ef95736d523edd260dabc1e17bd1543fba2a8f0c977d6dc8559547ff6d13f7412e547870332b41e12245afcb7d558e215b48ce696ab1c680af6a7738452828520547fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3e9549351606091821b6bffffffffffffffffffffffff19169581019590955230901b6034850152602884526001600160a01b039081169392169061ffff166109ba836111a4565b60408601519160208751970151853b15610a8a5791610a3687969492610a079694610a196040519b8c998a98899762c5803160e81b8952600489015260c0602489015260c4880190611496565b86810360031901604488015290611496565b9160648501528860848501526003198483030160a4850152611496565b03925af18015610a7d57610a4f575b61066a9150610614565b6001600160401b038211610a695761066a91604052610a45565b634e487b7160e01b81526041600452602490fd5b50604051903d90823e3d90fd5b8680fd5b60449060405190637166d3ed60e01b82523460048301526024820152fd5b604051636142d24160e01b8152600490fd5b6044925060405191634f1e4a6d60e01b835260048301526024820152fd5b6001600160e01b031960049290920360031b82901b161690503880610879565b602490604051906309e90d5d60e41b82526004820152fd5b604051630b8fc7cd60e21b8152600490fd5b8480fd5b8280fd5b8380fd5b604051637f4d001d60e01b8152600490fd5b5080fd5b8281101561057257610b5a81836114bb565b51610b68602082015161152a565b81519080549068010000000000000000821015610c015790610b8f916001820181556117b7565b610bed576001939291610ba1916117e6565b60036060610bbc610bb5602085015161156f565b84516115b4565b92610bc88151856117e6565b610bd860208201518786016117e6565b60408101516002850155015191015501610b48565b634e487b7160e01b87526004879052602487fd5b634e487b7160e01b88526041600452602488fd5b855b8183038110610c26575061055e565b610c2f8461152a565b54610c398561152a565b6000199182810191908211610d8157610c5b91610c55916117b7565b50611614565b90610c658661152a565b9081548015610d6d57610c7a828201846117b7565b610d5957908b82610c9160019897969594546115da565b80610d1d575b50505001905560038987610d0d60405194610cb186611173565b604051610cbd816111f5565b8481528652610d04610cfc60405192610cd5846111f5565b86845260208901938452610cf660408a019688885260608b0198895261156f565b906115b4565b9651876117e6565b518786016117e6565b5160028401555191015501610c17565b82601f8083118b14610d3657505050555b8b3880610c97565b83825260208220939192610d52910160051c84018b85016117cf565b5555610d2e565b634e487b7160e01b8c5260048c905260248cfd5b634e487b7160e01b8b52603160045260248bfd5b634e487b7160e01b8a52601160045260248afd5b634e487b7160e01b86526011600452602486fd5b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b91935091602080600192605f198a8203018552875190606080610e20610e106080865190808752860190611496565b8686015185820388870152611496565b9360408101516040850152015191015296019201920186939194926102d2565b604051632207376360e21b81526060600482015293508392610e66906064850190611496565b91602484015260448301520390fd5b90919293610e8385836114bb565b51838610610eb9575b604001518101809111610ea557936001019291906101aa565b634e487b7160e01b89526011600452602489fd5b610ec386896118eb565b602082018051604051610ef360208281610ee68183019687815193849201611473565b8101038084520182611210565b51902060208301908151604051610f1a60208281610ee68183019687815193849201611473565b519020036110235750504260608201511115610f37575b50610e8c565b8151604051610f5660208281610ee68183019687815193849201611473565b5190208151604051610f7860208281610ee68183019687815193849201611473565b51902003610fe257604081015160408301511490811591610fcf575b50610f9f5738610f31565b610fc59051604051918291633090512760e01b8352604060048401526044830190611496565b4260248301520390fd5b6060915001516060820151141538610f94565b61101f61100d925191516040519384936338f5a4a360e21b8552604060048601526044850190611496565b83810360031901602485015290611496565b0390fd5b9061101f61105692611068865193519151916040519586956301a7356160e71b8752606060048801526064870190611496565b85810360031901602487015290611496565b83810360031901604485015290611496565b60405162f3e6cf60e71b8152600490fd5b42606061109883896118eb565b015111156110a9575b600101610194565b9560001981146110bc57600101956110a1565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b86526032600452602486fd5b60405163cc393bbb60e01b8152600490fd5b60405163134d7e2360e11b8152602060048201528061101f6024820186611496565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048201526024810191909152604490fd5b604051632b6069a960e01b81523360048201526024810191909152604490fd5b80fd5b608081019081106001600160401b0382111761118e57604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b0382111761118e57604052565b60c081019081106001600160401b0382111761118e57604052565b604081019081106001600160401b0382111761118e57604052565b602081019081106001600160401b0382111761118e57604052565b90601f801991011681019081106001600160401b0382111761118e57604052565b919082606091031261127657604051611249816111a4565b91829080356001600160a01b03811681036112765760409182918452602081013560208501520135910152565b600080fd5b903590601e198136030182121561127657018035906001600160401b0382116112765760200191813603831361127657565b903590601e198136030182121561127657018035906001600160401b03821161127657602001918160051b3603831361127657565b9291926001600160401b03821161118e576040519161130b601f8201601f191660200184611210565b829481845281830111611276578281602093846000960137010152565b6001600160401b03811161118e5760051b60200190565b9080601f830112156112765781602061135a933591016112e2565b90565b92919061136981611328565b9160409161137a6040519485611210565b839581855260208095019160051b8101938385116112765781925b8584106113a55750505050505050565b6001600160401b038435818111611276578401916080838803126112765783516113ce81611173565b833583811161127657886113e391860161133f565b8152898401359283116112765783611400898c969587960161133f565b84830152858101358683015260608091013590820152815201930192611395565b908060209392818452848401376000828201840152601f01601f1916010190565b9035601e19823603018112156112765701602081359101916001600160401b03821161127657813603831361127657565b60005b8381106114865750506000910152565b8181015183820152602001611476565b906020916114af81518092818552858086019101611473565b601f01601f1916010190565b80518210156114cf5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b60206114fe918160405193828580945193849201611473565b81017f863e98553d473a330f13570b828238eab81d26cbf5ccc0856a5fcff7a8742b5681520301902090565b6020611543918160405193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a81081520301902090565b6020611588918160405193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a81181520301902090565b6020906115ce928260405194838680955193849201611473565b82019081520301902090565b90600182811c9216801561160a575b60208310146115f457565b634e487b7160e01b600052602260045260246000fd5b91607f16916115e9565b90604051918260008254611627816115da565b908184526020946001916001811690816000146116975750600114611658575b50505061165692500383611210565b565b600090815285812095935091905b81831061167f5750506116569350820101388080611647565b85548884018501529485019487945091830191611666565b9250505061165694925060ff191682840152151560051b820101388080611647565b6116c5909291926114e5565b918254906116d282611328565b916040926116e36040519182611210565b81815260209182820160009788528388208489925b84841061177a575050505050855b81518110156117715761171981836114bb565b51518551611736858281610ee68183019687815193849201611473565b519020855184810190611755868281610ee68b87815193849201611473565b5190201461176557600101611706565b95505050505060019190565b50505050508190565b6001916003918a5161178b816111a4565b61179486611614565b8152848601548382015260028601548c82015281520192019201919085906116f8565b80548210156114cf5760005260206000200190600090565b8181106117da575050565b600081556001016117cf565b91909182516001600160401b03811161118e5761180382546115da565b601f81116118ae575b50602080601f831160011461184957508192939460009261183e575b50508160011b916000199060031b1c1916179055565b015190503880611828565b90601f19831695846000526020600020926000905b8882106118965750508360019596971061187d575b505050811b019055565b015160001960f88460031b161c19169055388080611873565b8060018596829496860151815501950193019061185e565b6118db90836000526020600020601f840160051c810191602085106118e1575b601f0160051c01906117cf565b3861180c565b90915081906118ce565b91906040606061196582519361190085611173565b8285526020948386820152600093818587819401520152611937856119248961156f565b9881875193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a8108152030190206117b7565b5090825191818154611976816115da565b92600191808316908115611a0c57506001146119da575b505050509281848296976003965203019020908051936119ac85611173565b6119b583611614565b85526119c360018401611614565b908501526002820154908401520154606082015290565b909180939450528582205b8383106119fb575050508101818660038661198d565b8054858401529186019181016119e5565b60ff19168752505050508015150282019050818660038661198d565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311611a9e5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15610a7d5781516001600160a01b03811615611a98579190565b50600190565b50505050600090600390565b6005811015611bae5780611abb5750565b60018103611b085760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b60028103611b555760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b600314611b5e57565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212200e56bb78a112895e0c1222678d8860b2a02633cc4aaed9296fe037c984f03c2764736f6c63430008190033

Deployed Bytecode

0x6080604052600436101561001257600080fd5b6000803560e01c63d0c86e3e1461002857600080fd5b60c0366003190112611170576001600160401b03600435116111705760c0600435360360031901126111705760ff6044351660443503611170576001600160401b0360a4351161117057604060a435360360031901126111705761009136606460043501611231565b6040818101513360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020529190912054811115611150575060208101518042116111305750516001600160a01b03163303611118576101416101496100ff60048035018061127b565b61011660246004949394350160043560040161127b565b949061013961012f6044600435016004356004016112ad565b96909436916112e2565b9536916112e2565b92369161135d565b61015382846116b9565b90156110f65781519384156110e45761016b906114e5565b80548210156110d057855260208520600390910201600201549061018e8361152a565b54938594865b81811061108b575085821061107a579190869287925b828410610e755750505050818103610e40575050506040516101cb81611173565b600435600401356001600160401b038111610b2e576101f190600436918135010161133f565b8152602460043501356001600160401b038111610b2e5761021990600436918135010161133f565b6020820152604460043501356001600160401b038111610b2e576004350136602382011215610b2e5761025690369060246004820135910161135d565b604082015261026a36606460043501611231565b806060830152604080519160018060a01b03815116602084015260208101518284015201516060820152606081526102a181611173565b6040820151906040519182604081019160208083015280518093526060820192602060608260051b85010192019389905b828210610de1575050506102f19250601f198282030182520383611210565b60208351818151910120930151602081519101209160208151910120906020815191012091604051937f9ced5b44a2b3af08ce74be3ad81d6ad5addaf8756d8e783d649054a5c4a8ed04602086015260408501526060840152608083015260a082015260a08152610361816111bf565b7446756e6472616973696e673a4d696c6573746f6e6560581b6020604051610388816111da565b601581520152640323a323a360dc1b60206040516103a5816111da565b6005815201526020815191012060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f8b7bf121a4925c079594e9c05e9a8a973e9640c48e4905971b36414abc2cb56760408201527fca700de3093aaca17d95eed97350d2947040c19695a3b3744da22c72e3050f8b60608201524660808201523060a082015260a08152610442816111bf565b5190209060405190602082019261190160f01b8452602283015260428201526042815261046e81611173565b5190206024358103610dc1575061049a610492608435606435604435602435611a28565b919091611aaa565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b03169081845260205260ff60408420541615610da9575061053e61051a60246004350160043560040161127b565b6101416105346044600495949535016004356004016112ad565b94909236916112e2565b9081519261054b8261152a565b54908181810311610d9557808203610c15575b50506105699061152a565b54808311610b48575b50503360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a4013591505560016105de60206105cb6105c460048035018061127b565b36916112e2565b8160405193828580945193849201611473565b7f9d245c8905a41e40b5d7d8d225eabcef70dc5100963a988bf7a9d7b6a0cd4a7481830152810103019020015490468203610751575b905061062460048035018061127b565b61066a61067861064160246004969596350160043560040161127b565b6106556044600435016004356004016112ad565b94909760405196606088526060880191611421565b918583036020870152611421565b938285036040840152818552602085019160208160051b870101958286915b8383106106c857877f65cebc1b121235e152b12f6f8be0a2c605c91bcbd76e6abab932c553ffc38379888b0389a180f35b909192939497601f198282030189528535607e198436030181121561074d576020600192858293019060608061072b6107126107048680611442565b608087526080870191611421565b61071e87870187611442565b9086830389880152611421565b9360408101356040850152013591015297019901930191909793929497610697565b8880fd5b60a435600401356003811015610b4457600103610b325761077c602460a4350160a43560040161127b565b826040809593955161078d816111a4565b60608152606060208201520152830192602081850312610b2a578035906001600160401b038211610b2e5701606081850312610b2a57604051936107d0856111a4565b81356001600160401b038111610b2657816107ec91840161133f565b855260208201356001600160401b038111610b26578291610810916040940161133f565b60208601520135604084015282515115610b14578082527fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3ea60205261ffff60408320541615610afc57825180516020909101516001600160e01b03198116919060048210610adc575b50508183527ff6d13f7412e547870332b41e12245afcb7d558e215b48ce696ab1c680af6a774602052604083209063ffffffff60e01b169081845260205260ff60408420541615610abe5750604083015115610aac576040830151803410610a8e575081527fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3ea60209081526040808320547fe76a1a8cc2a93ef95736d523edd260dabc1e17bd1543fba2a8f0c977d6dc8559547ff6d13f7412e547870332b41e12245afcb7d558e215b48ce696ab1c680af6a7738452828520547fee52373cb78aacd3e095233a810a0da0ac079fc3c3fc7c96df1720037e08d3e9549351606091821b6bffffffffffffffffffffffff19169581019590955230901b6034850152602884526001600160a01b039081169392169061ffff166109ba836111a4565b60408601519160208751970151853b15610a8a5791610a3687969492610a079694610a196040519b8c998a98899762c5803160e81b8952600489015260c0602489015260c4880190611496565b86810360031901604488015290611496565b9160648501528860848501526003198483030160a4850152611496565b03925af18015610a7d57610a4f575b61066a9150610614565b6001600160401b038211610a695761066a91604052610a45565b634e487b7160e01b81526041600452602490fd5b50604051903d90823e3d90fd5b8680fd5b60449060405190637166d3ed60e01b82523460048301526024820152fd5b604051636142d24160e01b8152600490fd5b6044925060405191634f1e4a6d60e01b835260048301526024820152fd5b6001600160e01b031960049290920360031b82901b161690503880610879565b602490604051906309e90d5d60e41b82526004820152fd5b604051630b8fc7cd60e21b8152600490fd5b8480fd5b8280fd5b8380fd5b604051637f4d001d60e01b8152600490fd5b5080fd5b8281101561057257610b5a81836114bb565b51610b68602082015161152a565b81519080549068010000000000000000821015610c015790610b8f916001820181556117b7565b610bed576001939291610ba1916117e6565b60036060610bbc610bb5602085015161156f565b84516115b4565b92610bc88151856117e6565b610bd860208201518786016117e6565b60408101516002850155015191015501610b48565b634e487b7160e01b87526004879052602487fd5b634e487b7160e01b88526041600452602488fd5b855b8183038110610c26575061055e565b610c2f8461152a565b54610c398561152a565b6000199182810191908211610d8157610c5b91610c55916117b7565b50611614565b90610c658661152a565b9081548015610d6d57610c7a828201846117b7565b610d5957908b82610c9160019897969594546115da565b80610d1d575b50505001905560038987610d0d60405194610cb186611173565b604051610cbd816111f5565b8481528652610d04610cfc60405192610cd5846111f5565b86845260208901938452610cf660408a019688885260608b0198895261156f565b906115b4565b9651876117e6565b518786016117e6565b5160028401555191015501610c17565b82601f8083118b14610d3657505050555b8b3880610c97565b83825260208220939192610d52910160051c84018b85016117cf565b5555610d2e565b634e487b7160e01b8c5260048c905260248cfd5b634e487b7160e01b8b52603160045260248bfd5b634e487b7160e01b8a52601160045260248afd5b634e487b7160e01b86526011600452602486fd5b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b91935091602080600192605f198a8203018552875190606080610e20610e106080865190808752860190611496565b8686015185820388870152611496565b9360408101516040850152015191015296019201920186939194926102d2565b604051632207376360e21b81526060600482015293508392610e66906064850190611496565b91602484015260448301520390fd5b90919293610e8385836114bb565b51838610610eb9575b604001518101809111610ea557936001019291906101aa565b634e487b7160e01b89526011600452602489fd5b610ec386896118eb565b602082018051604051610ef360208281610ee68183019687815193849201611473565b8101038084520182611210565b51902060208301908151604051610f1a60208281610ee68183019687815193849201611473565b519020036110235750504260608201511115610f37575b50610e8c565b8151604051610f5660208281610ee68183019687815193849201611473565b5190208151604051610f7860208281610ee68183019687815193849201611473565b51902003610fe257604081015160408301511490811591610fcf575b50610f9f5738610f31565b610fc59051604051918291633090512760e01b8352604060048401526044830190611496565b4260248301520390fd5b6060915001516060820151141538610f94565b61101f61100d925191516040519384936338f5a4a360e21b8552604060048601526044850190611496565b83810360031901602485015290611496565b0390fd5b9061101f61105692611068865193519151916040519586956301a7356160e71b8752606060048801526064870190611496565b85810360031901602487015290611496565b83810360031901604485015290611496565b60405162f3e6cf60e71b8152600490fd5b42606061109883896118eb565b015111156110a9575b600101610194565b9560001981146110bc57600101956110a1565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b86526032600452602486fd5b60405163cc393bbb60e01b8152600490fd5b60405163134d7e2360e11b8152602060048201528061101f6024820186611496565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048201526024810191909152604490fd5b604051632b6069a960e01b81523360048201526024810191909152604490fd5b80fd5b608081019081106001600160401b0382111761118e57604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b0382111761118e57604052565b60c081019081106001600160401b0382111761118e57604052565b604081019081106001600160401b0382111761118e57604052565b602081019081106001600160401b0382111761118e57604052565b90601f801991011681019081106001600160401b0382111761118e57604052565b919082606091031261127657604051611249816111a4565b91829080356001600160a01b03811681036112765760409182918452602081013560208501520135910152565b600080fd5b903590601e198136030182121561127657018035906001600160401b0382116112765760200191813603831361127657565b903590601e198136030182121561127657018035906001600160401b03821161127657602001918160051b3603831361127657565b9291926001600160401b03821161118e576040519161130b601f8201601f191660200184611210565b829481845281830111611276578281602093846000960137010152565b6001600160401b03811161118e5760051b60200190565b9080601f830112156112765781602061135a933591016112e2565b90565b92919061136981611328565b9160409161137a6040519485611210565b839581855260208095019160051b8101938385116112765781925b8584106113a55750505050505050565b6001600160401b038435818111611276578401916080838803126112765783516113ce81611173565b833583811161127657886113e391860161133f565b8152898401359283116112765783611400898c969587960161133f565b84830152858101358683015260608091013590820152815201930192611395565b908060209392818452848401376000828201840152601f01601f1916010190565b9035601e19823603018112156112765701602081359101916001600160401b03821161127657813603831361127657565b60005b8381106114865750506000910152565b8181015183820152602001611476565b906020916114af81518092818552858086019101611473565b601f01601f1916010190565b80518210156114cf5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b60206114fe918160405193828580945193849201611473565b81017f863e98553d473a330f13570b828238eab81d26cbf5ccc0856a5fcff7a8742b5681520301902090565b6020611543918160405193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a81081520301902090565b6020611588918160405193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a81181520301902090565b6020906115ce928260405194838680955193849201611473565b82019081520301902090565b90600182811c9216801561160a575b60208310146115f457565b634e487b7160e01b600052602260045260246000fd5b91607f16916115e9565b90604051918260008254611627816115da565b908184526020946001916001811690816000146116975750600114611658575b50505061165692500383611210565b565b600090815285812095935091905b81831061167f5750506116569350820101388080611647565b85548884018501529485019487945091830191611666565b9250505061165694925060ff191682840152151560051b820101388080611647565b6116c5909291926114e5565b918254906116d282611328565b916040926116e36040519182611210565b81815260209182820160009788528388208489925b84841061177a575050505050855b81518110156117715761171981836114bb565b51518551611736858281610ee68183019687815193849201611473565b519020855184810190611755868281610ee68b87815193849201611473565b5190201461176557600101611706565b95505050505060019190565b50505050508190565b6001916003918a5161178b816111a4565b61179486611614565b8152848601548382015260028601548c82015281520192019201919085906116f8565b80548210156114cf5760005260206000200190600090565b8181106117da575050565b600081556001016117cf565b91909182516001600160401b03811161118e5761180382546115da565b601f81116118ae575b50602080601f831160011461184957508192939460009261183e575b50508160011b916000199060031b1c1916179055565b015190503880611828565b90601f19831695846000526020600020926000905b8882106118965750508360019596971061187d575b505050811b019055565b015160001960f88460031b161c19169055388080611873565b8060018596829496860151815501950193019061185e565b6118db90836000526020600020601f840160051c810191602085106118e1575b601f0160051c01906117cf565b3861180c565b90915081906118ce565b91906040606061196582519361190085611173565b8285526020948386820152600093818587819401520152611937856119248961156f565b9881875193828580945193849201611473565b81017f67c705175a85517628ec6756607a9a1ba0ec7dfd34fa758c0a03f49e7663a8108152030190206117b7565b5090825191818154611976816115da565b92600191808316908115611a0c57506001146119da575b505050509281848296976003965203019020908051936119ac85611173565b6119b583611614565b85526119c360018401611614565b908501526002820154908401520154606082015290565b909180939450528582205b8383106119fb575050508101818660038661198d565b8054858401529186019181016119e5565b60ff19168752505050508015150282019050818660038661198d565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311611a9e5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa15610a7d5781516001600160a01b03811615611a98579190565b50600190565b50505050600090600390565b6005811015611bae5780611abb5750565b60018103611b085760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b60028103611b555760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b600314611b5e57565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212200e56bb78a112895e0c1222678d8860b2a02633cc4aaed9296fe037c984f03c2764736f6c63430008190033

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

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