List Offer

1. Summary

PWNSimpleLoanListOffer.sol defines List Offer for the Simple Loan type.

List offer enables creating offers for a list of NFTs from a collection or an entire NFT collection.

3. Contract details

  • PWNSimpleLoanListOffer.sol is written in Solidity version 0.8.16

Features

  • Make List Offer

  • Create Simple Loan terms from List Offer

  • Provides a function to encode List Offer

Inherited contracts, implemented Interfaces and ERCs

Functions

makeOffer

Overview

Make an on-chain list offer.

This function takes one argument supplied by the caller:

  • Offer calldataoffer - Offer struct with the list offer parameters

Implementation

function makeOffer(Offer calldata offer) external {
    _makeOffer(getOfferHash(offer), offer.lender);
}
createLOANTerms

Overview

Builds simple loan terms from given data.

This function takes three arguments supplied by the loan type:

  • addresscaller - The caller of the createLoan function on the Loan contract

  • bytes calldatafactoryData - Encoded data for the Loan Terms factory

  • bytes calldatasignature - Singed loan factory data

Implementation

function createLOANTerms(
    address caller,
    bytes calldata factoryData,
    bytes calldata signature
) external override onlyActiveLoan returns (PWNLOANTerms.Simple memory loanTerms) {

    (Offer memory offer, OfferValues memory offerValues) = abi.decode(factoryData, (Offer, OfferValues));
    bytes32 offerHash = getOfferHash(offer);

    address lender = offer.lender;
    address borrower = caller;

    // Check that offer has been made via on-chain tx, EIP-1271 or signed off-chain
    if (offersMade[offerHash] == false)
        if (PWNSignatureChecker.isValidSignatureNow(lender, offerHash, signature) == false)
            revert InvalidSignature();

    // Check valid offer
    if (offer.expiration != 0 && block.timestamp >= offer.expiration)
        revert OfferExpired();

    if (revokedOfferNonce.isNonceRevoked(lender, offer.nonce) == true)
        revert NonceAlreadyRevoked();

    if (offer.borrower != address(0))
        if (borrower != offer.borrower)
            revert CallerIsNotStatedBorrower(offer.borrower);

    if (offer.duration < MIN_LOAN_DURATION)
        revert InvalidDuration();

    // Collateral id list
    if (offer.collateralIdsWhitelistMerkleRoot != bytes32(0)) {
        // Verify whitelisted collateral id
        bool isVerifiedId = MerkleProof.verify(
            offerValues.merkleInclusionProof,
            offer.collateralIdsWhitelistMerkleRoot,
            keccak256(abi.encodePacked(offerValues.collateralId))
        );
        if (isVerifiedId == false)
            revert CollateralIdIsNotWhitelisted();
    } // else: Any collateral id - collection offer

    // Prepare collateral and loan asset
    MultiToken.Asset memory collateral = MultiToken.Asset({
        category: offer.collateralCategory,
        assetAddress: offer.collateralAddress,
        id: offerValues.collateralId,
        amount: offer.collateralAmount
    });
    MultiToken.Asset memory loanAsset = MultiToken.Asset({
        category: MultiToken.Category.ERC20,
        assetAddress: offer.loanAssetAddress,
        id: 0,
        amount: offer.loanAmount
    });

    // Create loan object
    loanTerms = PWNLOANTerms.Simple({
        lender: lender,
        borrower: borrower,
        expiration: uint40(block.timestamp) + offer.duration,
        collateral: collateral,
        asset: loanAsset,
        loanRepayAmount: offer.loanAmount + offer.loanYield
    });

    // Revoke offer if not persistent
    if (!offer.isPersistent)
        revokedOfferNonce.revokeNonce(lender, offer.nonce);
}
encodeLoanTermsFactoryData

Overview

Returns encoded input data for the loan terms factory (inherited by this contract).

This function takes two arguments supplied by the caller:

  • Offer memoryOffer - List offer struct to encode

  • OfferValues memoryofferValues - Concrete values for list offer from a borrower.

Implementation

function encodeLoanTermsFactoryData(Offer memory offer, OfferValues memory offerValues) external pure returns (bytes memory) {
    return abi.encode(offer, offerValues);
}

View Functions

getOfferHash

Overview

Returns a list offer hash according to EIP-712.

This function takes one argument supplied by the caller:

  • Offer memoryoffer - List offer struct to get hash of

Implementation

function getOfferHash(Offer memory offer) public view returns (bytes32) {
    return keccak256(abi.encodePacked(
        hex"1901",
        DOMAIN_SEPARATOR,
        keccak256(abi.encodePacked(
            OFFER_TYPEHASH,
            abi.encode(offer)
        ))
    ));
}

Events

The PWN Simple Loan List Offer contract inherits events from the Simple Loan Offer contract and does not define any additional custom events or errors.

List Offer Struct

TypeNameComment

MultiToken.Category

collateralCategory

0 -> ERC-20 1 -> ERC-721 2 -> ERC-1155

address

collateralAddress

Address of an asset used as a collateral.

bytes32

collateralIdsWhitelistMerkleRoot

Merkle tree root of a set of whitelisted collateral ids.

uint256

collateralAmount

Amount of tokens used as a collateral, in case of ERC721 should be 0.

address

loanAssetAddress

Address of an loaned asset.

uint256

loanAmount

Amount of tokens which is requested as a loan.

uint256

loanYield

Amount of tokens which act as a lenders loan interest. Borrower has to pay back a borrowed amount + yield.

uint32

duration

Loan duration in seconds.

uint40

expiration

Request expiration unix timestamp in seconds.

address

borrower

Address of a borrower. This address has to sign a request for it to be valid. If the address is zero address, anybody with valid collateral can accept the offer.

address

lender

Address of a lender. Only this address can accept a request. If the address is zero address, anybody with a loan asset can accept the request.

bool

isPersistent

If true, offer will not be revoked on acceptance. Persistent offer can be revoked manually.

uint256

nonce

Additional value to enable identical requests in time. Without it, it would be impossible to make a request, which was once revoked. Nonce can be used to create a group of requests, where accepting one request will make other requests in the group invalid.

Offer Values Struct

When a borrower decides to accept a list offer, concrete values for a simple loan have to be provided. Offer Values Struct serves this purpose.

TypeNameComment

uint256

collateralId

Selected collateral id to be used as a collateral.

bytes32[]

merkleInclusionProof

Proof of inclusion, that selected collateral id is whitelisted. This proof should create same hash as the merkle tree root given in an Offer. Can be empty for collection offers.

Last updated