Skip to main content

List Proposal

1. Summary

PWNSimpleLoanListProposal.sol defines the List Proposal type for Simple Loan and implements functions to make an on-chain proposal and accept proposals.

The List Proposal can define a list of acceptable collateral ids or a whole collection. Interest can be either accruing or fixed.

3. Contract details

  • PWNSimpleLoanListProposal.sol is written in Solidity version 0.8.16

Features

  • Provides acceptProposal function and makeProposal for on-chain proposals
  • Defines the Proposal struct

Inherited contracts, implemented Interfaces and ERCs

Functions

acceptProposal

Overview

A function to accept a proposal.

This function takes five arguments supplied by the caller:

  • addressacceptor - Address of a proposal acceptor
  • uint256refinancingLoanId - Refinancing loan ID
  • bytes32 calldataproposalData - Encoded Proposal and ProposalValues structs
  • bytes32[] calldataproposalInclusionProof - Multiproposal inclusion proof. Empty if single proposal
  • bytes calldatasignature - Signature of a proposal

Implementation

function acceptProposal(
address acceptor,
uint256 refinancingLoanId,
bytes calldata proposalData,
bytes32[] calldata proposalInclusionProof,
bytes calldata signature
) override external returns (bytes32 proposalHash, PWNSimpleLoan.Terms memory loanTerms) {
// Decode proposal data
(Proposal memory proposal, ProposalValues memory proposalValues) = decodeProposalData(proposalData);

// Make proposal hash
proposalHash = _getProposalHash(PROPOSAL_TYPEHASH, _erc712EncodeProposal(proposal));

// Check provided collateral id
if (proposal.collateralIdsWhitelistMerkleRoot != bytes32(0)) {
// Verify whitelisted collateral id
if (
!MerkleProof.verify({
proof: proposalValues.merkleInclusionProof,
root: proposal.collateralIdsWhitelistMerkleRoot,
leaf: keccak256(abi.encodePacked(proposalValues.collateralId))
})
) revert CollateralIdNotWhitelisted({ id: proposalValues.collateralId });
}

// Note: If the `collateralIdsWhitelistMerkleRoot` is empty, any collateral id can be used.

ProposalValuesBase memory proposalValuesBase = ProposalValuesBase({
refinancingLoanId: refinancingLoanId,
acceptor: acceptor,
acceptorControllerData: proposalValues.acceptorControllerData
});

// Try to accept proposal
_acceptProposal(
proposalHash,
proposalInclusionProof,
signature,
ProposalBase({
collateralAddress: proposal.collateralAddress,
collateralId: proposalValues.collateralId,
checkCollateralStateFingerprint: proposal.checkCollateralStateFingerprint,
collateralStateFingerprint: proposal.collateralStateFingerprint,
creditAmount: proposal.creditAmount,
availableCreditLimit: proposal.availableCreditLimit,
utilizedCreditId: proposal.utilizedCreditId,
expiration: proposal.expiration,
acceptorController: proposal.acceptorController,
acceptorControllerData: proposal.acceptorControllerData,
proposer: proposal.proposer,
isOffer: proposal.isOffer,
refinancingLoanId: proposal.refinancingLoanId,
nonceSpace: proposal.nonceSpace,
nonce: proposal.nonce,
loanContract: proposal.loanContract
}),
proposalValuesBase
);

// Create loan terms object
loanTerms = PWNSimpleLoan.Terms({
lender: proposal.isOffer ? proposal.proposer : acceptor,
borrower: proposal.isOffer ? acceptor : proposal.proposer,
duration: _getLoanDuration(proposal.durationOrDate),
collateral: MultiToken.Asset({
category: proposal.collateralCategory,
assetAddress: proposal.collateralAddress,
id: proposalValues.collateralId,
amount: proposal.collateralAmount
}),
credit: MultiToken.ERC20({
assetAddress: proposal.creditAddress,
amount: proposal.creditAmount
}),
fixedInterestAmount: proposal.fixedInterestAmount,
accruingInterestAPR: proposal.accruingInterestAPR,
lenderSpecHash: proposal.isOffer ? proposal.proposerSpecHash : bytes32(0),
borrowerSpecHash: proposal.isOffer ? bytes32(0) : proposal.proposerSpecHash
});
}
makeProposal

Overview

Function to create an on-chain proposal. Marks the hash of the supplied proposal as proposed.

This function takes one argument supplied by the caller:

  • Proposal calldataproposal - Proposal struct containing all needed proposal data

Implementation

function makeProposal(Proposal calldata proposal) external returns (bytes32 proposalHash) {
proposalHash = getProposalHash(proposal);
_makeProposal(proposalHash, proposal.proposer);
emit ProposalMade(proposalHash, proposal.proposer, proposal);
}

View Functions

getProposalHash

Overview

This function returns supplied proposals hash according to EIP-712.

This function takes one argument supplied by the caller:

  • Proposal calldataproposal - Proposal struct to be hashed

Implementation

function getProposalHash(Proposal calldata proposal) public view returns (bytes32) {
return _getProposalHash(PROPOSAL_TYPEHASH, _erc712EncodeProposal(proposal));
}
encodeProposalData

Overview

Function to encode a proposal struct and proposal values.

This function takes two arguments supplied by the caller:

  • Proposal memoryproposal - Proposal struct to be encoded
  • ProposalValues memoryproposalValues - ProposalValues struct to be encoded

Implementation

function encodeProposalData(
Proposal memory proposal,
ProposalValues memory proposalValues
) external pure returns (bytes memory) {
return abi.encode(proposal, proposalValues);
}
decodeProposalData

Overview

Function to decode an encoded proposal struct and proposal values.

This function takes one argument supplied by the caller:

Implementation

function decodeProposalData(bytes memory proposalData) public pure returns (Proposal memory, ProposalValues memory) {
return abi.decode(proposalData, (Proposal, ProposalValues));
}

Events

The PWN Simple Loan List Proposal contract defines one event and one error.

event ProposalMade(bytes32 indexed proposalHash, address indexed proposer, Proposal proposal);
ProposalMade

ProposalMade event is emitted when an on-chain proposal is made.

This event has three parameters:

  • bytes32 indexedproposalHash - Hash of the proposed proposal
  • address indexedproposer - Address of the proposer
  • Proposalproposal - The proposal made

Errors

error CollateralIdNotWhitelisted(uint256 id);
CollateralIdNotWhitelisted

CollateralIdNotWhitelisted error is thrown when a collateral id is not whitelisted.

This error has one parameter:

  • uint256id - The collateral id that's not whitelisted

Proposal struct

TypeNameComment
MultiToken.CategorycollateralCategoryCorresponding collateral category
addresscollateralAddressAddress of a loan collateral
bytes32collateralIdsWhitelistMerkleRootMerkle tree root of a set of whitelisted collateral ids
uint256collateralAmountAmount of a collateral. Zero if ERC-721
boolcheckCollateralStateFingerprintFlag to enable check of collaterals state fingerprint (see ERC-5646)
bytes32collateralStateFingerprintA collateral state fingerprint (see ERC-5646)
addresscreditAddressAddress of credit asset
uint256creditAmountAmount of credit asset
uint256availableCreditLimitMaximum credit limit of credit asset
uint256fixedInterestAmountFixed interest amount in credit tokens. It is the minimum amount of interest which has to be paid by a borrower
uint24accruingInterestAPRAccruing interest APR with 2 decimals
uint32durationOrDateDuration of a loan in seconds. If the value is greater than 10^9, it's considered a timestamp of the loan end
uint40expirationProposal expiration unix timestamp in seconds
addressacceptorControllerAddress of Acceptor Controller contract that will verify submitted acceptor data
bytesacceptorControllerDataData provided by proposer to be verified by Acceptor Controller
addressproposerProposer address
bytes32proposerSpecHashHash of a proposer specific data, which must be provided during a loan creation
boolisOfferFlag to determine if a proposal is an offer or loan request
uint256refinancingLoanIdID of a loan to be refinanced. Zero if creating a new loan.
uint256nonceSpaceNonce space of the proposal
uint256nonceNonce of the proposal
addressloanContractLoan type contract

ProposalValues struct

TypeNameComment
uint256collateralIdID of the collateral to use. ID must be included in the merkle tree which root was submitted in the Proposal struct.
bytes32[]merkleInclusionProofID merkle inclusion proof
bytesacceptorControllerDataData provided by proposal acceptor to be passed to the acceptor controller if defined in the Proposal struct