ETH Price: $2,295.40 (-0.91%)
Gas: 1.82 Gwei

Contract

0x60Da568b88037d0735715819a37714d28BD56347
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x61192761144431962022-03-23 14:52:35908 days ago1648047155IN
 Create: NFTfiSigningUtils
0 ETH0.0577617240

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NFTfiSigningUtils

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 100 runs

Other Settings:
default evmVersion
File 1 of 8 : NFTfiSigningUtils.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.4;

import "../interfaces/IBundleBuilder.sol";
import "../loans/direct/loanTypes/LoanData.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

/**
 * @title  NFTfiSigningUtils
 * @author NFTfi
 * @notice Helper contract for NFTfi. This contract manages verifying signatures from off-chain NFTfi orders.
 * Based on the version of this same contract used on NFTfi V1
 */
library NFTfiSigningUtils {
    /* ********* */
    /* FUNCTIONS */
    /* ********* */

    /**
     * @dev This function gets the current chain ID.
     */
    function getChainID() public view returns (uint256) {
        uint256 id;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            id := chainid()
        }
        return id;
    }

    /**
     * @notice This function is when the lender accepts a borrower's binding listing terms, to validate the lender's
     * signature that the borrower provided off-chain to verify that it did indeed made such listing.
     *
     * @param _listingTerms - The listing terms struct containing:
     * - loanERC20Denomination: The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * - minLoanPrincipalAmount: The minumum sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maxLoanPrincipalAmount: The  sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maximumRepaymentAmount: The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * - nftCollateralContract: The address of the ERC721 contract of the NFT collateral.
     * - nftCollateralId: The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * - revenueSharePartner: The address of the partner that will receive the revenue share.
     * - minLoanDuration: The minumum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * - maxLoanDuration: The maximum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * - maxInterestRateForDurationInBasisPoints: This is maximum the interest rate (measured in basis points, e.g.
     * hundreths of a percent) for the loan, that must be repaid pro-rata by the borrower at the conclusion of the loan
     * or risk seizure of their nft collateral. Note if the type of the loan is fixed then this value  is not used and
     * is irrelevant so it should be set to 0.
     * - referralFeeInBasisPoints: The percent (measured in basis points) of the loan principal amount that will be
     * taken as a fee to pay to the referrer, 0 if the lender is not paying referral fee.
     * @param _signature - The offer struct containing:
     * - signer: The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * - nonce: The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     *   - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     *   - Second, it allows a user to cancel an off-chain order by calling
     * NFTfi.cancelLoanCommitmentBeforeLoanHasBegun(), which marks the nonce as used and prevents any future loan from
     * using the user's off-chain order that contains that nonce.
     * - expiry: Date when the signature expires
     * - signature: The ECDSA signature of the borrower, obtained off-chain ahead of time, signing the following
     * combination of parameters:
     *   - listingTerms.loanERC20Denomination,
     *   - listingTerms.minLoanPrincipalAmount,
     *   - listingTerms.maxLoanPrincipalAmount,
     *   - listingTerms.nftCollateralContract,
     *   - listingTerms.nftCollateralId,
     *   - listingTerms.revenueSharePartner,
     *   - listingTerms.minLoanDuration,
     *   - listingTerms.maxLoanDuration,
     *   - listingTerms.maxInterestRateForDurationInBasisPoints,
     *   - listingTerms.referralFeeInBasisPoints,
     *   - signature.signer,
     *   - signature.nonce,
     *   - signature.expiry,
     *   - address of this contract
     *   - chainId
     */
    function isValidBorrowerSignature(LoanData.ListingTerms memory _listingTerms, LoanData.Signature memory _signature)
        external
        view
        returns (bool)
    {
        return isValidBorrowerSignature(_listingTerms, _signature, address(this));
    }

    /**
     * @dev This function overload the previous function to allow the caller to specify the address of the contract
     *
     */
    function isValidBorrowerSignature(
        LoanData.ListingTerms memory _listingTerms,
        LoanData.Signature memory _signature,
        address _loanContract
    ) public view returns (bool) {
        require(block.timestamp <= _signature.expiry, "Borrower Signature has expired");
        require(_loanContract != address(0), "Loan is zero address");
        if (_signature.signer == address(0)) {
            return false;
        } else {
            bytes32 message = keccak256(
                abi.encodePacked(
                    getEncodedListing(_listingTerms),
                    getEncodedSignature(_signature),
                    _loanContract,
                    getChainID()
                )
            );

            return
                SignatureChecker.isValidSignatureNow(
                    _signature.signer,
                    ECDSA.toEthSignedMessageHash(message),
                    _signature.signature
                );
        }
    }

    /**
     * @notice This function is when the lender accepts a borrower's binding listing terms, to validate the lender's
     * signature that the borrower provided off-chain to verify that it did indeed made such listing.
     *
     * @param _listingTerms - The listing terms struct containing:
     * - loanERC20Denomination: The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * - minLoanPrincipalAmount: The minumum sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maxLoanPrincipalAmount: The  sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maximumRepaymentAmount: The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * - nftCollateralContract: The address of the ERC721 contract of the NFT collateral.
     * - nftCollateralId: The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * - revenueSharePartner: The address of the partner that will receive the revenue share.
     * - minLoanDuration: The minumum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * - maxLoanDuration: The maximum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * - maxInterestRateForDurationInBasisPoints: This is maximum the interest rate (measured in basis points, e.g.
     * hundreths of a percent) for the loan, that must be repaid pro-rata by the borrower at the conclusion of the loan
     * or risk seizure of their nft collateral. Note if the type of the loan is fixed then this value  is not used and
     * is irrelevant so it should be set to 0.
     * - referralFeeInBasisPoints: The percent (measured in basis points) of the loan principal amount that will be
     * taken as a fee to pay to the referrer, 0 if the lender is not paying referral fee.
     * @param _bundleElements - the lists of erc721-20-1155 tokens that are to be bundled
     * @param _signature - The offer struct containing:
     * - signer: The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * - nonce: The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     *   - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     *   - Second, it allows a user to cancel an off-chain order by calling
     * NFTfi.cancelLoanCommitmentBeforeLoanHasBegun(), which marks the nonce as used and prevents any future loan from
     * using the user's off-chain order that contains that nonce.
     * - expiry: Date when the signature expires
     * - signature: The ECDSA signature of the borrower, obtained off-chain ahead of time, signing the following
     * combination of parameters:
     *   - listingTerms.loanERC20Denomination,
     *   - listingTerms.minLoanPrincipalAmount,
     *   - listingTerms.maxLoanPrincipalAmount,
     *   - listingTerms.nftCollateralContract,
     *   - listingTerms.nftCollateralId,
     *   - listingTerms.revenueSharePartner,
     *   - listingTerms.minLoanDuration,
     *   - listingTerms.maxLoanDuration,
     *   - listingTerms.maxInterestRateForDurationInBasisPoints,
     *   - listingTerms.referralFeeInBasisPoints,
     *   - bundleElements
     *   - signature.signer,
     *   - signature.nonce,
     *   - signature.expiry,
     *   - address of this contract
     *   - chainId
     */
    function isValidBorrowerSignatureBundle(
        LoanData.ListingTerms memory _listingTerms,
        IBundleBuilder.BundleElements memory _bundleElements,
        LoanData.Signature memory _signature
    ) external view returns (bool) {
        return isValidBorrowerSignatureBundle(_listingTerms, _bundleElements, _signature, address(this));
    }

    /**
     * @dev This function overload the previous function to allow the caller to specify the address of the contract
     *
     */
    function isValidBorrowerSignatureBundle(
        LoanData.ListingTerms memory _listingTerms,
        IBundleBuilder.BundleElements memory _bundleElements,
        LoanData.Signature memory _signature,
        address _loanContract
    ) public view returns (bool) {
        require(block.timestamp <= _signature.expiry, "Borrower Signature has expired");
        require(_loanContract != address(0), "Loan is zero address");
        if (_signature.signer == address(0)) {
            return false;
        } else {
            bytes32 message = keccak256(
                abi.encodePacked(
                    getEncodedListing(_listingTerms),
                    abi.encode(_bundleElements),
                    getEncodedSignature(_signature),
                    _loanContract,
                    getChainID()
                )
            );

            return
                SignatureChecker.isValidSignatureNow(
                    _signature.signer,
                    ECDSA.toEthSignedMessageHash(message),
                    _signature.signature
                );
        }
    }

    /**
     * @notice This function is when the borrower accepts a lender's offer, to validate the lender's signature that the
     * lender provided off-chain to verify that it did indeed made such offer.
     *
     * @param _offer - The offer struct containing:
     * - loanERC20Denomination: The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * - loanPrincipalAmount: The original sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maximumRepaymentAmount: The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * - nftCollateralContract: The address of the ERC721 contract of the NFT collateral.
     * - nftCollateralId: The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * - referrer: The address of the referrer who found the lender matching the listing, Zero address to signal
     * this there is no referrer.
     * - loanDuration: The amount of time (measured in seconds) that can elapse before the lender can liquidate the
     * loan and seize the underlying collateral NFT.
     * - loanInterestRateForDurationInBasisPoints: This is the interest rate (measured in basis points, e.g.
     * hundreths of a percent) for the loan, that must be repaid pro-rata by the borrower at the conclusion of the loan
     * or risk seizure of their nft collateral. Note if the type of the loan is fixed then this value  is not used and
     * is irrelevant so it should be set to 0.
     * - loanAdminFeeInBasisPoints: The percent (measured in basis points) of the interest earned that will be
     * taken as a fee by the contract admins when the loan is repaid. The fee is stored in the loan struct to prevent an
     * attack where the contract admins could adjust the fee right before a loan is repaid, and take all of the interest
     * earned.
     * @param _signature - The signature structure containing:
     * - signer: The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * - nonce: The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     *   - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     *   - Second, it allows a user to cancel an off-chain order by calling
     * NFTfi.cancelLoanCommitmentBeforeLoanHasBegun(), which marks the nonce as used and prevents any future loan from
     * using the user's off-chain order that contains that nonce.
     * - expiry: Date when the signature expires
     * - signature: The ECDSA signature of the lender, obtained off-chain ahead of time, signing the following
     * combination of parameters:
     *   - offer.loanERC20Denomination
     *   - offer.loanPrincipalAmount
     *   - offer.maximumRepaymentAmount
     *   - offer.nftCollateralContract
     *   - offer.nftCollateralId
     *   - offer.referrer
     *   - offer.loanDuration
     *   - offer.loanAdminFeeInBasisPoints
     *   - signature.signer,
     *   - signature.nonce,
     *   - signature.expiry,
     *   - address of this contract
     *   - chainId
     */
    function isValidLenderSignature(LoanData.Offer memory _offer, LoanData.Signature memory _signature)
        external
        view
        returns (bool)
    {
        return isValidLenderSignature(_offer, _signature, address(this));
    }

    /**
     * @dev This function overload the previous function to allow the caller to specify the address of the contract
     *
     */
    function isValidLenderSignature(
        LoanData.Offer memory _offer,
        LoanData.Signature memory _signature,
        address _loanContract
    ) public view returns (bool) {
        require(block.timestamp <= _signature.expiry, "Lender Signature has expired");
        require(_loanContract != address(0), "Loan is zero address");
        if (_signature.signer == address(0)) {
            return false;
        } else {
            bytes32 message = keccak256(
                abi.encodePacked(getEncodedOffer(_offer), getEncodedSignature(_signature), _loanContract, getChainID())
            );

            return
                SignatureChecker.isValidSignatureNow(
                    _signature.signer,
                    ECDSA.toEthSignedMessageHash(message),
                    _signature.signature
                );
        }
    }

    /**
     * @notice This function is when the borrower accepts a lender's offer, to validate the lender's signature that the
     * lender provided off-chain to verify that it did indeed made such offer.
     *
     * @param _offer - The offer struct containing:
     * - loanERC20Denomination: The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * - loanPrincipalAmount: The original sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * - maximumRepaymentAmount: The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * - nftCollateralContract: The address of the ERC721 contract of the NFT collateral.
     * - nftCollateralId: The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * - referrer: The address of the referrer who found the lender matching the listing, Zero address to signal
     * this there is no referrer.
     * - loanDuration: The amount of time (measured in seconds) that can elapse before the lender can liquidate the
     * loan and seize the underlying collateral NFT.
     * - loanInterestRateForDurationInBasisPoints: This is the interest rate (measured in basis points, e.g.
     * hundreths of a percent) for the loan, that must be repaid pro-rata by the borrower at the conclusion of the loan
     * or risk seizure of their nft collateral. Note if the type of the loan is fixed then this value  is not used and
     * is irrelevant so it should be set to 0.
     * - loanAdminFeeInBasisPoints: The percent (measured in basis points) of the interest earned that will be
     * taken as a fee by the contract admins when the loan is repaid. The fee is stored in the loan struct to prevent an
     * attack where the contract admins could adjust the fee right before a loan is repaid, and take all of the interest
     * earned.
     * @param _bundleElements - the lists of erc721-20-1155 tokens that are to be bundled
     * @param _signature - The signature structure containing:
     * - signer: The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * - nonce: The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     *   - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     *   - Second, it allows a user to cancel an off-chain order by calling
     * NFTfi.cancelLoanCommitmentBeforeLoanHasBegun(), which marks the nonce as used and prevents any future loan from
     * using the user's off-chain order that contains that nonce.
     * - expiry: Date when the signature expires
     * - signature: The ECDSA signature of the lender, obtained off-chain ahead of time, signing the following
     * combination of parameters:
     *   - offer.loanERC20Denomination
     *   - offer.loanPrincipalAmount
     *   - offer.maximumRepaymentAmount
     *   - offer.nftCollateralContract
     *   - offer.nftCollateralId
     *   - offer.referrer
     *   - offer.loanDuration
     *   - offer.loanAdminFeeInBasisPoints
     *   - bundleElements
     *   - signature.signer,
     *   - signature.nonce,
     *   - signature.expiry,
     *   - address of this contract
     *   - chainId
     */
    function isValidLenderSignatureBundle(
        LoanData.Offer memory _offer,
        IBundleBuilder.BundleElements memory _bundleElements,
        LoanData.Signature memory _signature
    ) external view returns (bool) {
        return isValidLenderSignatureBundle(_offer, _bundleElements, _signature, address(this));
    }

    /**
     * @dev This function overload the previous function to allow the caller to specify the address of the contract
     *
     */
    function isValidLenderSignatureBundle(
        LoanData.Offer memory _offer,
        IBundleBuilder.BundleElements memory _bundleElements,
        LoanData.Signature memory _signature,
        address _loanContract
    ) public view returns (bool) {
        require(block.timestamp <= _signature.expiry, "Lender Signature has expired");
        require(_loanContract != address(0), "Loan is zero address");
        if (_signature.signer == address(0)) {
            return false;
        } else {
            bytes32 message = keccak256(
                abi.encodePacked(
                    getEncodedOffer(_offer),
                    abi.encode(_bundleElements),
                    getEncodedSignature(_signature),
                    _loanContract,
                    getChainID()
                )
            );

            return
                SignatureChecker.isValidSignatureNow(
                    _signature.signer,
                    ECDSA.toEthSignedMessageHash(message),
                    _signature.signature
                );
        }
    }

    /**
     * @notice This function is called in renegotiateLoan() to validate the lender's signature that the lender provided
     * off-chain to verify that they did indeed want to agree to this loan renegotiation according to these terms.
     *
     * @param _loanId - The unique identifier for the loan to be renegotiated
     * @param _newLoanDuration - The new amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * @param _newMaximumRepaymentAmount - The new maximum amount of money that the borrower would be required to
     * retrieve their collateral, measured in the smallest units of the ERC20 currency used for the loan. The
     * borrower will always have to pay this amount to retrieve their collateral, regardless of whether they repay
     * early.
     * @param _renegotiationFee Agreed upon fee in ether that borrower pays for the lender for the renegitiation
     * @param _signature - The signature structure containing:
     * - signer: The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * - nonce: The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     * - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     * - Second, it allows a user to cancel an off-chain order by calling NFTfi.cancelLoanCommitmentBeforeLoanHasBegun()
     * , which marks the nonce as used and prevents any future loan from using the user's off-chain order that contains
     * that nonce.
     * - expiry - The date when the renegotiation offer expires
     * - lenderSignature - The ECDSA signature of the lender, obtained off-chain ahead of time, signing the
     * following combination of parameters:
     * - _loanId
     * - _newLoanDuration
     * - _newMaximumRepaymentAmount
     * - _lender
     * - _lenderNonce
     * - _expiry
     * - address of this contract
     * - chainId
     */
    function isValidLenderRenegotiationSignature(
        uint256 _loanId,
        uint32 _newLoanDuration,
        uint256 _newMaximumRepaymentAmount,
        uint256 _renegotiationFee,
        LoanData.Signature memory _signature
    ) external view returns (bool) {
        return
            isValidLenderRenegotiationSignature(
                _loanId,
                _newLoanDuration,
                _newMaximumRepaymentAmount,
                _renegotiationFee,
                _signature,
                address(this)
            );
    }

    /**
     * @dev This function overload the previous function to allow the caller to specify the address of the contract
     *
     */
    function isValidLenderRenegotiationSignature(
        uint256 _loanId,
        uint32 _newLoanDuration,
        uint256 _newMaximumRepaymentAmount,
        uint256 _renegotiationFee,
        LoanData.Signature memory _signature,
        address _loanContract
    ) public view returns (bool) {
        require(block.timestamp <= _signature.expiry, "Renegotiation Signature has expired");
        require(_loanContract != address(0), "Loan is zero address");
        if (_signature.signer == address(0)) {
            return false;
        } else {
            bytes32 message = keccak256(
                abi.encodePacked(
                    _loanId,
                    _newLoanDuration,
                    _newMaximumRepaymentAmount,
                    _renegotiationFee,
                    getEncodedSignature(_signature),
                    _loanContract,
                    getChainID()
                )
            );

            return
                SignatureChecker.isValidSignatureNow(
                    _signature.signer,
                    ECDSA.toEthSignedMessageHash(message),
                    _signature.signature
                );
        }
    }

    /**
     * @dev We need this to avoid stack too deep errors.
     */
    function getEncodedListing(LoanData.ListingTerms memory _listingTerms) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                _listingTerms.loanERC20Denomination,
                _listingTerms.minLoanPrincipalAmount,
                _listingTerms.maxLoanPrincipalAmount,
                _listingTerms.nftCollateralContract,
                _listingTerms.nftCollateralId,
                _listingTerms.revenueSharePartner,
                _listingTerms.minLoanDuration,
                _listingTerms.maxLoanDuration,
                _listingTerms.maxInterestRateForDurationInBasisPoints,
                _listingTerms.referralFeeInBasisPoints
            );
    }

    /**
     * @dev We need this to avoid stack too deep errors.
     */
    function getEncodedOffer(LoanData.Offer memory _offer) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                _offer.loanERC20Denomination,
                _offer.loanPrincipalAmount,
                _offer.maximumRepaymentAmount,
                _offer.nftCollateralContract,
                _offer.nftCollateralId,
                _offer.referrer,
                _offer.loanDuration,
                _offer.loanAdminFeeInBasisPoints
            );
    }

    /**
     * @dev We need this to avoid stack too deep errors.
     */
    function getEncodedSignature(LoanData.Signature memory _signature) internal pure returns (bytes memory) {
        return abi.encodePacked(_signature.signer, _signature.nonce, _signature.expiry);
    }
}

File 2 of 8 : IBundleBuilder.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.4;

interface IBundleBuilder {
    /**
     * @notice data of a erc721 bundle element
     *
     * @param tokenContract - address of the token contract
     * @param id - id of the token
     * @param safeTransferable - wether the implementing token contract has a safeTransfer function or not
     */
    struct BundleElementERC721 {
        address tokenContract;
        uint256 id;
        bool safeTransferable;
    }

    /**
     * @notice data of a erc20 bundle element
     *
     * @param tokenContract - address of the token contract
     * @param amount - amount of the token
     */
    struct BundleElementERC20 {
        address tokenContract;
        uint256 amount;
    }

    /**
     * @notice data of a erc20 bundle element
     *
     * @param tokenContract - address of the token contract
     * @param ids - list of ids of the tokens
     * @param amounts - list amounts of the tokens
     */
    struct BundleElementERC1155 {
        address tokenContract;
        uint256[] ids;
        uint256[] amounts;
    }

    /**
     * @notice the lists of erc721-20-1155 tokens that are to be bundled
     *
     * @param erc721s list of erc721 tokens
     * @param erc20s list of erc20 tokens
     * @param erc1155s list of erc1155 tokens
     */
    struct BundleElements {
        BundleElementERC721[] erc721s;
        BundleElementERC20[] erc20s;
        BundleElementERC1155[] erc1155s;
    }

    /**
     * @notice used by the loan contract to build a bundle from the BundleElements struct at the beginning of a loan,
     * returns the id of the created bundle
     *
     * @param _bundleElements - the lists of erc721-20-1155 tokens that are to be bundled
     * @param _sender sender of the tokens in the bundle - the borrower
     * @param _receiver receiver of the created bundle, normally the loan contract
     */
    function buildBundle(
        BundleElements memory _bundleElements,
        address _sender,
        address _receiver
    ) external returns (uint256);

    /**
     * @notice Remove all the children from the bundle
     * @dev This method may run out of gas if the list of children is too big. In that case, children can be removed
     *      individually.
     * @param _tokenId the id of the bundle
     * @param _receiver address of the receiver of the children
     */
    function decomposeBundle(uint256 _tokenId, address _receiver) external;
}

File 3 of 8 : LoanData.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.4;

/**
 * @title  LoanData
 * @author NFTfi
 * @notice An interface containg the main Loan struct shared by Direct Loans types.
 */
interface LoanData {
    /* ********** */
    /* DATA TYPES */
    /* ********** */

    /**
     * @notice The main Loan Terms struct. This data is saved upon loan creation.
     *
     * @param loanERC20Denomination - The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * @param loanPrincipalAmount - The original sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * @param maximumRepaymentAmount - The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * @param nftCollateralContract - The address of the the NFT collateral contract.
     * @param nftCollateralWrapper - The NFTfi wrapper of the NFT collateral contract.
     * @param nftCollateralId - The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * @param loanStartTime - The block.timestamp when the loan first began (measured in seconds).
     * @param loanDuration - The amount of time (measured in seconds) that can elapse before the lender can liquidate
     * the loan and seize the underlying collateral NFT.
     * @param loanInterestRateForDurationInBasisPoints - This is the interest rate (measured in basis points, e.g.
     * hundreths of a percent) for the loan, that must be repaid pro-rata by the borrower at the conclusion of the loan
     * or risk seizure of their nft collateral. Note if the type of the loan is fixed then this value  is not used and
     * is irrelevant so it should be set to 0.
     * @param loanAdminFeeInBasisPoints - The percent (measured in basis points) of the interest earned that will be
     * taken as a fee by the contract admins when the loan is repaid. The fee is stored in the loan struct to prevent an
     * attack where the contract admins could adjust the fee right before a loan is repaid, and take all of the interest
     * earned.
     * @param borrower
     */
    struct LoanTerms {
        uint256 loanPrincipalAmount;
        uint256 maximumRepaymentAmount;
        uint256 nftCollateralId;
        address loanERC20Denomination;
        uint32 loanDuration;
        uint16 loanInterestRateForDurationInBasisPoints;
        uint16 loanAdminFeeInBasisPoints;
        address nftCollateralWrapper;
        uint64 loanStartTime;
        address nftCollateralContract;
        address borrower;
    }

    /**
     * @notice Some extra Loan's settings struct. This data is saved upon loan creation.
     * We need this to avoid stack too deep errors.
     *
     * @param revenueSharePartner - The address of the partner that will receive the revenue share.
     * @param revenueShareInBasisPoints - The percent (measured in basis points) of the admin fee amount that will be
     * taken as a revenue share for a t
     * @param referralFeeInBasisPoints - The percent (measured in basis points) of the loan principal amount that will
     * be taken as a fee to pay to the referrer, 0 if the lender is not paying referral fee.he partner, at the moment
     * the loan is begun.
     */
    struct LoanExtras {
        address revenueSharePartner;
        uint16 revenueShareInBasisPoints;
        uint16 referralFeeInBasisPoints;
    }

    /**
     * @notice The offer made by the lender. Used as parameter on both acceptOffer (initiated by the borrower) and
     * acceptListing (initiated by the lender).
     *
     * @param loanERC20Denomination - The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * @param loanPrincipalAmount - The original sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * @param maximumRepaymentAmount - The maximum amount of money that the borrower would be required to retrieve their
     *  collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always
     * have to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * @param nftCollateralContract - The address of the ERC721 contract of the NFT collateral.
     * @param nftCollateralId - The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * @param referrer - The address of the referrer who found the lender matching the listing, Zero address to signal
     * this there is no referrer.
     * @param loanDuration - The amount of time (measured in seconds) that can elapse before the lender can liquidate
     * the loan and seize the underlying collateral NFT.
     * @param loanAdminFeeInBasisPoints - The percent (measured in basis points) of the interest earned that will be
     * taken as a fee by the contract admins when the loan is repaid. The fee is stored in the loan struct to prevent an
     * attack where the contract admins could adjust the fee right before a loan is repaid, and take all of the interest
     * earned.
     */
    struct Offer {
        uint256 loanPrincipalAmount;
        uint256 maximumRepaymentAmount;
        uint256 nftCollateralId;
        address nftCollateralContract;
        uint32 loanDuration;
        uint16 loanAdminFeeInBasisPoints;
        address loanERC20Denomination;
        address referrer;
    }

    /**
     * @notice Signature related params. Used as parameter on both acceptOffer (containing borrower signature) and
     * acceptListing (containing lender signature).
     *
     * @param signer - The address of the signer. The borrower for `acceptOffer` the lender for `acceptListing`.
     * @param nonce - The nonce referred here is not the same as an Ethereum account's nonce.
     * We are referring instead to a nonce that is used by the lender or the borrower when they are first signing
     * off-chain NFTfi orders. These nonce can be any uint256 value that the user has not previously used to sign an
     * off-chain order. Each nonce can be used at most once per user within NFTfi, regardless of whether they are the
     * lender or the borrower in that situation. This serves two purposes:
     * - First, it prevents replay attacks where an attacker would submit a user's off-chain order more than once.
     * - Second, it allows a user to cancel an off-chain order by calling NFTfi.cancelLoanCommitmentBeforeLoanHasBegun()
     * , which marks the nonce as used and prevents any future loan from using the user's off-chain order that contains
     * that nonce.
     * @param expiry - Date when the signature expires
     * @param signature - The ECDSA signature of the borrower or the lender, obtained off-chain ahead of time, signing
     * the following combination of parameters:
     * - Borrower
     *   - ListingTerms.loanERC20Denomination,
     *   - ListingTerms.minLoanPrincipalAmount,
     *   - ListingTerms.maxLoanPrincipalAmount,
     *   - ListingTerms.nftCollateralContract,
     *   - ListingTerms.nftCollateralId,
     *   - ListingTerms.revenueSharePartner,
     *   - ListingTerms.minLoanDuration,
     *   - ListingTerms.maxLoanDuration,
     *   - ListingTerms.maxInterestRateForDurationInBasisPoints,
     *   - ListingTerms.referralFeeInBasisPoints,
     *   - Signature.signer,
     *   - Signature.nonce,
     *   - Signature.expiry,
     *   - address of the loan type contract
     *   - chainId
     * - Lender:
     *   - Offer.loanERC20Denomination
     *   - Offer.loanPrincipalAmount
     *   - Offer.maximumRepaymentAmount
     *   - Offer.nftCollateralContract
     *   - Offer.nftCollateralId
     *   - Offer.referrer
     *   - Offer.loanDuration
     *   - Offer.loanAdminFeeInBasisPoints
     *   - Signature.signer,
     *   - Signature.nonce,
     *   - Signature.expiry,
     *   - address of the loan type contract
     *   - chainId
     */
    struct Signature {
        uint256 nonce;
        uint256 expiry;
        address signer;
        bytes signature;
    }

    /**
     * @notice Some extra parameters that the borrower needs to set when accepting an offer.
     *
     * @param revenueSharePartner - The address of the partner that will receive the revenue share.
     * @param referralFeeInBasisPoints - The percent (measured in basis points) of the loan principal amount that will
     * be taken as a fee to pay to the referrer, 0 if the lender is not paying referral fee.
     */
    struct BorrowerSettings {
        address revenueSharePartner;
        uint16 referralFeeInBasisPoints;
    }

    /**
     * @notice Terms the borrower set off-chain and is willing to accept automatically when fulfiled by a lender's
     * offer.
     *
     * @param loanERC20Denomination - The address of the ERC20 contract of the currency being used as principal/interest
     * for this loan.
     * @param minLoanPrincipalAmount - The minumum sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * @param maxLoanPrincipalAmount - The  sum of money transferred from lender to borrower at the beginning of
     * the loan, measured in loanERC20Denomination's smallest units.
     * @param maximumRepaymentAmount - The maximum amount of money that the borrower would be required to retrieve their
     * collateral, measured in the smallest units of the ERC20 currency used for the loan. The borrower will always have
     * to pay this amount to retrieve their collateral, regardless of whether they repay early.
     * @param nftCollateralContract - The address of the ERC721 contract of the NFT collateral.
     * @param nftCollateralId - The ID within the NFTCollateralContract for the NFT being used as collateral for this
     * loan. The NFT is stored within this contract during the duration of the loan.
     * @param revenueSharePartner - The address of the partner that will receive the revenue share.
     * @param minLoanDuration - The minumum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * @param maxLoanDuration - The maximum amount of time (measured in seconds) that can elapse before the lender can
     * liquidate the loan and seize the underlying collateral NFT.
     * @param maxInterestRateForDurationInBasisPoints - This is maximum the interest rate (measured in basis points,
     * e.g. hundreths of a percent) for the loan.
     * @param referralFeeInBasisPoints - The percent (measured in basis points) of the loan principal amount that will
     * be taken as a fee to pay to the referrer, 0 if the lender is not paying referral fee.
     */
    struct ListingTerms {
        uint256 minLoanPrincipalAmount;
        uint256 maxLoanPrincipalAmount;
        uint256 nftCollateralId;
        address nftCollateralContract;
        uint32 minLoanDuration;
        uint32 maxLoanDuration;
        uint16 maxInterestRateForDurationInBasisPoints;
        uint16 referralFeeInBasisPoints;
        address revenueSharePartner;
        address loanERC20Denomination;
    }
}

File 4 of 8 : SignatureChecker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.0;

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

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

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

File 5 of 8 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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
    }

    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");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' 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) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        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.
            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 if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } 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 (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

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

        return (signer, RecoverError.NoError);
    }

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

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

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

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

File 6 of 8 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

pragma solidity ^0.8.0;

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

File 8 of 8 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

Settings
{
  "metadata": {
    "bytecodeHash": "none",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"getChainID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"minLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maxLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"minLoanDuration","type":"uint32"},{"internalType":"uint32","name":"maxLoanDuration","type":"uint32"},{"internalType":"uint16","name":"maxInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"address","name":"loanERC20Denomination","type":"address"}],"internalType":"struct LoanData.ListingTerms","name":"_listingTerms","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"}],"name":"isValidBorrowerSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"minLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maxLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"minLoanDuration","type":"uint32"},{"internalType":"uint32","name":"maxLoanDuration","type":"uint32"},{"internalType":"uint16","name":"maxInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"address","name":"loanERC20Denomination","type":"address"}],"internalType":"struct LoanData.ListingTerms","name":"_listingTerms","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"},{"internalType":"address","name":"_loanContract","type":"address"}],"name":"isValidBorrowerSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"minLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maxLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"minLoanDuration","type":"uint32"},{"internalType":"uint32","name":"maxLoanDuration","type":"uint32"},{"internalType":"uint16","name":"maxInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"address","name":"loanERC20Denomination","type":"address"}],"internalType":"struct LoanData.ListingTerms","name":"_listingTerms","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"safeTransferable","type":"bool"}],"internalType":"struct IBundleBuilder.BundleElementERC721[]","name":"erc721s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBundleBuilder.BundleElementERC20[]","name":"erc20s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IBundleBuilder.BundleElementERC1155[]","name":"erc1155s","type":"tuple[]"}],"internalType":"struct IBundleBuilder.BundleElements","name":"_bundleElements","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"}],"name":"isValidBorrowerSignatureBundle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"minLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maxLoanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"minLoanDuration","type":"uint32"},{"internalType":"uint32","name":"maxLoanDuration","type":"uint32"},{"internalType":"uint16","name":"maxInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"address","name":"loanERC20Denomination","type":"address"}],"internalType":"struct LoanData.ListingTerms","name":"_listingTerms","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"safeTransferable","type":"bool"}],"internalType":"struct IBundleBuilder.BundleElementERC721[]","name":"erc721s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBundleBuilder.BundleElementERC20[]","name":"erc20s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IBundleBuilder.BundleElementERC1155[]","name":"erc1155s","type":"tuple[]"}],"internalType":"struct IBundleBuilder.BundleElements","name":"_bundleElements","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"},{"internalType":"address","name":"_loanContract","type":"address"}],"name":"isValidBorrowerSignatureBundle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_loanId","type":"uint256"},{"internalType":"uint32","name":"_newLoanDuration","type":"uint32"},{"internalType":"uint256","name":"_newMaximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"_renegotiationFee","type":"uint256"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"},{"internalType":"address","name":"_loanContract","type":"address"}],"name":"isValidLenderRenegotiationSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_loanId","type":"uint256"},{"internalType":"uint32","name":"_newLoanDuration","type":"uint32"},{"internalType":"uint256","name":"_newMaximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"_renegotiationFee","type":"uint256"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"}],"name":"isValidLenderRenegotiationSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"internalType":"struct LoanData.Offer","name":"_offer","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"},{"internalType":"address","name":"_loanContract","type":"address"}],"name":"isValidLenderSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"internalType":"struct LoanData.Offer","name":"_offer","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"}],"name":"isValidLenderSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"internalType":"struct LoanData.Offer","name":"_offer","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"safeTransferable","type":"bool"}],"internalType":"struct IBundleBuilder.BundleElementERC721[]","name":"erc721s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBundleBuilder.BundleElementERC20[]","name":"erc20s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IBundleBuilder.BundleElementERC1155[]","name":"erc1155s","type":"tuple[]"}],"internalType":"struct IBundleBuilder.BundleElements","name":"_bundleElements","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"},{"internalType":"address","name":"_loanContract","type":"address"}],"name":"isValidLenderSignatureBundle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"internalType":"struct LoanData.Offer","name":"_offer","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"safeTransferable","type":"bool"}],"internalType":"struct IBundleBuilder.BundleElementERC721[]","name":"erc721s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBundleBuilder.BundleElementERC20[]","name":"erc20s","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IBundleBuilder.BundleElementERC1155[]","name":"erc1155s","type":"tuple[]"}],"internalType":"struct IBundleBuilder.BundleElements","name":"_bundleElements","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct LoanData.Signature","name":"_signature","type":"tuple"}],"name":"isValidLenderSignatureBundle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

61192761003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100b35760003560e01c806387c0a5731161007b57806387c0a57314610127578063a819956e1461013a578063c42129211461014d578063d06ff74114610160578063eb2ac63f14610173578063fb7a322a1461018657600080fd5b80632eb68793146100b85780633ce5ed9f146100e05780634051a17a146100f3578063564b81ef146101065780636ab81ec014610114575b600080fd5b6100cb6100c6366004610fa8565b610199565b60405190151581526020015b60405180910390f35b6100cb6100ee36600461101c565b6101b1565b6100cb6101013660046110a2565b6102a9565b6040514681526020016100d7565b6100cb61012236600461125f565b6102b6565b6100cb61013536600461131d565b610376565b6100cb6101483660046111ac565b610476565b6100cb61015b3660046110f0565b6104e7565b6100cb61016e3660046112b5565b610558565b6100cb610181366004611227565b610568565b6100cb61019436600461114f565b610575565b60006101a7848484306101b1565b90505b9392505050565b600082602001514211156101e05760405162461bcd60e51b81526004016101d79061168e565b60405180910390fd5b6001600160a01b0382166102065760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b0316610220575060006102a1565b600061022b86610583565b8560405160200161023c919061172a565b604051602081830303815290604052610254866105e8565b854660405160200161026a95949392919061158e565b60405160208183030381529060405280519060200120905061029d84604001516102938361062b565b866060015161067e565b9150505b949350505050565b60006101aa8383306104e7565b600082602001514211156102dc5760405162461bcd60e51b81526004016101d7906116c5565b6001600160a01b0382166103025760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b031661031c575060006101aa565b6000610327856107d8565b610330856105e8565b84466040516020016103459493929190611543565b60405160208183030381529060405280519060200120905061036e84604001516102938361062b565b9150506101aa565b600082602001514211156103d85760405162461bcd60e51b815260206004820152602360248201527f52656e65676f74696174696f6e205369676e61747572652068617320657870696044820152621c995960ea1b60648201526084016101d7565b6001600160a01b0382166103fe5760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b03166104185750600061046c565b600087878787610427886105e8565b874660405160200161043f97969594939291906115ed565b60405160208183030381529060405280519060200120905061046884604001516102938361062b565b9150505b9695505050505050565b6000826020015142111561049c5760405162461bcd60e51b81526004016101d7906116c5565b6001600160a01b0382166104c25760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b03166104dc575060006102a1565b600061022b866107d8565b6000826020015142111561050d5760405162461bcd60e51b81526004016101d79061168e565b6001600160a01b0382166105335760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b031661054d575060006101aa565b600061032785610583565b600061046c868686868630610376565b60006101aa8383306102b6565b60006101a784848430610476565b6060816101200151826000015183602001518460600151856040015186610100015187608001518860a001518960c001518a60e001516040516020016105d29a99989796959493929190611491565b6040516020818303038152906040529050919050565b60608160400151826000015183602001516040516020016105d29392919060609390931b6001600160601b03191683526014830191909152603482015260540190565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b600080600061068d8585610881565b909250905060008160048111156106b457634e487b7160e01b600052602160045260246000fd5b1480156106d25750856001600160a01b0316826001600160a01b0316145b156106e2576001925050506101aa565b600080876001600160a01b0316631626ba7e60e01b888860405160240161070a929190611654565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516107489190611527565b600060405180830381855afa9150503d8060008114610783576040519150601f19603f3d011682016040523d82523d6000602084013e610788565b606091505b509150915081801561079b575080516020145b80156107cc57508051630b135d3f60e11b906107c09083016020908101908401610f80565b6001600160e01b031916145b98975050505050505050565b60608160c0015182600001518360200151846060015185604001518660e0015187608001518860a001516040516020016105d2989796959493929190606098891b6001600160601b031990811682526014820198909852603481019690965293871b86166054860152606885019290925290941b909216608882015260e09290921b6001600160e01b031916609c83015260f01b6001600160f01b03191660a082015260a20190565b6000808251604114156108b85760208301516040840151606085015160001a6108ac878285856108f1565b945094505050506108ea565b8251604014156108e257602083015160408401516108d78683836109d4565b9350935050506108ea565b506000905060025b9250929050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561091e57506000905060036109cb565b8460ff16601b1415801561093657508460ff16601c14155b1561094757506000905060046109cb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561099b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166109c4576000600192509250506109cb565b9150600090505b94509492505050565b6000806001600160ff1b038316816109f160ff86901c601b6118b0565b90506109ff878288856108f1565b935093505050935093915050565b80356001600160a01b0381168114610a2457600080fd5b919050565b600082601f830112610a39578081fd5b81356020610a4e610a498361188d565b61185d565b80838252828201915082860187848660051b8901011115610a6d578586fd5b855b85811015610b175781356001600160401b0380821115610a8d578889fd5b908901906060828c03601f1901811315610aa557898afd5b610aad6117ce565b610ab8898501610a0d565b815260408085013584811115610acc578c8dfd5b610ada8f8c83890101610baa565b838c015250918401359183831115610af0578b8cfd5b610afe8e8b85880101610baa565b9082015287525050509284019290840190600101610a6f565b5090979650505050505050565b600082601f830112610b34578081fd5b81356020610b44610a498361188d565b80838252828201915082860187848660061b8901011115610b63578586fd5b855b85811015610b1757604080838b031215610b7d578788fd5b610b856117f6565b610b8e84610a0d565b8152838701358782015285529385019390910190600101610b65565b600082601f830112610bba578081fd5b81356020610bca610a498361188d565b80838252828201915082860187848660051b8901011115610be9578586fd5b855b85811015610b1757813584529284019290840190600101610beb565b60006060808385031215610c19578182fd5b610c216117ce565b915082356001600160401b0380821115610c3a57600080fd5b818501915085601f830112610c4e57600080fd5b81356020610c5e610a498361188d565b82815281810190858301878502870184018b1015610c7b57600080fd5b600096505b84871015610cde5787818c031215610c9757600080fd5b610c9f6117ce565b610ca882610a0d565b815284820135858201526040808301358015158114610cc657600080fd5b90820152835260019690960195918301918701610c80565b5087525086810135945082851115610cf557600080fd5b610d0188868901610b24565b90860152506040850135925080831115610d1a57600080fd5b5050610d2884828501610a29565b60408301525092915050565b60006101408284031215610d46578081fd5b610d4e611818565b9050813581526020820135602082015260408201356040820152610d7460608301610a0d565b6060820152610d8560808301610f6c565b6080820152610d9660a08301610f6c565b60a0820152610da760c08301610f5a565b60c0820152610db860e08301610f5a565b60e0820152610100610dcb818401610a0d565b90820152610120610ddd838201610a0d565b9082015292915050565b6000610100808385031215610dfa578182fd5b604051908101906001600160401b0382118183101715610e1c57610e1c611904565b81604052809250833581526020840135602082015260408401356040820152610e4760608501610a0d565b6060820152610e5860808501610f6c565b6080820152610e6960a08501610f5a565b60a0820152610e7a60c08501610a0d565b60c0820152610e8b60e08501610a0d565b60e0820152505092915050565b600060808284031215610ea9578081fd5b610eb161183b565b90508135815260208083013581830152610ecd60408401610a0d565b604083015260608301356001600160401b0380821115610eec57600080fd5b818501915085601f830112610f0057600080fd5b813581811115610f1257610f12611904565b610f24601f8201601f1916850161185d565b91508082528684828501011115610f3a57600080fd5b808484018584013760008482840101525080606085015250505092915050565b803561ffff81168114610a2457600080fd5b803563ffffffff81168114610a2457600080fd5b600060208284031215610f91578081fd5b81516001600160e01b0319811681146101aa578182fd5b60008060006101808486031215610fbd578182fd5b610fc78585610d34565b92506101408401356001600160401b0380821115610fe3578384fd5b610fef87838801610c07565b9350610160860135915080821115611005578283fd5b5061101286828701610e98565b9150509250925092565b6000806000806101a08587031215611032578182fd5b61103c8686610d34565b93506101408501356001600160401b0380821115611058578384fd5b61106488838901610c07565b945061016087013591508082111561107a578384fd5b5061108787828801610e98565b9250506110976101808601610a0d565b905092959194509250565b60008061016083850312156110b5578182fd5b6110bf8484610d34565b91506101408301356001600160401b038111156110da578182fd5b6110e685828601610e98565b9150509250929050565b60008060006101808486031215611105578081fd5b61110f8585610d34565b92506101408401356001600160401b0381111561112a578182fd5b61113686828701610e98565b9250506111466101608501610a0d565b90509250925092565b60008060006101408486031215611164578081fd5b61116e8585610de7565b92506101008401356001600160401b038082111561118a578283fd5b61119687838801610c07565b9350610120860135915080821115611005578283fd5b60008060008061016085870312156111c2578182fd5b6111cc8686610de7565b93506101008501356001600160401b03808211156111e8578384fd5b6111f488838901610c07565b945061012087013591508082111561120a578384fd5b5061121787828801610e98565b9250506110976101408601610a0d565b600080610120838503121561123a578182fd5b6112448484610de7565b91506101008301356001600160401b038111156110da578182fd5b60008060006101408486031215611274578081fd5b61127e8585610de7565b92506101008401356001600160401b03811115611299578182fd5b6112a586828701610e98565b9250506111466101208501610a0d565b600080600080600060a086880312156112cc578283fd5b853594506112dc60208701610f6c565b9350604086013592506060860135915060808601356001600160401b03811115611304578182fd5b61131088828901610e98565b9150509295509295909350565b60008060008060008060c08789031215611335578384fd5b8635955061134560208801610f6c565b9450604087013593506060870135925060808701356001600160401b0381111561136d578182fd5b61137989828a01610e98565b92505061138860a08801610a0d565b90509295509295509295565b6000815180845260208085019450848260051b8601828601855b85811015610b17578383038952815180516001600160a01b03168452858101516060878601819052906113e382870182611462565b915050604080830151925085820381870152506114008183611462565b9a87019a94505050908401906001016113ae565b6000815180845260208085019450808401835b8381101561145757815180516001600160a01b031688528301518388015260409096019590820190600101611427565b509495945050505050565b6000815180845260208085019450808401835b8381101561145757815187529582019590820190600101611475565b60006001600160601b0319808d60601b1683528b60148401528a6034840152808a60601b166054840152886068840152808860601b1660888401525063ffffffff60e01b808760e01b16609c840152808660e01b1660a08401525061ffff60f01b8460f01b1660a483015261151560a683018460f01b6001600160f01b0319169052565b5060a8019a9950505050505050505050565b600082516115398184602087016118d4565b9190910192915050565b60008551611555818460208a016118d4565b855190830190611569818360208a016118d4565b60609590951b6001600160601b03191694019384525050601482015260340192915050565b600086516115a0818460208b016118d4565b8651908301906115b4818360208b016118d4565b86519101906115c7818360208a016118d4565b60609590951b6001600160601b0319169401938452505060148201526034019392505050565b87815263ffffffff60e01b8760e01b166020820152856024820152846044820152600084516116238160648501602089016118d4565b80830190506001600160601b03198560601b1660648201528360788201526098810191505098975050505050505050565b82815260406020820152600082518060408401526116798160608501602087016118d4565b601f01601f1916919091016060019392505050565b6020808252601e908201527f426f72726f776572205369676e61747572652068617320657870697265640000604082015260600190565b6020808252601c908201527f4c656e646572205369676e617475726520686173206578706972656400000000604082015260600190565b6020808252601490820152734c6f616e206973207a65726f206164647265737360601b604082015260600190565b60208082528251606083830181905281516080850181905260009392830191849160a08701905b8084101561179057845180516001600160a01b031683528681015187840152604090810151151590830152938501936001939093019290820190611751565b50848801519450601f199350838782030160408801526117b08186611414565b945050604087015191508286850301818701525061046c8382611394565b604051606081016001600160401b03811182821017156117f0576117f0611904565b60405290565b604080519081016001600160401b03811182821017156117f0576117f0611904565b60405161014081016001600160401b03811182821017156117f0576117f0611904565b604051608081016001600160401b03811182821017156117f0576117f0611904565b604051601f8201601f191681016001600160401b038111828210171561188557611885611904565b604052919050565b60006001600160401b038211156118a6576118a6611904565b5060051b60200190565b600082198211156118cf57634e487b7160e01b81526011600452602481fd5b500190565b60005b838110156118ef5781810151838201526020016118d7565b838111156118fe576000848401525b50505050565b634e487b7160e01b600052604160045260246000fdfea164736f6c6343000804000a

Deployed Bytecode

0x7360da568b88037d0735715819a37714d28bd5634730146080604052600436106100b35760003560e01c806387c0a5731161007b57806387c0a57314610127578063a819956e1461013a578063c42129211461014d578063d06ff74114610160578063eb2ac63f14610173578063fb7a322a1461018657600080fd5b80632eb68793146100b85780633ce5ed9f146100e05780634051a17a146100f3578063564b81ef146101065780636ab81ec014610114575b600080fd5b6100cb6100c6366004610fa8565b610199565b60405190151581526020015b60405180910390f35b6100cb6100ee36600461101c565b6101b1565b6100cb6101013660046110a2565b6102a9565b6040514681526020016100d7565b6100cb61012236600461125f565b6102b6565b6100cb61013536600461131d565b610376565b6100cb6101483660046111ac565b610476565b6100cb61015b3660046110f0565b6104e7565b6100cb61016e3660046112b5565b610558565b6100cb610181366004611227565b610568565b6100cb61019436600461114f565b610575565b60006101a7848484306101b1565b90505b9392505050565b600082602001514211156101e05760405162461bcd60e51b81526004016101d79061168e565b60405180910390fd5b6001600160a01b0382166102065760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b0316610220575060006102a1565b600061022b86610583565b8560405160200161023c919061172a565b604051602081830303815290604052610254866105e8565b854660405160200161026a95949392919061158e565b60405160208183030381529060405280519060200120905061029d84604001516102938361062b565b866060015161067e565b9150505b949350505050565b60006101aa8383306104e7565b600082602001514211156102dc5760405162461bcd60e51b81526004016101d7906116c5565b6001600160a01b0382166103025760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b031661031c575060006101aa565b6000610327856107d8565b610330856105e8565b84466040516020016103459493929190611543565b60405160208183030381529060405280519060200120905061036e84604001516102938361062b565b9150506101aa565b600082602001514211156103d85760405162461bcd60e51b815260206004820152602360248201527f52656e65676f74696174696f6e205369676e61747572652068617320657870696044820152621c995960ea1b60648201526084016101d7565b6001600160a01b0382166103fe5760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b03166104185750600061046c565b600087878787610427886105e8565b874660405160200161043f97969594939291906115ed565b60405160208183030381529060405280519060200120905061046884604001516102938361062b565b9150505b9695505050505050565b6000826020015142111561049c5760405162461bcd60e51b81526004016101d7906116c5565b6001600160a01b0382166104c25760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b03166104dc575060006102a1565b600061022b866107d8565b6000826020015142111561050d5760405162461bcd60e51b81526004016101d79061168e565b6001600160a01b0382166105335760405162461bcd60e51b81526004016101d7906116fc565b60408301516001600160a01b031661054d575060006101aa565b600061032785610583565b600061046c868686868630610376565b60006101aa8383306102b6565b60006101a784848430610476565b6060816101200151826000015183602001518460600151856040015186610100015187608001518860a001518960c001518a60e001516040516020016105d29a99989796959493929190611491565b6040516020818303038152906040529050919050565b60608160400151826000015183602001516040516020016105d29392919060609390931b6001600160601b03191683526014830191909152603482015260540190565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b600080600061068d8585610881565b909250905060008160048111156106b457634e487b7160e01b600052602160045260246000fd5b1480156106d25750856001600160a01b0316826001600160a01b0316145b156106e2576001925050506101aa565b600080876001600160a01b0316631626ba7e60e01b888860405160240161070a929190611654565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516107489190611527565b600060405180830381855afa9150503d8060008114610783576040519150601f19603f3d011682016040523d82523d6000602084013e610788565b606091505b509150915081801561079b575080516020145b80156107cc57508051630b135d3f60e11b906107c09083016020908101908401610f80565b6001600160e01b031916145b98975050505050505050565b60608160c0015182600001518360200151846060015185604001518660e0015187608001518860a001516040516020016105d2989796959493929190606098891b6001600160601b031990811682526014820198909852603481019690965293871b86166054860152606885019290925290941b909216608882015260e09290921b6001600160e01b031916609c83015260f01b6001600160f01b03191660a082015260a20190565b6000808251604114156108b85760208301516040840151606085015160001a6108ac878285856108f1565b945094505050506108ea565b8251604014156108e257602083015160408401516108d78683836109d4565b9350935050506108ea565b506000905060025b9250929050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561091e57506000905060036109cb565b8460ff16601b1415801561093657508460ff16601c14155b1561094757506000905060046109cb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561099b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166109c4576000600192509250506109cb565b9150600090505b94509492505050565b6000806001600160ff1b038316816109f160ff86901c601b6118b0565b90506109ff878288856108f1565b935093505050935093915050565b80356001600160a01b0381168114610a2457600080fd5b919050565b600082601f830112610a39578081fd5b81356020610a4e610a498361188d565b61185d565b80838252828201915082860187848660051b8901011115610a6d578586fd5b855b85811015610b175781356001600160401b0380821115610a8d578889fd5b908901906060828c03601f1901811315610aa557898afd5b610aad6117ce565b610ab8898501610a0d565b815260408085013584811115610acc578c8dfd5b610ada8f8c83890101610baa565b838c015250918401359183831115610af0578b8cfd5b610afe8e8b85880101610baa565b9082015287525050509284019290840190600101610a6f565b5090979650505050505050565b600082601f830112610b34578081fd5b81356020610b44610a498361188d565b80838252828201915082860187848660061b8901011115610b63578586fd5b855b85811015610b1757604080838b031215610b7d578788fd5b610b856117f6565b610b8e84610a0d565b8152838701358782015285529385019390910190600101610b65565b600082601f830112610bba578081fd5b81356020610bca610a498361188d565b80838252828201915082860187848660051b8901011115610be9578586fd5b855b85811015610b1757813584529284019290840190600101610beb565b60006060808385031215610c19578182fd5b610c216117ce565b915082356001600160401b0380821115610c3a57600080fd5b818501915085601f830112610c4e57600080fd5b81356020610c5e610a498361188d565b82815281810190858301878502870184018b1015610c7b57600080fd5b600096505b84871015610cde5787818c031215610c9757600080fd5b610c9f6117ce565b610ca882610a0d565b815284820135858201526040808301358015158114610cc657600080fd5b90820152835260019690960195918301918701610c80565b5087525086810135945082851115610cf557600080fd5b610d0188868901610b24565b90860152506040850135925080831115610d1a57600080fd5b5050610d2884828501610a29565b60408301525092915050565b60006101408284031215610d46578081fd5b610d4e611818565b9050813581526020820135602082015260408201356040820152610d7460608301610a0d565b6060820152610d8560808301610f6c565b6080820152610d9660a08301610f6c565b60a0820152610da760c08301610f5a565b60c0820152610db860e08301610f5a565b60e0820152610100610dcb818401610a0d565b90820152610120610ddd838201610a0d565b9082015292915050565b6000610100808385031215610dfa578182fd5b604051908101906001600160401b0382118183101715610e1c57610e1c611904565b81604052809250833581526020840135602082015260408401356040820152610e4760608501610a0d565b6060820152610e5860808501610f6c565b6080820152610e6960a08501610f5a565b60a0820152610e7a60c08501610a0d565b60c0820152610e8b60e08501610a0d565b60e0820152505092915050565b600060808284031215610ea9578081fd5b610eb161183b565b90508135815260208083013581830152610ecd60408401610a0d565b604083015260608301356001600160401b0380821115610eec57600080fd5b818501915085601f830112610f0057600080fd5b813581811115610f1257610f12611904565b610f24601f8201601f1916850161185d565b91508082528684828501011115610f3a57600080fd5b808484018584013760008482840101525080606085015250505092915050565b803561ffff81168114610a2457600080fd5b803563ffffffff81168114610a2457600080fd5b600060208284031215610f91578081fd5b81516001600160e01b0319811681146101aa578182fd5b60008060006101808486031215610fbd578182fd5b610fc78585610d34565b92506101408401356001600160401b0380821115610fe3578384fd5b610fef87838801610c07565b9350610160860135915080821115611005578283fd5b5061101286828701610e98565b9150509250925092565b6000806000806101a08587031215611032578182fd5b61103c8686610d34565b93506101408501356001600160401b0380821115611058578384fd5b61106488838901610c07565b945061016087013591508082111561107a578384fd5b5061108787828801610e98565b9250506110976101808601610a0d565b905092959194509250565b60008061016083850312156110b5578182fd5b6110bf8484610d34565b91506101408301356001600160401b038111156110da578182fd5b6110e685828601610e98565b9150509250929050565b60008060006101808486031215611105578081fd5b61110f8585610d34565b92506101408401356001600160401b0381111561112a578182fd5b61113686828701610e98565b9250506111466101608501610a0d565b90509250925092565b60008060006101408486031215611164578081fd5b61116e8585610de7565b92506101008401356001600160401b038082111561118a578283fd5b61119687838801610c07565b9350610120860135915080821115611005578283fd5b60008060008061016085870312156111c2578182fd5b6111cc8686610de7565b93506101008501356001600160401b03808211156111e8578384fd5b6111f488838901610c07565b945061012087013591508082111561120a578384fd5b5061121787828801610e98565b9250506110976101408601610a0d565b600080610120838503121561123a578182fd5b6112448484610de7565b91506101008301356001600160401b038111156110da578182fd5b60008060006101408486031215611274578081fd5b61127e8585610de7565b92506101008401356001600160401b03811115611299578182fd5b6112a586828701610e98565b9250506111466101208501610a0d565b600080600080600060a086880312156112cc578283fd5b853594506112dc60208701610f6c565b9350604086013592506060860135915060808601356001600160401b03811115611304578182fd5b61131088828901610e98565b9150509295509295909350565b60008060008060008060c08789031215611335578384fd5b8635955061134560208801610f6c565b9450604087013593506060870135925060808701356001600160401b0381111561136d578182fd5b61137989828a01610e98565b92505061138860a08801610a0d565b90509295509295509295565b6000815180845260208085019450848260051b8601828601855b85811015610b17578383038952815180516001600160a01b03168452858101516060878601819052906113e382870182611462565b915050604080830151925085820381870152506114008183611462565b9a87019a94505050908401906001016113ae565b6000815180845260208085019450808401835b8381101561145757815180516001600160a01b031688528301518388015260409096019590820190600101611427565b509495945050505050565b6000815180845260208085019450808401835b8381101561145757815187529582019590820190600101611475565b60006001600160601b0319808d60601b1683528b60148401528a6034840152808a60601b166054840152886068840152808860601b1660888401525063ffffffff60e01b808760e01b16609c840152808660e01b1660a08401525061ffff60f01b8460f01b1660a483015261151560a683018460f01b6001600160f01b0319169052565b5060a8019a9950505050505050505050565b600082516115398184602087016118d4565b9190910192915050565b60008551611555818460208a016118d4565b855190830190611569818360208a016118d4565b60609590951b6001600160601b03191694019384525050601482015260340192915050565b600086516115a0818460208b016118d4565b8651908301906115b4818360208b016118d4565b86519101906115c7818360208a016118d4565b60609590951b6001600160601b0319169401938452505060148201526034019392505050565b87815263ffffffff60e01b8760e01b166020820152856024820152846044820152600084516116238160648501602089016118d4565b80830190506001600160601b03198560601b1660648201528360788201526098810191505098975050505050505050565b82815260406020820152600082518060408401526116798160608501602087016118d4565b601f01601f1916919091016060019392505050565b6020808252601e908201527f426f72726f776572205369676e61747572652068617320657870697265640000604082015260600190565b6020808252601c908201527f4c656e646572205369676e617475726520686173206578706972656400000000604082015260600190565b6020808252601490820152734c6f616e206973207a65726f206164647265737360601b604082015260600190565b60208082528251606083830181905281516080850181905260009392830191849160a08701905b8084101561179057845180516001600160a01b031683528681015187840152604090810151151590830152938501936001939093019290820190611751565b50848801519450601f199350838782030160408801526117b08186611414565b945050604087015191508286850301818701525061046c8382611394565b604051606081016001600160401b03811182821017156117f0576117f0611904565b60405290565b604080519081016001600160401b03811182821017156117f0576117f0611904565b60405161014081016001600160401b03811182821017156117f0576117f0611904565b604051608081016001600160401b03811182821017156117f0576117f0611904565b604051601f8201601f191681016001600160401b038111828210171561188557611885611904565b604052919050565b60006001600160401b038211156118a6576118a6611904565b5060051b60200190565b600082198211156118cf57634e487b7160e01b81526011600452602481fd5b500190565b60005b838110156118ef5781810151838201526020016118d7565b838111156118fe576000848401525b50505050565b634e487b7160e01b600052604160045260246000fdfea164736f6c6343000804000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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