ETH Price: $2,678.34 (-2.20%)

Contract

0xd8562f0a7546065FCbf30e744B7A233BAB56e46D
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
InvestorRaiseFacet

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 41 : InvestorRaiseFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// Local imports - constants, encoders, events, errors, structs
import { RaiseConstants } from "../../constants/RaiseConstants.sol";
import { RaiseEncoder } from "../../encoders/RaiseEncoder.sol";
import { RaiseEvents } from "../../events/RaiseEvents.sol";
import { RequestTypes } from "../../structs/RequestTypes.sol";

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

// Local imports - services
import { InvestorService } from "../../libraries/services/raise/InvestorService.sol";
import { SignatureService } from "../../libraries/services/utils/SignatureService.sol";
import { BadgeService } from "../../libraries/services/assets/BadgeService.sol";
import { BaseAssetService } from "../../libraries/services/assets/BaseAssetService.sol";

// Local imports - interfaces
import { IInvestorRaiseFacet } from "../../interfaces/raise/IInvestorRaiseFacet.sol";

contract InvestorRaiseFacet is IInvestorRaiseFacet {
    // -----------------------------------------------------------------------
    //                              Invest
    // -----------------------------------------------------------------------

    /// @dev Invest in a raise and mint ERC1155 equity badge for it.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: NewInvestment(address sender, string raiseId, uint256 investment, bytes32 message, uint256 data).
    /// @param _request InvestRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function invest(RequestTypes.InvestRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external {
        // tx.members
        address sender_ = msg.sender;

        // request.members
        string memory raiseId_ = _request.raiseId;
        uint256 investment_ = _request.investment;

        // validate request
        InvestorService.validateInvestRequest(_request);

        // eip712 encoding
        bytes memory encodedMsg_ = RaiseEncoder.encodeInvest(_request);

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

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

        // collect investment
        BaseAssetService.collectBaseAsset(raiseId_, sender_, _request.investment);

        // equity id
        uint256 badgeId_ = BadgeService.convertRaiseToBadge(raiseId_);

        // increase nonce
        LibNonce.setNonce(sender_, _request.base.nonce);

        // mint badge
        BadgeService.mintBadge(raiseId_, badgeId_, investment_);

        // storage
        InvestorService.saveInvestment(raiseId_, investment_);

        // event
        emit RaiseEvents.NewInvestment(sender_, raiseId_, investment_, _message, badgeId_);
    }

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

    /// @dev Refund investment to investor, if raise was not successful (softcap hasn't been reached).
    /// @dev Validation: Validate raise, sender and ability to refund.
    /// @dev Events: InvestmentRefunded(address sender, string raiseId, uint256 amount).
    /// @param _raiseId ID of raise
    function refundInvestment(string memory _raiseId) external {
        // tx.members
        address sender_ = msg.sender;

        // validate request
        InvestorService.validateRefundInvestment(_raiseId);

        // refund base asset
        uint256 investment_ = BaseAssetService.refundBaseAsset(_raiseId, sender_);

        // emit
        emit RaiseEvents.InvestmentRefunded(sender_, _raiseId, investment_);
    }
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]
    
**************************************/

/// @notice Constants used in raise facet and raise encoder.
library RaiseConstants {
    // -----------------------------------------------------------------------
    //                              Constants
    // -----------------------------------------------------------------------

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

    /// @dev Typehash for create raise by startup
    bytes32 internal constant STARTUP_CREATE_RAISE_TYPEHASH =
        keccak256("CreateRaiseRequest(bytes raise,bytes raiseDetails,bytes erc20Asset,bytes baseAsset,bytes base,string badgeUri)");
    /// @dev Typehash for set token by an early stage startup
    bytes32 internal constant STARTUP_SET_TOKEN_TYPEHASH = keccak256("SetTokenRequest(string raiseId,address token,bytes base)");
    /// @dev Typehash for investing into raise by investor
    bytes32 internal constant INVESTOR_INVEST_TYPEHASH =
        keccak256("InvestRequest(string raiseId,uint256 investment,uint256 maxTicketSize,bytes base)");
    /// @dev Typehash for register raise
    bytes32 internal constant STARTUP_REGISTER_RAISE_TYPEHASH =
        keccak256("RegisterRaiseRequest(bytes raise,bytes raiseDetails,bytes erc20Asset,bytes baseAsset,bytes crossChainBase)");
    /// @dev Typehash for finish raise
    bytes32 internal constant STARTUP_FINISH_RAISE_TYPEHASH =
        keccak256("FinishRaiseRequest(string raiseId,uint256 raised,bytes32 merkleTreeRoot,bytes base)");
    /// @dev Typehash for finish raise in receiver
    bytes32 internal constant STARTUP_FINISH_RAISE_RECEIVER_TYPEHASH =
        keccak256("FinishRaiseReceiverRequest(string raiseId,uint256 raised,bytes32 merkleTreeRoot,bytes crossChainBase)");
}

File 3 of 41 : RaiseEncoder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// local imports
import { RaiseConstants } from "../constants/RaiseConstants.sol";
import { RequestTypes } from "../structs/RequestTypes.sol";

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

    Raise encoder

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

/// @notice Raise encoder for EIP712 message hash.
library RaiseEncoder {
    /// @dev Encode create raise request data.
    /// @param _request RequestTypes.CreateRaiseRequest struct
    function encodeCreateRaise(RequestTypes.CreateRaiseRequest memory _request) internal pure returns (bytes memory) {
        // encode request elements
        bytes memory encodedRaise_ = abi.encode(_request.raise);
        bytes memory encodedRaiseDetails_ = abi.encode(_request.raiseDetails);
        bytes memory encodedERC20Asset_ = abi.encode(_request.erc20Asset);
        bytes memory encodedBaseAsset_ = abi.encode(_request.baseAsset);
        bytes memory encodedBase_ = abi.encode(_request.base);

        // return encoded data
        return
            abi.encode(
                RaiseConstants.STARTUP_CREATE_RAISE_TYPEHASH,
                keccak256(encodedRaise_),
                keccak256(encodedRaiseDetails_),
                keccak256(encodedERC20Asset_),
                keccak256(encodedBaseAsset_),
                keccak256(encodedBase_),
                keccak256(bytes(_request.badgeUri))
            );
    }

    /// @dev Encode register raise request.
    /// @param _request RequestTypes.RegisterRaiseRequest struct
    /// @return Encoded message.
    function encodeRegisterRaise(RequestTypes.RegisterRaiseRequest memory _request) internal pure returns (bytes memory) {
        bytes memory encodedRaise_ = abi.encode(_request.raise);
        bytes memory encodedRaiseDetails_ = abi.encode(_request.raiseDetails);
        bytes memory encodedERC20Asset_ = abi.encode(_request.erc20Asset);
        bytes memory encodedBaseAsset_ = abi.encode(_request.baseAsset);
        bytes memory encodedBase_ = abi.encode(_request.crossChainBase);

        return
            abi.encode(
                RaiseConstants.STARTUP_REGISTER_RAISE_TYPEHASH,
                keccak256(encodedRaise_),
                keccak256(encodedRaiseDetails_),
                keccak256(encodedERC20Asset_),
                keccak256(encodedBaseAsset_),
                keccak256(encodedBase_)
            );
    }

    /// @dev Encode finish raise request.
    /// @param _request RequestTypes.FinishRaiseRequest struct
    /// @return Encoded message.
    function encodeFinishRaise(RequestTypes.FinishRaiseRequest memory _request) internal pure returns (bytes memory) {
        bytes memory encodedBase_ = abi.encode(_request.base);

        return
            abi.encode(
                RaiseConstants.STARTUP_FINISH_RAISE_TYPEHASH,
                keccak256(bytes(_request.raiseId)),
                _request.raised,
                _request.merkleRoot,
                keccak256(encodedBase_)
            );
    }

    /// @dev Encode finish raise receiver request.
    /// @param _request RequestTypes.FinishRaiseReceiverRequest struct
    /// @return Encoded message.
    function encodeFinishRaiseReceiver(RequestTypes.FinishRaiseReceiverRequest memory _request) internal pure returns (bytes memory) {
        bytes memory encodedBase_ = abi.encode(_request.crossChainBase);

        return
            abi.encode(
                RaiseConstants.STARTUP_FINISH_RAISE_RECEIVER_TYPEHASH,
                keccak256(bytes(_request.raiseId)),
                _request.raised,
                _request.merkleRoot,
                keccak256(encodedBase_)
            );
    }

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

        // msg
        bytes memory encodedMsg_ = abi.encode(
            RaiseConstants.STARTUP_SET_TOKEN_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            _request.token,
            keccak256(encodedBase_)
        );

        // return
        return encodedMsg_;
    }

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

        // msg
        bytes memory encodedMsg_ = abi.encode(
            RaiseConstants.INVESTOR_INVEST_TYPEHASH,
            keccak256(bytes(_request.raiseId)),
            _request.investment,
            _request.maxTicketSize,
            keccak256(encodedBase_)
        );

        // return
        return encodedMsg_;
    }
}

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

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

    security-contact:
    - [email protected]
    maintainers:
    - [email protected]
    - [email protected]
    - [email protected]
    - [email protected]
    contributors:
    - [email protected]

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

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

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

    Raise events
    
**************************************/

/// @dev All events connected with raises.
library RaiseEvents {
    // -----------------------------------------------------------------------
    //                              Raise
    // -----------------------------------------------------------------------

    event NewRaise(
        address sender,
        StorageTypes.Raise raise,
        StorageTypes.RaiseDetails raiseDetails,
        StorageTypes.ERC20Asset erc20Asset,
        StorageTypes.BaseAsset baseAsset,
        uint256 badgeId,
        uint256 nonce
    );
    event RaiseRegistered(
        StorageTypes.Raise raise,
        StorageTypes.RaiseDetails raiseDetails,
        StorageTypes.ERC20Asset erc20Asset,
        StorageTypes.BaseAsset baseAsset,
        uint256 nonce
    );
    event RaiseFinishedSuccessfully(address sender, string raiseId, bytes32 merkleTreeRoot); // 0x8e24bfdd
    event RaiseFinishedUnsuccessfully(address sender, string raiseId, uint256 raised, uint256 softcap); // 0xb54e9804

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

    event TokenSet(address sender, string raiseId, address token);

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

    event NewInvestment(address sender, string raiseId, uint256 investment, bytes32 message, uint256 data);

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

    event InvestmentRefunded(address sender, string raiseId, uint256 amount);
    event CollateralRefunded(address startup, string raiseId, uint256 amount);

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

    event UnsoldReclaimed(address startup, string raiseId, uint256 amount);
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// 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 6 of 41 : LibNonce.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

    Nonce library

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

    Diamond storage containing nonces

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

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

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

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

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

library InvestorService {
    /// @dev Validate invest request.
    /// @dev Validation: Checks validity of sender, request, raise and investment.
    /// @param _request InvestRequest struct
    function validateInvestRequest(RequestTypes.InvestRequest calldata _request) internal view {
        // tx.members
        address sender_ = msg.sender;
        uint256 now_ = block.timestamp;

        // request members
        string memory raiseId_ = _request.raiseId;

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

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

        // verify sender
        if (sender_ != _request.base.sender) {
            revert RequestErrors.IncorrectSender(sender_);
        }

        // existence check
        if (!RaiseService.isRaiseExists(raiseId_)) {
            revert RaiseErrors.RaiseDoesNotExists(raiseId_);
        }

        // get base asset chain id
        uint256 baseAssetChainId_ = LibBaseAsset.getChainId(raiseId_);

        // validate if base asset is on the current chain
        if (baseAssetChainId_ != block.chainid) {
            revert CrossChainErrors.InvalidChainId(block.chainid, baseAssetChainId_);
        }

        // startup owner cannot invest
        if (sender_ == LibRaise.getController(raiseId_) || sender_ == LibRaise.getReceiver(raiseId_)) {
            revert RaiseErrors.OwnerCannotInvest(sender_, raiseId_);
        }

        // check if fundraising is active (in time)
        if (!RaiseService.isRaiseActive(raiseId_)) {
            revert RaiseErrors.RaiseNotActive(raiseId_, now_);
        }

        // verify amount + storage vs ticket size
        // TODO: getInvested -> invested from proofs
        uint256 existingInvestment_ = LibInvestorFundsInfo.getInvested(raiseId_, sender_);
        if (existingInvestment_ + _request.investment > _request.maxTicketSize) {
            revert RaiseErrors.InvestmentOverLimit(existingInvestment_, _request.investment, _request.maxTicketSize);
        }

        // check if the investement does not make the total investment exceed the limit
        uint256 existingTotalInvestment_ = LibRaise.getRaised(raiseId_);
        uint256 hardcap_ = LibRaise.getHardcap(raiseId_);
        if (existingTotalInvestment_ + _request.investment > hardcap_) {
            revert RaiseErrors.InvestmentOverHardcap(existingTotalInvestment_, _request.investment, hardcap_);
        }
    }

    /// @dev Validate refund investment.
    /// @dev Validation: Validate raise, sender and ability to refund.
    /// @param _raiseId ID of raise
    function validateRefundInvestment(string memory _raiseId) internal view {
        // tx.members
        address sender_ = msg.sender;

        // check if raise exists
        if (!RaiseService.isRaiseExists(_raiseId)) {
            revert RaiseErrors.RaiseDoesNotExists(_raiseId);
        }

        // get base asset chain id
        uint256 baseAssetChainId_ = LibBaseAsset.getChainId(_raiseId);

        // validate if base asset is on the current chain
        if (baseAssetChainId_ != block.chainid) {
            revert CrossChainErrors.InvalidChainId(block.chainid, baseAssetChainId_);
        }

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

        // check if user invested
        // TODO: getInvested -> invested from proofs
        if (LibInvestorFundsInfo.getInvested(_raiseId, sender_) == 0) {
            revert RaiseErrors.UserHasNotInvested(sender_, _raiseId);
        }

        // check if already refunded
        if (LibInvestorFundsInfo.getInvestmentRefunded(_raiseId, sender_)) {
            revert RaiseErrors.InvestorAlreadyRefunded(sender_, _raiseId);
        }
    }

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

        // increase raised amount for raise
        LibRaise.increaseRaised(_raiseId, _investment);

        // increase invested amount for user
        LibInvestorFundsInfo.increaseInvested(_raiseId, sender_, _investment);
    }
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// OpenZeppelin
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

// Local imports - storages
import { LibAppStorage } from "../../storage/ethereum/LibAppStorage.sol";
import { LibBaseAsset } from "../../../libraries/storage/assets/LibBaseAsset.sol";

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

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

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

        // get base asset
        IERC20Metadata baseAsset_ = IERC20Metadata(LibBaseAsset.getAddress(_raiseId));

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

        // mint equity badge
        badge.mint(sender_, _badgeId, _investment / 10 ** baseAsset_.decimals(), data_);
    }

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

    /// @dev Set URI for given badge id on the Equity Badge ERC-1155 token.
    /// @param _badgeId ID of badge
    /// @param _uri URI
    function setEquityBadgeURI(uint256 _badgeId, string memory _uri) internal {
        LibAppStorage.getBadge().setURI(_badgeId, _uri);
    }
}

File 10 of 41 : BaseAssetService.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

// Local imports - constants, encoders, events, errors, structs
import { RaiseErrors } from "../../../errors/RaiseErrors.sol";
import { LibEscrow } from "../../storage/assets/LibEscrow.sol";
import { LibBaseAsset } from "../../storage/assets/LibBaseAsset.sol";
import { LibInvestorFundsInfo } from "../../storage/raise/LibInvestorFundsInfo.sol";

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

library BaseAssetService {
    using SafeERC20 for IERC20;

    /// @dev Collect base asset from investor.
    /// @dev Validation: Requires investor to have assets and provide enough allowance.
    /// @dev Events: Transfer(address from, address to, uint256 value).
    /// @param _raiseId Id of the raise
    /// @param _sender Address of investor
    /// @param _investment Amount of investment
    function collectBaseAsset(string memory _raiseId, address _sender, uint256 _investment) internal {
        // get base asset address
        IERC20 baseAsset_ = IERC20(LibBaseAsset.getAddress(_raiseId));

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

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

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

        // transfer
        baseAsset_.safeTransferFrom(_sender, escrow_, _investment);
    }

    /// @dev Refund base asset to investor.
    /// @dev Validation: Requires investor to have assets and provide enough allowance.
    /// @dev Events: Transfer(address from, address to, uint256 value).
    /// @param _raiseId Id of the raise
    /// @param _account Address of investor
    /// @return investment_ Amount of investment
    function refundBaseAsset(string memory _raiseId, address _account) internal returns (uint256 investment_) {
        // get Escrow address
        address escrow_ = LibEscrow.getEscrow(_raiseId);

        // get investment
        // TODO: getInvested -> invested from proofs
        investment_ = LibInvestorFundsInfo.getInvested(_raiseId, _account);

        // prepare for transfer
        LibInvestorFundsInfo.setInvestmentRefunded(_raiseId, _account, true);

        // get base asset address
        address baseAsset_ = LibBaseAsset.getAddress(_raiseId);

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

        // transfer
        IEscrow(escrow_).withdraw(baseAsset_, receiverData_);
    }
}

File 11 of 41 : IInvestorRaiseFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

interface IInvestorRaiseFacet {
    /// @dev Invest in a raise and mint ERC1155 equity badge for it.
    /// @dev Validation: Requires valid cosignature from AngelBlock validator to execute.
    /// @dev Events: NewInvestment(address sender, string raiseId, uint256 investment, bytes32 message, uint256 data).
    /// @param _request InvestRequest struct
    /// @param _message EIP712 messages that contains request
    /// @param _v Part of signature for message
    /// @param _r Part of signature for message
    /// @param _s Part of signature for message
    function invest(RequestTypes.InvestRequest calldata _request, bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) external;

    /// @dev Refund investment to investor, if raise was not successful (softcap hasn't been reached).
    /// @dev Validation: Validate raise, sender and ability to refund.
    /// @dev Events: InvestmentRefunded(address sender, string raiseId, uint256 amount).
    /// @param _raiseId ID of raise
    function refundInvestment(string memory _raiseId) external;
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// 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 receiver Address of wallet that will receive funds from Escrow
    /// @param controller Address of wallet that will trigger claim on Escrow
    struct Raise {
        string raiseId;
        EnumTypes.RaiseType raiseType;
        address receiver;
        address controller;
    }

    /// @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; // TODO: Convert to receiver and controller
    }

    /// @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 13 of 41 : CrossChainRequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// 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 14 of 41 : CrossChainErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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 15 of 41 : RequestErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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 BadgeUriEmpty(); // 0xb03cfc55
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

    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

    // -----------------------------------------------------------------------
    //                              Finish Raise
    // -----------------------------------------------------------------------

    error RaiseCannotBeFinishedYet(string raiseId, uint256 raised, uint256 hardcap, uint256 endTimestamp); // 0xaaf81bbb
    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

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

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

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

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

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

/// @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 18 of 41 : LibRaise.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

// 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 receiver.
    /// @param _raiseId Raise id
    /// @return Raise receiver
    function getReceiver(string memory _raiseId) internal view returns (address) {
        // return
        return raiseStorage().raises[_raiseId].receiver;
    }

    /// @dev Diamond storage setter: raise receiver.
    /// @param _raiseId Raise id
    /// @param _receiver Receiver address
    function setReceiver(string memory _raiseId, address _receiver) internal {
        // set receiver
        raiseStorage().raises[_raiseId].receiver = _receiver;
    }

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

    /// @dev Diamond storage setter: raise controller.
    /// @param _raiseId Raise id
    /// @param _controller Raise controller
    function setController(string memory _raiseId, address _controller) internal {
        // set controller
        raiseStorage().raises[_raiseId].controller = _controller;
    }

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

File 19 of 41 : LibBaseAsset.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

    /// @dev Investor funds info storage pointer.
    bytes32 internal constant INVESTOR_FUNDS_INFO_STORAGE_POSITION = keccak256("angelblock.fundraising.investor.funds.info");

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

    /// @dev Investor funds info storage struct.
    /// @param investorFundsInfo Mapping of raise id to investor funds info struct
    struct InvestorFundsInfoStorage {
        mapping(string => StorageTypes.InvestorFundsInfo) investorFundsInfo;
    }

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

    /// @dev Function returning investor funds info storage at storage pointer slot.
    /// @return ifis InvestorFundsInfoStorage struct instance at storage pointer position
    function investorFundsInfoStorage() internal pure returns (InvestorFundsInfoStorage storage ifis) {
        // declare position
        bytes32 position = INVESTOR_FUNDS_INFO_STORAGE_POSITION;

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

        // explicit return
        return ifis;
    }

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

    /// @dev Diamond storage getter: Invested amount in given raise.
    /// @param _raiseId ID of the raise
    /// @param _account Investor address
    /// @return Amount of invested base asset in the given raise
    function getInvested(string memory _raiseId, address _account) internal view returns (uint256) {
        // return
        return investorFundsInfoStorage().investorFundsInfo[_raiseId].invested[_account];
    }

    /// @dev Diamond storage getter: Is investment refunded.
    /// @param _raiseId ID of the raise
    /// @param _account Investor address
    /// @return Is invested refunded
    function getInvestmentRefunded(string memory _raiseId, address _account) internal view returns (bool) {
        return investorFundsInfoStorage().investorFundsInfo[_raiseId].investmentRefunded[_account];
    }

    /// @dev Diamond storage setter: Increase invested amount for given raise.
    /// @param _raiseId ID of the raise
    /// @param _account Investor address
    /// @param _invested Value to be increased
    function increaseInvested(string memory _raiseId, address _account, uint256 _invested) internal {
        investorFundsInfoStorage().investorFundsInfo[_raiseId].invested[_account] += _invested;
    }

    /// @dev Diamond storage setter: Is investment refunded.
    /// @param _raiseId ID of the raise
    /// @param _account Investor address
    /// @param _refunded Is invested refunded
    function setInvestmentRefunded(string memory _raiseId, address _account, bool _refunded) internal {
        investorFundsInfoStorage().investorFundsInfo[_raiseId].investmentRefunded[_account] = _refunded;
    }
}

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

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

File 22 of 41 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

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

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

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

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

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

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

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

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

        return (signer, RecoverError.NoError);
    }

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

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

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

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

File 23 of 41 : SignatureConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

/// @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 24 of 41 : SignatureErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

    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 25 of 41 : AccessTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

File 26 of 41 : LibAccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

    AccessControl library

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

    Diamond storage containing access control data

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

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

    /// @dev Access control storage pointer.
    bytes32 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 27 of 41 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 28 of 41 : LibAppStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

// Local imports - Interfaces
import { IEquityBadge } from "../../../../interfaces/IEquityBadge.sol";

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

    AppStorage library

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

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

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

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

    /// @dev App storage struct. Special type of diamond storage with no storage pointer.
    /// @param usdt USDT token
    /// @param equityBadge Equity badge
    struct AppStorage {
        bytes32 slot0; // free slot 0 that can be taken over
        IEquityBadge equityBadge;
    }

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

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

        // explicit return
        return s;
    }

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

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

        Get badge

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

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

File 29 of 41 : IEquityBadge.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

    EquityBadge interface

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 32 of 41 : LibEscrow.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

File 33 of 41 : IEscrow.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

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

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

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

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

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

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

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

File 34 of 41 : LibERC20Asset.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

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

    security-contact:
    - [email protected]

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

    contributors:
    - [email protected]

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

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

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

pragma solidity ^0.8.0;

import "./math/Math.sol";

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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/",
    "@layerzerolabs/lz-evm-oapp-v2/=src/fundraising/node_modules/@layerzerolabs/lz-evm-oapp-v2/",
    "@layerzerolabs/lz-evm-messagelib-v2/=src/fundraising/node_modules/@layerzerolabs/lz-evm-messagelib-v2/",
    "@layerzerolabs/lz-evm-protocol-v2/=src/fundraising/node_modules/@layerzerolabs/lz-evm-protocol-v2/",
    "solidity-bytes-utils/=src/fundraising/node_modules/solidity-bytes-utils/",
    "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/",
    "layer-zero/=src/fundraising/node_modules/layer-zero/",
    "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

[{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"IncorrectSender","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"IncorrectSigner","type":"error"},{"inputs":[{"internalType":"uint256","name":"current","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidChainId","type":"error"},{"inputs":[{"internalType":"bytes32","name":"verify","type":"bytes32"},{"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"InvalidMessage","type":"error"},{"inputs":[{"internalType":"uint256","name":"existingInvestment","type":"uint256"},{"internalType":"uint256","name":"newInvestment","type":"uint256"},{"internalType":"uint256","name":"hardcap","type":"uint256"}],"name":"InvestmentOverHardcap","type":"error"},{"inputs":[{"internalType":"uint256","name":"existingInvestment","type":"uint256"},{"internalType":"uint256","name":"newInvestment","type":"uint256"},{"internalType":"uint256","name":"maxTicketSize","type":"uint256"}],"name":"InvestmentOverLimit","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"raiseId","type":"string"}],"name":"InvestorAlreadyRefunded","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":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NotEnoughAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"investment","type":"uint256"}],"name":"NotEnoughBalanceForInvestment","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"raiseId","type":"string"}],"name":"OwnerCannotInvest","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"RaiseDoesNotExists","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"uint256","name":"currentTime","type":"uint256"}],"name":"RaiseNotActive","type":"error"},{"inputs":[{"internalType":"string","name":"raiseId","type":"string"}],"name":"RaiseNotFailed","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"RequestExpired","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"raiseId","type":"string"}],"name":"UserHasNotInvested","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"raiseId","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvestmentRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"raiseId","type":"string"},{"indexed":false,"internalType":"uint256","name":"investment","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"message","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"data","type":"uint256"}],"name":"NewInvestment","type":"event"},{"inputs":[{"components":[{"internalType":"string","name":"raiseId","type":"string"},{"internalType":"uint256","name":"investment","type":"uint256"},{"internalType":"uint256","name":"maxTicketSize","type":"uint256"},{"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.InvestRequest","name":"_request","type":"tuple"},{"internalType":"bytes32","name":"_message","type":"bytes32"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"invest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_raiseId","type":"string"}],"name":"refundInvestment","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60808060405234601557611758908161001b8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c8063ef88123714610e475763fe599cdb1461003357600080fd5b34610e405760031960a036820112610e435767ffffffffffffffff60043511610e435760c09060043536030112610e405760ff6044351660443503610e405761008a610083600480350180611332565b3691611295565b61009b610083600480350180611332565b3360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f602052604090205460a460043501351115610e1a57608460043501354211610df457600435606401356001600160a01b03811690819003610a83573303610ddc5761010c816113aa565b15610db7576001604051602081845161012881838589016112ea565b600080516020611703833981519152818301528101030190200154468103610d995750604051815161015e8183602086016112ea565b810160027fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d29283835260208160018060a01b0394030190200154163314908115610d61575b50610d4357600360405160208184516101bf81838589016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3818301528101030190200154600460405160208185516102038183858a016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d38152030190200154904210159081610d38575b5015610d0957604051602081835161025481838588016112ea565b7f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710818301528101030190203360005260205260406000205461029c6024600435013582611387565b6044600435013510610ccb575060016103046020604051818186516102c48183858b016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d481830152810103019020549381604051938285809451938492016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3815203019020015490816103416024600435013583611387565b11610c9c57505060405180608081011067ffffffffffffffff608083011117610c8657608081016040526004356004013567ffffffffffffffff8111610a83576103929060043691813501016112cc565b8152602460043501356020820152604460043501356040820152606060631960043536030112610a74576040519081606081011067ffffffffffffffff606084011117610c865760608201604052606460043501358252602082016084600435013581526040830160a46004350135815283606084015260405191602083019460018060a01b0390511685525160408301525160608201526060815261043781611203565b815160208151910120926040602084015193015191519020906040519260208401947f214b8909051ccaffc46e15bfdd43fc0d820efdcaaa8586858f58df2b7912d756865260408501526060840152608083015260a082015260a0815261049d8161121f565b7046756e6472616973696e673a526169736560781b60206040516104c08161123b565b60118152015264323a333a3160d81b60206040516104dd8161123b565b60058152015251902060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f4488c40da75f747650ea253102292d50b0c3f0c34fc80e9620d8c9efafb9094e60408201527f967e55b836baa81f8a8590db04c7d2845cce2aa2b174a806a020b0c3cfcc763460608201524660808201523060a082015260a081526105768161121f565b5190209060405190602082019261190160f01b845260228301526042820152604281526105a281611203565b5190206024358103610c6657506105ce6105c66084356064356044356024356114c0565b91909161154f565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b0316908160005260205260ff6040600020541615610c4e5750604051815161064c8183602086016112ea565b810190600080516020611703833981519152825260208160018060a01b039303019020541660405182516106848183602087016112ea565b8101907fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d7087188825260208160018060a01b03930301902054166040516370a0823160e01b8152336004820152602081602481865afa908115610bea578591610c1c575b506024600435013511610bf557604051636eb1769f60e11b8152336004820152306024820152602081604481865afa908115610bea578591610bb3575b506024600435013511610b80576040516323b872dd60e01b60208201908152336024808401919091526001600160a01b039390931660448301526004359092013560648083019190915281526107ed92909185908190610783608486611257565b604051946107908661123b565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af13d15610b78573d916107d183611279565b926107df6040519485611257565b83523d87602085013e611669565b805180610afb575b505060405160208101906020825261082281610814604082018661130d565b03601f198101835282611257565b5190203360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a40135905560018060a01b0360015416604051835161087a8183602088016112ea565b810190600080516020611703833981519152825260208160018060a01b0393030190205416600460206040519285828501528184526108b88461123b565b60405163313ce56760e01b815292839182905afa8015610af0578690610aaf575b60ff91501690604d8211610a9b5781600a0a15610a875790829186933b15610a83576109429284928360405180968195829463731133e960e01b84523360048501528b6024850152600a0a6024600435013504604484015260806064840152608483019061130d565b03925af18015610a7857610a60575b507f8511384efa543c4c9f6cbba3d34a2fc2df4f9490df6b476af3bffa137bd7fe4b610a408484604051602081845161098d81838589016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d48152030190206109c7602460043501358254611387565b905560405160208184516109de81838589016112ea565b81017f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710815203019020336000526020526040600020610a24602460043501358254611387565b905560405192839233845260a0602085015260a084019061130d565b90602460043501356040840152602435606084015260808301520390a180f35b610a69906111ef565b610a74578238610951565b8280fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526012600452602486fd5b634e487b7160e01b86526011600452602486fd5b506020813d602011610ae8575b81610ac960209383611257565b81010312610ae4575160ff81168103610ae45760ff906108d9565b8580fd5b3d9150610abc565b6040513d88823e3d90fd5b8160209181010312610a745760200151801590811503610a7457610b205738806107f5565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b606091611669565b60405163892e773960e01b81523360048083019190915230602480840191909152903501356044820152606490fd5b0390fd5b90506020813d602011610be2575b81610bce60209383611257565b81010312610bdd575138610722565b600080fd5b3d9150610bc1565b6040513d87823e3d90fd5b60405163aff6db1560e01b8152336004808301919091526024903581013590820152604490fd5b90506020813d602011610c46575b81610c3760209383611257565b81010312610bdd5751386106e5565b3d9150610c2a565b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b634e487b7160e01b600052604160045260246000fd5b60405163f0152bdf60e01b81526004808201929092529035602490810135908201526044810191909152606490fd5b610baf90604051918291631f5dfbcb60e11b835260446004350135906024600435013590600485016040919493926060820195825260208201520152565b610d2e9060405191829163251061ff60e01b835260406004840152604483019061130d565b4260248301520390fd5b905042111538610239565b6040516344b4eea960e01b8152908190610baf903360048401611365565b905060016040518351610d788183602088016112ea565b8101928352602081838060a01b039403019020015460081c163314386101a3565b60449060405190639fba672f60e01b82524660048301526024820152fd5b604051637813445960e01b815260206004820152908190610baf90602483019061130d565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048083019190915235608401356024820152604490fd5b604051632b6069a960e01b8152336004808301919091523560a401356024820152604490fd5b80fd5b5080fd5b5034610e4057602080600319360112610e435767ffffffffffffffff600435818111610a8357610e7b9036906004016112cc565b610e84816113aa565b156111cc5760405191815192600185840194610ea18184886112ea565b820191868160008051602061170383398151915294858152030190200154468103610d99575060ff60405186818651610edb81838b6112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d5815203019020541660038110156111b85760010361119657604051938351610f278187846112ea565b85019486817f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c67109788815203019020338852865260408720541561117a57600160405187818751610f788183886112ea565b81018981520301902001338852865260ff60408820541661115e579085929161104f84604051928751610fac8186846112ea565b84017fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d708718881528460018060a01b0398899687930301902054169460405183818b51610ff78183886112ea565b81018d815203019020338d528352600160408d20549a8460405180928d5161102081848a6112ea565b82019081520301902001338d52835260408c20600160ff19825416179055604051809481938b519283916112ea565b82019081520301902054166040519260408401908482109082111761114a579088939291604052338352878301878152823b1561114657606492859160405197889687956318c0bbe560e01b87526004870152511660248501525160448401525af18015610bea57611108575b50916060916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294604051948594338652850152606084019061130d565b9060408301520390a180f35b916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294929561113b6060956111ef565b9592945050916110bc565b8480fd5b634e487b7160e01b89526041600452602489fd5b604051635f37987760e11b815280610baf863360048401611365565b604051637976c6f960e11b815280610baf863360048401611365565b604051630f22dbc360e11b81526004810186905280610baf602482018661130d565b634e487b7160e01b87526021600452602487fd5b82610baf604051928392637813445960e01b84526004840152602483019061130d565b67ffffffffffffffff8111610c8657604052565b6080810190811067ffffffffffffffff821117610c8657604052565b60c0810190811067ffffffffffffffff821117610c8657604052565b6040810190811067ffffffffffffffff821117610c8657604052565b90601f8019910116810190811067ffffffffffffffff821117610c8657604052565b67ffffffffffffffff8111610c8657601f01601f191660200190565b9291926112a182611279565b916112af6040519384611257565b829481845281830111610bdd578281602093846000960137010152565b9080601f83011215610bdd578160206112e793359101611295565b90565b60005b8381106112fd5750506000910152565b81810151838201526020016112ed565b90602091611326815180928185528580860191016112ea565b601f01601f1916010190565b903590601e1981360301821215610bdd570180359067ffffffffffffffff8211610bdd57602001918136038313610bdd57565b6001600160a01b0390911681526040602082018190526112e79291019061130d565b9190820180921161139457565b634e487b7160e01b600052601160045260246000fd5b9060405182818094516113c381602097888096016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d28152030190209160405190600084549460018660011c91600188169788156114b6575b85841089146114a257869798848897985290816000146114805750600114611441575b50505061143b92500382611257565b51151590565b600090815285812095935091905b81831061146857505061143b935082010138808061142c565b8554878401850152948501948694509183019161144f565b9250505061143b94925060ff191682840152151560051b82010138808061142c565b634e487b7160e01b85526022600452602485fd5b92607f1692611409565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116115435791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156115365781516001600160a01b03811615611530579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b600581101561165357806115605750565b600181036115ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036115fa5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461160357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b919290156116cb575081511561167d575090565b3b156116865790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156116de5750805190602001fd5b60405162461bcd60e51b815260206004820152908190610baf90602483019061130d56fe2b1fc81139dd17ad3c1801c783e31f497c37ee7d1bfea80d7d4940b0aa2775b6a2646970667358221220701817dc17242236c5514825f327f43216cde64061064f6407b810aafd31c8f764736f6c63430008190033

Deployed Bytecode

0x6080604052600436101561001257600080fd5b6000803560e01c8063ef88123714610e475763fe599cdb1461003357600080fd5b34610e405760031960a036820112610e435767ffffffffffffffff60043511610e435760c09060043536030112610e405760ff6044351660443503610e405761008a610083600480350180611332565b3691611295565b61009b610083600480350180611332565b3360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f602052604090205460a460043501351115610e1a57608460043501354211610df457600435606401356001600160a01b03811690819003610a83573303610ddc5761010c816113aa565b15610db7576001604051602081845161012881838589016112ea565b600080516020611703833981519152818301528101030190200154468103610d995750604051815161015e8183602086016112ea565b810160027fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d29283835260208160018060a01b0394030190200154163314908115610d61575b50610d4357600360405160208184516101bf81838589016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3818301528101030190200154600460405160208185516102038183858a016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d38152030190200154904210159081610d38575b5015610d0957604051602081835161025481838588016112ea565b7f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710818301528101030190203360005260205260406000205461029c6024600435013582611387565b6044600435013510610ccb575060016103046020604051818186516102c48183858b016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d481830152810103019020549381604051938285809451938492016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3815203019020015490816103416024600435013583611387565b11610c9c57505060405180608081011067ffffffffffffffff608083011117610c8657608081016040526004356004013567ffffffffffffffff8111610a83576103929060043691813501016112cc565b8152602460043501356020820152604460043501356040820152606060631960043536030112610a74576040519081606081011067ffffffffffffffff606084011117610c865760608201604052606460043501358252602082016084600435013581526040830160a46004350135815283606084015260405191602083019460018060a01b0390511685525160408301525160608201526060815261043781611203565b815160208151910120926040602084015193015191519020906040519260208401947f214b8909051ccaffc46e15bfdd43fc0d820efdcaaa8586858f58df2b7912d756865260408501526060840152608083015260a082015260a0815261049d8161121f565b7046756e6472616973696e673a526169736560781b60206040516104c08161123b565b60118152015264323a333a3160d81b60206040516104dd8161123b565b60058152015251902060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f4488c40da75f747650ea253102292d50b0c3f0c34fc80e9620d8c9efafb9094e60408201527f967e55b836baa81f8a8590db04c7d2845cce2aa2b174a806a020b0c3cfcc763460608201524660808201523060a082015260a081526105768161121f565b5190209060405190602082019261190160f01b845260228301526042820152604281526105a281611203565b5190206024358103610c6657506105ce6105c66084356064356044356024356114c0565b91909161154f565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b0316908160005260205260ff6040600020541615610c4e5750604051815161064c8183602086016112ea565b810190600080516020611703833981519152825260208160018060a01b039303019020541660405182516106848183602087016112ea565b8101907fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d7087188825260208160018060a01b03930301902054166040516370a0823160e01b8152336004820152602081602481865afa908115610bea578591610c1c575b506024600435013511610bf557604051636eb1769f60e11b8152336004820152306024820152602081604481865afa908115610bea578591610bb3575b506024600435013511610b80576040516323b872dd60e01b60208201908152336024808401919091526001600160a01b039390931660448301526004359092013560648083019190915281526107ed92909185908190610783608486611257565b604051946107908661123b565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af13d15610b78573d916107d183611279565b926107df6040519485611257565b83523d87602085013e611669565b805180610afb575b505060405160208101906020825261082281610814604082018661130d565b03601f198101835282611257565b5190203360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a40135905560018060a01b0360015416604051835161087a8183602088016112ea565b810190600080516020611703833981519152825260208160018060a01b0393030190205416600460206040519285828501528184526108b88461123b565b60405163313ce56760e01b815292839182905afa8015610af0578690610aaf575b60ff91501690604d8211610a9b5781600a0a15610a875790829186933b15610a83576109429284928360405180968195829463731133e960e01b84523360048501528b6024850152600a0a6024600435013504604484015260806064840152608483019061130d565b03925af18015610a7857610a60575b507f8511384efa543c4c9f6cbba3d34a2fc2df4f9490df6b476af3bffa137bd7fe4b610a408484604051602081845161098d81838589016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d48152030190206109c7602460043501358254611387565b905560405160208184516109de81838589016112ea565b81017f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710815203019020336000526020526040600020610a24602460043501358254611387565b905560405192839233845260a0602085015260a084019061130d565b90602460043501356040840152602435606084015260808301520390a180f35b610a69906111ef565b610a74578238610951565b8280fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526012600452602486fd5b634e487b7160e01b86526011600452602486fd5b506020813d602011610ae8575b81610ac960209383611257565b81010312610ae4575160ff81168103610ae45760ff906108d9565b8580fd5b3d9150610abc565b6040513d88823e3d90fd5b8160209181010312610a745760200151801590811503610a7457610b205738806107f5565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b606091611669565b60405163892e773960e01b81523360048083019190915230602480840191909152903501356044820152606490fd5b0390fd5b90506020813d602011610be2575b81610bce60209383611257565b81010312610bdd575138610722565b600080fd5b3d9150610bc1565b6040513d87823e3d90fd5b60405163aff6db1560e01b8152336004808301919091526024903581013590820152604490fd5b90506020813d602011610c46575b81610c3760209383611257565b81010312610bdd5751386106e5565b3d9150610c2a565b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b634e487b7160e01b600052604160045260246000fd5b60405163f0152bdf60e01b81526004808201929092529035602490810135908201526044810191909152606490fd5b610baf90604051918291631f5dfbcb60e11b835260446004350135906024600435013590600485016040919493926060820195825260208201520152565b610d2e9060405191829163251061ff60e01b835260406004840152604483019061130d565b4260248301520390fd5b905042111538610239565b6040516344b4eea960e01b8152908190610baf903360048401611365565b905060016040518351610d788183602088016112ea565b8101928352602081838060a01b039403019020015460081c163314386101a3565b60449060405190639fba672f60e01b82524660048301526024820152fd5b604051637813445960e01b815260206004820152908190610baf90602483019061130d565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048083019190915235608401356024820152604490fd5b604051632b6069a960e01b8152336004808301919091523560a401356024820152604490fd5b80fd5b5080fd5b5034610e4057602080600319360112610e435767ffffffffffffffff600435818111610a8357610e7b9036906004016112cc565b610e84816113aa565b156111cc5760405191815192600185840194610ea18184886112ea565b820191868160008051602061170383398151915294858152030190200154468103610d99575060ff60405186818651610edb81838b6112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d5815203019020541660038110156111b85760010361119657604051938351610f278187846112ea565b85019486817f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c67109788815203019020338852865260408720541561117a57600160405187818751610f788183886112ea565b81018981520301902001338852865260ff60408820541661115e579085929161104f84604051928751610fac8186846112ea565b84017fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d708718881528460018060a01b0398899687930301902054169460405183818b51610ff78183886112ea565b81018d815203019020338d528352600160408d20549a8460405180928d5161102081848a6112ea565b82019081520301902001338d52835260408c20600160ff19825416179055604051809481938b519283916112ea565b82019081520301902054166040519260408401908482109082111761114a579088939291604052338352878301878152823b1561114657606492859160405197889687956318c0bbe560e01b87526004870152511660248501525160448401525af18015610bea57611108575b50916060916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294604051948594338652850152606084019061130d565b9060408301520390a180f35b916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294929561113b6060956111ef565b9592945050916110bc565b8480fd5b634e487b7160e01b89526041600452602489fd5b604051635f37987760e11b815280610baf863360048401611365565b604051637976c6f960e11b815280610baf863360048401611365565b604051630f22dbc360e11b81526004810186905280610baf602482018661130d565b634e487b7160e01b87526021600452602487fd5b82610baf604051928392637813445960e01b84526004840152602483019061130d565b67ffffffffffffffff8111610c8657604052565b6080810190811067ffffffffffffffff821117610c8657604052565b60c0810190811067ffffffffffffffff821117610c8657604052565b6040810190811067ffffffffffffffff821117610c8657604052565b90601f8019910116810190811067ffffffffffffffff821117610c8657604052565b67ffffffffffffffff8111610c8657601f01601f191660200190565b9291926112a182611279565b916112af6040519384611257565b829481845281830111610bdd578281602093846000960137010152565b9080601f83011215610bdd578160206112e793359101611295565b90565b60005b8381106112fd5750506000910152565b81810151838201526020016112ed565b90602091611326815180928185528580860191016112ea565b601f01601f1916010190565b903590601e1981360301821215610bdd570180359067ffffffffffffffff8211610bdd57602001918136038313610bdd57565b6001600160a01b0390911681526040602082018190526112e79291019061130d565b9190820180921161139457565b634e487b7160e01b600052601160045260246000fd5b9060405182818094516113c381602097888096016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d28152030190209160405190600084549460018660011c91600188169788156114b6575b85841089146114a257869798848897985290816000146114805750600114611441575b50505061143b92500382611257565b51151590565b600090815285812095935091905b81831061146857505061143b935082010138808061142c565b8554878401850152948501948694509183019161144f565b9250505061143b94925060ff191682840152151560051b82010138808061142c565b634e487b7160e01b85526022600452602485fd5b92607f1692611409565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116115435791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156115365781516001600160a01b03811615611530579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b600581101561165357806115605750565b600181036115ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036115fa5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461160357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b919290156116cb575081511561167d575090565b3b156116865790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156116de5750805190602001fd5b60405162461bcd60e51b815260206004820152908190610baf90602483019061130d56fe2b1fc81139dd17ad3c1801c783e31f497c37ee7d1bfea80d7d4940b0aa2775b6a2646970667358221220701817dc17242236c5514825f327f43216cde64061064f6407b810aafd31c8f764736f6c63430008190033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.