Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
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
Contract Source Code (Solidity Standard Json-Input format)
// 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_); } }
// 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)"); }
// 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_; } }
// 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); }
// 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; } }
// 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; } }
// 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); } }
// 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_; } }
// 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); } }
// 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_); } }
// 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; }
// 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; } }
// 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; } }
// 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 }
// 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 }
// 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 }
// 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 } }
// 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; } }
// 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; } }
// 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; } }
// 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); } }
// 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)); } }
// 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)"); }
// 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 }
// 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"); }
// 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); } } }
// 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); }
// 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; } }
// 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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// 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; } }
// 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; }
// 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // 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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: 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); } } }
// 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); }
{ "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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
60808060405234601557611758908161001b8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c8063ef88123714610e475763fe599cdb1461003357600080fd5b34610e405760031960a036820112610e435767ffffffffffffffff60043511610e435760c09060043536030112610e405760ff6044351660443503610e405761008a610083600480350180611332565b3691611295565b61009b610083600480350180611332565b3360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f602052604090205460a460043501351115610e1a57608460043501354211610df457600435606401356001600160a01b03811690819003610a83573303610ddc5761010c816113aa565b15610db7576001604051602081845161012881838589016112ea565b600080516020611703833981519152818301528101030190200154468103610d995750604051815161015e8183602086016112ea565b810160027fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d29283835260208160018060a01b0394030190200154163314908115610d61575b50610d4357600360405160208184516101bf81838589016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3818301528101030190200154600460405160208185516102038183858a016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d38152030190200154904210159081610d38575b5015610d0957604051602081835161025481838588016112ea565b7f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710818301528101030190203360005260205260406000205461029c6024600435013582611387565b6044600435013510610ccb575060016103046020604051818186516102c48183858b016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d481830152810103019020549381604051938285809451938492016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3815203019020015490816103416024600435013583611387565b11610c9c57505060405180608081011067ffffffffffffffff608083011117610c8657608081016040526004356004013567ffffffffffffffff8111610a83576103929060043691813501016112cc565b8152602460043501356020820152604460043501356040820152606060631960043536030112610a74576040519081606081011067ffffffffffffffff606084011117610c865760608201604052606460043501358252602082016084600435013581526040830160a46004350135815283606084015260405191602083019460018060a01b0390511685525160408301525160608201526060815261043781611203565b815160208151910120926040602084015193015191519020906040519260208401947f214b8909051ccaffc46e15bfdd43fc0d820efdcaaa8586858f58df2b7912d756865260408501526060840152608083015260a082015260a0815261049d8161121f565b7046756e6472616973696e673a526169736560781b60206040516104c08161123b565b60118152015264323a333a3160d81b60206040516104dd8161123b565b60058152015251902060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f4488c40da75f747650ea253102292d50b0c3f0c34fc80e9620d8c9efafb9094e60408201527f967e55b836baa81f8a8590db04c7d2845cce2aa2b174a806a020b0c3cfcc763460608201524660808201523060a082015260a081526105768161121f565b5190209060405190602082019261190160f01b845260228301526042820152604281526105a281611203565b5190206024358103610c6657506105ce6105c66084356064356044356024356114c0565b91909161154f565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b0316908160005260205260ff6040600020541615610c4e5750604051815161064c8183602086016112ea565b810190600080516020611703833981519152825260208160018060a01b039303019020541660405182516106848183602087016112ea565b8101907fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d7087188825260208160018060a01b03930301902054166040516370a0823160e01b8152336004820152602081602481865afa908115610bea578591610c1c575b506024600435013511610bf557604051636eb1769f60e11b8152336004820152306024820152602081604481865afa908115610bea578591610bb3575b506024600435013511610b80576040516323b872dd60e01b60208201908152336024808401919091526001600160a01b039390931660448301526004359092013560648083019190915281526107ed92909185908190610783608486611257565b604051946107908661123b565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af13d15610b78573d916107d183611279565b926107df6040519485611257565b83523d87602085013e611669565b805180610afb575b505060405160208101906020825261082281610814604082018661130d565b03601f198101835282611257565b5190203360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a40135905560018060a01b0360015416604051835161087a8183602088016112ea565b810190600080516020611703833981519152825260208160018060a01b0393030190205416600460206040519285828501528184526108b88461123b565b60405163313ce56760e01b815292839182905afa8015610af0578690610aaf575b60ff91501690604d8211610a9b5781600a0a15610a875790829186933b15610a83576109429284928360405180968195829463731133e960e01b84523360048501528b6024850152600a0a6024600435013504604484015260806064840152608483019061130d565b03925af18015610a7857610a60575b507f8511384efa543c4c9f6cbba3d34a2fc2df4f9490df6b476af3bffa137bd7fe4b610a408484604051602081845161098d81838589016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d48152030190206109c7602460043501358254611387565b905560405160208184516109de81838589016112ea565b81017f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710815203019020336000526020526040600020610a24602460043501358254611387565b905560405192839233845260a0602085015260a084019061130d565b90602460043501356040840152602435606084015260808301520390a180f35b610a69906111ef565b610a74578238610951565b8280fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526012600452602486fd5b634e487b7160e01b86526011600452602486fd5b506020813d602011610ae8575b81610ac960209383611257565b81010312610ae4575160ff81168103610ae45760ff906108d9565b8580fd5b3d9150610abc565b6040513d88823e3d90fd5b8160209181010312610a745760200151801590811503610a7457610b205738806107f5565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b606091611669565b60405163892e773960e01b81523360048083019190915230602480840191909152903501356044820152606490fd5b0390fd5b90506020813d602011610be2575b81610bce60209383611257565b81010312610bdd575138610722565b600080fd5b3d9150610bc1565b6040513d87823e3d90fd5b60405163aff6db1560e01b8152336004808301919091526024903581013590820152604490fd5b90506020813d602011610c46575b81610c3760209383611257565b81010312610bdd5751386106e5565b3d9150610c2a565b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b634e487b7160e01b600052604160045260246000fd5b60405163f0152bdf60e01b81526004808201929092529035602490810135908201526044810191909152606490fd5b610baf90604051918291631f5dfbcb60e11b835260446004350135906024600435013590600485016040919493926060820195825260208201520152565b610d2e9060405191829163251061ff60e01b835260406004840152604483019061130d565b4260248301520390fd5b905042111538610239565b6040516344b4eea960e01b8152908190610baf903360048401611365565b905060016040518351610d788183602088016112ea565b8101928352602081838060a01b039403019020015460081c163314386101a3565b60449060405190639fba672f60e01b82524660048301526024820152fd5b604051637813445960e01b815260206004820152908190610baf90602483019061130d565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048083019190915235608401356024820152604490fd5b604051632b6069a960e01b8152336004808301919091523560a401356024820152604490fd5b80fd5b5080fd5b5034610e4057602080600319360112610e435767ffffffffffffffff600435818111610a8357610e7b9036906004016112cc565b610e84816113aa565b156111cc5760405191815192600185840194610ea18184886112ea565b820191868160008051602061170383398151915294858152030190200154468103610d99575060ff60405186818651610edb81838b6112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d5815203019020541660038110156111b85760010361119657604051938351610f278187846112ea565b85019486817f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c67109788815203019020338852865260408720541561117a57600160405187818751610f788183886112ea565b81018981520301902001338852865260ff60408820541661115e579085929161104f84604051928751610fac8186846112ea565b84017fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d708718881528460018060a01b0398899687930301902054169460405183818b51610ff78183886112ea565b81018d815203019020338d528352600160408d20549a8460405180928d5161102081848a6112ea565b82019081520301902001338d52835260408c20600160ff19825416179055604051809481938b519283916112ea565b82019081520301902054166040519260408401908482109082111761114a579088939291604052338352878301878152823b1561114657606492859160405197889687956318c0bbe560e01b87526004870152511660248501525160448401525af18015610bea57611108575b50916060916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294604051948594338652850152606084019061130d565b9060408301520390a180f35b916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294929561113b6060956111ef565b9592945050916110bc565b8480fd5b634e487b7160e01b89526041600452602489fd5b604051635f37987760e11b815280610baf863360048401611365565b604051637976c6f960e11b815280610baf863360048401611365565b604051630f22dbc360e11b81526004810186905280610baf602482018661130d565b634e487b7160e01b87526021600452602487fd5b82610baf604051928392637813445960e01b84526004840152602483019061130d565b67ffffffffffffffff8111610c8657604052565b6080810190811067ffffffffffffffff821117610c8657604052565b60c0810190811067ffffffffffffffff821117610c8657604052565b6040810190811067ffffffffffffffff821117610c8657604052565b90601f8019910116810190811067ffffffffffffffff821117610c8657604052565b67ffffffffffffffff8111610c8657601f01601f191660200190565b9291926112a182611279565b916112af6040519384611257565b829481845281830111610bdd578281602093846000960137010152565b9080601f83011215610bdd578160206112e793359101611295565b90565b60005b8381106112fd5750506000910152565b81810151838201526020016112ed565b90602091611326815180928185528580860191016112ea565b601f01601f1916010190565b903590601e1981360301821215610bdd570180359067ffffffffffffffff8211610bdd57602001918136038313610bdd57565b6001600160a01b0390911681526040602082018190526112e79291019061130d565b9190820180921161139457565b634e487b7160e01b600052601160045260246000fd5b9060405182818094516113c381602097888096016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d28152030190209160405190600084549460018660011c91600188169788156114b6575b85841089146114a257869798848897985290816000146114805750600114611441575b50505061143b92500382611257565b51151590565b600090815285812095935091905b81831061146857505061143b935082010138808061142c565b8554878401850152948501948694509183019161144f565b9250505061143b94925060ff191682840152151560051b82010138808061142c565b634e487b7160e01b85526022600452602485fd5b92607f1692611409565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116115435791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156115365781516001600160a01b03811615611530579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b600581101561165357806115605750565b600181036115ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036115fa5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461160357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b919290156116cb575081511561167d575090565b3b156116865790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156116de5750805190602001fd5b60405162461bcd60e51b815260206004820152908190610baf90602483019061130d56fe2b1fc81139dd17ad3c1801c783e31f497c37ee7d1bfea80d7d4940b0aa2775b6a2646970667358221220701817dc17242236c5514825f327f43216cde64061064f6407b810aafd31c8f764736f6c63430008190033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c8063ef88123714610e475763fe599cdb1461003357600080fd5b34610e405760031960a036820112610e435767ffffffffffffffff60043511610e435760c09060043536030112610e405760ff6044351660443503610e405761008a610083600480350180611332565b3691611295565b61009b610083600480350180611332565b3360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f602052604090205460a460043501351115610e1a57608460043501354211610df457600435606401356001600160a01b03811690819003610a83573303610ddc5761010c816113aa565b15610db7576001604051602081845161012881838589016112ea565b600080516020611703833981519152818301528101030190200154468103610d995750604051815161015e8183602086016112ea565b810160027fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d29283835260208160018060a01b0394030190200154163314908115610d61575b50610d4357600360405160208184516101bf81838589016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3818301528101030190200154600460405160208185516102038183858a016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d38152030190200154904210159081610d38575b5015610d0957604051602081835161025481838588016112ea565b7f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710818301528101030190203360005260205260406000205461029c6024600435013582611387565b6044600435013510610ccb575060016103046020604051818186516102c48183858b016112ea565b7fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d481830152810103019020549381604051938285809451938492016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d3815203019020015490816103416024600435013583611387565b11610c9c57505060405180608081011067ffffffffffffffff608083011117610c8657608081016040526004356004013567ffffffffffffffff8111610a83576103929060043691813501016112cc565b8152602460043501356020820152604460043501356040820152606060631960043536030112610a74576040519081606081011067ffffffffffffffff606084011117610c865760608201604052606460043501358252602082016084600435013581526040830160a46004350135815283606084015260405191602083019460018060a01b0390511685525160408301525160608201526060815261043781611203565b815160208151910120926040602084015193015191519020906040519260208401947f214b8909051ccaffc46e15bfdd43fc0d820efdcaaa8586858f58df2b7912d756865260408501526060840152608083015260a082015260a0815261049d8161121f565b7046756e6472616973696e673a526169736560781b60206040516104c08161123b565b60118152015264323a333a3160d81b60206040516104dd8161123b565b60058152015251902060405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f4488c40da75f747650ea253102292d50b0c3f0c34fc80e9620d8c9efafb9094e60408201527f967e55b836baa81f8a8590db04c7d2845cce2aa2b174a806a020b0c3cfcc763460608201524660808201523060a082015260a081526105768161121f565b5190209060405190602082019261190160f01b845260228301526042820152604281526105a281611203565b5190206024358103610c6657506105ce6105c66084356064356044356024356114c0565b91909161154f565b7f8cbf19ed556a3e128df9c72e5dce5e834043d6d77187038226aec48c4119033483527f16e84d5fc59ca78ed52bf90afd136a46c4b52d34f370ac69613ffbf9b96bbf38602052604083209060018060a01b0316908160005260205260ff6040600020541615610c4e5750604051815161064c8183602086016112ea565b810190600080516020611703833981519152825260208160018060a01b039303019020541660405182516106848183602087016112ea565b8101907fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d7087188825260208160018060a01b03930301902054166040516370a0823160e01b8152336004820152602081602481865afa908115610bea578591610c1c575b506024600435013511610bf557604051636eb1769f60e11b8152336004820152306024820152602081604481865afa908115610bea578591610bb3575b506024600435013511610b80576040516323b872dd60e01b60208201908152336024808401919091526001600160a01b039390931660448301526004359092013560648083019190915281526107ed92909185908190610783608486611257565b604051946107908661123b565b602086527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65646020870152519082855af13d15610b78573d916107d183611279565b926107df6040519485611257565b83523d87602085013e611669565b805180610afb575b505060405160208101906020825261082281610814604082018661130d565b03601f198101835282611257565b5190203360009081527ff99f5a59dae478b454da96b28b027339f1f555cd7d66f9ae4c949b5abb157d3f6020526040902060043560a40135905560018060a01b0360015416604051835161087a8183602088016112ea565b810190600080516020611703833981519152825260208160018060a01b0393030190205416600460206040519285828501528184526108b88461123b565b60405163313ce56760e01b815292839182905afa8015610af0578690610aaf575b60ff91501690604d8211610a9b5781600a0a15610a875790829186933b15610a83576109429284928360405180968195829463731133e960e01b84523360048501528b6024850152600a0a6024600435013504604484015260806064840152608483019061130d565b03925af18015610a7857610a60575b507f8511384efa543c4c9f6cbba3d34a2fc2df4f9490df6b476af3bffa137bd7fe4b610a408484604051602081845161098d81838589016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d48152030190206109c7602460043501358254611387565b905560405160208184516109de81838589016112ea565b81017f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c6710815203019020336000526020526040600020610a24602460043501358254611387565b905560405192839233845260a0602085015260a084019061130d565b90602460043501356040840152602435606084015260808301520390a180f35b610a69906111ef565b610a74578238610951565b8280fd5b6040513d84823e3d90fd5b8380fd5b634e487b7160e01b86526012600452602486fd5b634e487b7160e01b86526011600452602486fd5b506020813d602011610ae8575b81610ac960209383611257565b81010312610ae4575160ff81168103610ae45760ff906108d9565b8580fd5b3d9150610abc565b6040513d88823e3d90fd5b8160209181010312610a745760200151801590811503610a7457610b205738806107f5565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b606091611669565b60405163892e773960e01b81523360048083019190915230602480840191909152903501356044820152606490fd5b0390fd5b90506020813d602011610be2575b81610bce60209383611257565b81010312610bdd575138610722565b600080fd5b3d9150610bc1565b6040513d87823e3d90fd5b60405163aff6db1560e01b8152336004808301919091526024903581013590820152604490fd5b90506020813d602011610c46575b81610c3760209383611257565b81010312610bdd5751386106e5565b3d9150610c2a565b602490604051906333ffff9b60e01b82526004820152fd5b60449060405190633bae936760e21b825260048201526024356024820152fd5b634e487b7160e01b600052604160045260246000fd5b60405163f0152bdf60e01b81526004808201929092529035602490810135908201526044810191909152606490fd5b610baf90604051918291631f5dfbcb60e11b835260446004350135906024600435013590600485016040919493926060820195825260208201520152565b610d2e9060405191829163251061ff60e01b835260406004840152604483019061130d565b4260248301520390fd5b905042111538610239565b6040516344b4eea960e01b8152908190610baf903360048401611365565b905060016040518351610d788183602088016112ea565b8101928352602081838060a01b039403019020015460081c163314386101a3565b60449060405190639fba672f60e01b82524660048301526024820152fd5b604051637813445960e01b815260206004820152908190610baf90602483019061130d565b604051633ed482bf60e11b8152336004820152602490fd5b60405163451445c960e11b81523360048083019190915235608401356024820152604490fd5b604051632b6069a960e01b8152336004808301919091523560a401356024820152604490fd5b80fd5b5080fd5b5034610e4057602080600319360112610e435767ffffffffffffffff600435818111610a8357610e7b9036906004016112cc565b610e84816113aa565b156111cc5760405191815192600185840194610ea18184886112ea565b820191868160008051602061170383398151915294858152030190200154468103610d99575060ff60405186818651610edb81838b6112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d5815203019020541660038110156111b85760010361119657604051938351610f278187846112ea565b85019486817f972e751fecad8f52768758def61f99dbe3674f22c8ddd85dd7a19aa7814c67109788815203019020338852865260408720541561117a57600160405187818751610f788183886112ea565b81018981520301902001338852865260ff60408820541661115e579085929161104f84604051928751610fac8186846112ea565b84017fa8f64ad630c534f80721a435710c22b3ca51ebc098919499ff8c9a74d708718881528460018060a01b0398899687930301902054169460405183818b51610ff78183886112ea565b81018d815203019020338d528352600160408d20549a8460405180928d5161102081848a6112ea565b82019081520301902001338d52835260408c20600160ff19825416179055604051809481938b519283916112ea565b82019081520301902054166040519260408401908482109082111761114a579088939291604052338352878301878152823b1561114657606492859160405197889687956318c0bbe560e01b87526004870152511660248501525160448401525af18015610bea57611108575b50916060916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294604051948594338652850152606084019061130d565b9060408301520390a180f35b916110fc7f030163c67b9a119f93c825d413b9507242db884bdf30cfe31325b83d848dd9f294929561113b6060956111ef565b9592945050916110bc565b8480fd5b634e487b7160e01b89526041600452602489fd5b604051635f37987760e11b815280610baf863360048401611365565b604051637976c6f960e11b815280610baf863360048401611365565b604051630f22dbc360e11b81526004810186905280610baf602482018661130d565b634e487b7160e01b87526021600452602487fd5b82610baf604051928392637813445960e01b84526004840152602483019061130d565b67ffffffffffffffff8111610c8657604052565b6080810190811067ffffffffffffffff821117610c8657604052565b60c0810190811067ffffffffffffffff821117610c8657604052565b6040810190811067ffffffffffffffff821117610c8657604052565b90601f8019910116810190811067ffffffffffffffff821117610c8657604052565b67ffffffffffffffff8111610c8657601f01601f191660200190565b9291926112a182611279565b916112af6040519384611257565b829481845281830111610bdd578281602093846000960137010152565b9080601f83011215610bdd578160206112e793359101611295565b90565b60005b8381106112fd5750506000910152565b81810151838201526020016112ed565b90602091611326815180928185528580860191016112ea565b601f01601f1916010190565b903590601e1981360301821215610bdd570180359067ffffffffffffffff8211610bdd57602001918136038313610bdd57565b6001600160a01b0390911681526040602082018190526112e79291019061130d565b9190820180921161139457565b634e487b7160e01b600052601160045260246000fd5b9060405182818094516113c381602097888096016112ea565b81017fcb6c47b3daa6db10ae5e4ec1cf9f8100d11f82b57c506d550c00ec86c5cce1d28152030190209160405190600084549460018660011c91600188169788156114b6575b85841089146114a257869798848897985290816000146114805750600114611441575b50505061143b92500382611257565b51151590565b600090815285812095935091905b81831061146857505061143b935082010138808061142c565b8554878401850152948501948694509183019161144f565b9250505061143b94925060ff191682840152151560051b82010138808061142c565b634e487b7160e01b85526022600452602485fd5b92607f1692611409565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116115435791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156115365781516001600160a01b03811615611530579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b600581101561165357806115605750565b600181036115ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036115fa5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461160357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b919290156116cb575081511561167d575090565b3b156116865790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156116de5750805190602001fd5b60405162461bcd60e51b815260206004820152908190610baf90602483019061130d56fe2b1fc81139dd17ad3c1801c783e31f497c37ee7d1bfea80d7d4940b0aa2775b6a2646970667358221220701817dc17242236c5514825f327f43216cde64061064f6407b810aafd31c8f764736f6c63430008190033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.