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.
2. Important links
3. Contract details
- PWNSimpleLoanListProposal.sol is written in Solidity version 0.8.16
Features
- Provides
acceptProposal
function andmakeProposal
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:
address
acceptor
- Address of a proposal acceptoruint256
refinancingLoanId
- Refinancing loan IDbytes32 calldata
proposalData
- Encoded Proposal and ProposalValues structsbytes32[] calldata
proposalInclusionProof
- Multiproposal inclusion proof. Empty if single proposalbytes calldata
signature
- 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 calldata
proposal
- 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 calldata
proposal
- 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 memory
proposal
- Proposal struct to be encodedProposalValues memory
proposalValues
- 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:
bytes memory
proposalData
- Encoded Proposal and ProposalValues structs
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 indexed
proposalHash
- Hash of the proposed proposaladdress indexed
proposer
- Address of the proposerProposal
proposal
- 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:
uint256
id
- The collateral id that's not whitelisted
Proposal
struct
Type | Name | Comment |
---|---|---|
MultiToken.Category | collateralCategory | Corresponding collateral category |
address | collateralAddress | Address of a loan collateral |
bytes32 | collateralIdsWhitelistMerkleRoot | Merkle tree root of a set of whitelisted collateral ids |
uint256 | collateralAmount | Amount of a collateral. Zero if ERC-721 |
bool | checkCollateralStateFingerprint | Flag to enable check of collaterals state fingerprint (see ERC-5646) |
bytes32 | collateralStateFingerprint | A collateral state fingerprint (see ERC-5646) |
address | creditAddress | Address of credit asset |
uint256 | creditAmount | Amount of credit asset |
uint256 | availableCreditLimit | Maximum credit limit of credit asset |
uint256 | fixedInterestAmount | Fixed interest amount in credit tokens. It is the minimum amount of interest which has to be paid by a borrower |
uint24 | accruingInterestAPR | Accruing interest APR with 2 decimals |
uint32 | durationOrDate | Duration of a loan in seconds. If the value is greater than 10^9 , it's considered a timestamp of the loan end |
uint40 | expiration | Proposal expiration unix timestamp in seconds |
address | acceptorController | Address of Acceptor Controller contract that will verify submitted acceptor data |
bytes | acceptorControllerData | Data provided by proposer to be verified by Acceptor Controller |
address | proposer | Proposer address |
bytes32 | proposerSpecHash | Hash of a proposer specific data, which must be provided during a loan creation |
bool | isOffer | Flag to determine if a proposal is an offer or loan request |
uint256 | refinancingLoanId | ID of a loan to be refinanced. Zero if creating a new loan. |
uint256 | nonceSpace | Nonce space of the proposal |
uint256 | nonce | Nonce of the proposal |
address | loanContract | Loan type contract |
ProposalValues
struct
Type | Name | Comment |
---|---|---|
uint256 | collateralId | ID of the collateral to use. ID must be included in the merkle tree which root was submitted in the Proposal struct. |
bytes32[] | merkleInclusionProof | ID merkle inclusion proof |
bytes | acceptorControllerData | Data provided by proposal acceptor to be passed to the acceptor controller if defined in the Proposal struct |