Protocol - Lending Pro
Introduction
This protocol implements a peer-to-peer lending system for ERC20 tokens. It allows ERC20 token owners to use their assets as collateral to borrow cryptocurrency, while lenders can provide loans and earn interest. The protocol is designed to be trustless, efficient, and flexible, with support for various ERC20 tokens as collateral. It also includes features for dynamic collateral management, partial liquidations, and loan refinancing. The protocol introduces a robust vault system for enhanced compliance and isolated collateral management.
Overview
The protocol is implemented in Vyper 0.4.3. The main component is the P2PLendingErc20 contract, which supports peer-to-peer lending backed by ERC20 collateral. It utilizes P2PLendingBase for shared state and common logic, P2PLendingRefinance as a facet for complex refinancing operations, P2PLendingLiquidation as a facet for liquidation operations, and interacts with a KYCValidator contract for compliance checks, and finally, a P2PLendingVault contract for collateral handling.
Defining a "market" as the pair <CollateralToken, PrincipalToken> , each market has its own set of smart contracts to isolate risk and enhance compliance. For the latter, the protocol introduces a novel dedicated vault system where, for each market and each borrower, the collateral tokens of all that borrower's loans are placed inside a dedicated vault. The vault is a smart contract that acts as an escrow for the collateral tokens during loans.
The lending in the context of this protocol means that:
A lender provides a loan offer with specific terms
A borrower creates a loan using their ERC20 tokens as collateral
The loan is created when the borrower accepts an offer
The borrower repays the loan within the specified term
If the borrower defaults, the lender or a liquidator can trigger a full liquidation to claim the ERC20 collateral
The loan can be partially liquidated if the Loan-to-Value (LTV) ratio exceeds a certain threshold
The lender can "call" a loan, initiating a repayment window before maturity
Borrowers can add or remove collateral from an ongoing loan
A loan may be replaced by the borrower while still ongoing, by accepting a new offer (refinancing)
The lender may replace a loan while it is still ongoing, under certain defined conditions (lender-initiated refinancing)
Core Contracts
The protocol consists of the following core contracts:
P2PLendingErc20.vy: The main entry point for users to interact with the lending protocol, incorporating the vault system.P2PLendingBase.vy: An abstract base contract that holds core state variables and implements common internal logic, including vault interactions.P2PLendingRefinance.vy: A facet contract (called viadelegatecall) handling loan refinancing logic.P2PLendingLiquidation.vy: A facet contract (called viadelegatecall) handling loan liquidation logic.P2PLendingVault.vy: A minimal proxy factory and implementation for individual borrower collateral vaults, deployed via CREATE2. Each vault holds the collateral for a borrower's loans and provides isolated management.KYCValidator.vy: A contract responsible for validating signed KYC attestations for borrowers and lenders.
General considerations
The current status of the protocol follows certain assumptions:
Support for any ERC20 token as collateral, specified at deployment
Use of an ERC20 token (e.g., USDC) as a payment token, defined at deployment time for each instance of
P2PLendingErc20Integration with an oracle (Chainlink AggregatorV3) for collateral valuation
All participants (borrower and lender) must have valid KYC attestations signed by a whitelisted KYC validator.
Loan terms are part of the lender's offers, which are signed and kept off-chain
Offers have an expiration timestamp and can be revoked on-chain
Loans can be callable by the lender after a specified
call_eligibilityperiod, starting acall_windowfor repayment before defaultLoans can be partially liquidated if the LTV exceeds a
partial_liquidation_ltvthresholdDynamic collateral management (add/remove collateral tokens) is supported
Additional fees are supported for both the protocol (upfront and settlement) and for the lender (origination)
A vault system (
P2PLendingVault) to hold collateral. Each borrower in each market has a unique vault, deployed via CREATE2, enhancing collateral isolation and compliance
Architecture

The P2PLendingErc20.vy contract serves as the main entry point. It uses P2PLendingBase.vy for common logic and state, which has been updated to interact with the P2PLendingVault system. Each borrower has a unique, minimal proxy vault deployed via CREATE2 (P2PLendingVault), which securely holds their collateral. Refinancing and liquidation logic are handled by P2PLendingRefinance.vy and P2PLendingLiquidation.vy facets, respectively, which also interact with the vaults. The KYCValidator.vy remains an external dependency.
Users and other protocols should primarily interact with the P2PLendingErc20.vy contract. This contract is responsible for:
Creating loans based on signed offers and collateral tokens, including KYC validation (collateral deposited into the borrower's dedicated vault)
Settling loans and distributing funds (collateral withdrawn from the vault and returned to the borrower)
Handling defaulted loans by allowing lenders to claim collateral (collateral transferred from the borrower's vault to the lender)
Performing partial liquidations based on LTV thresholds (collateral transferred from the borrower's vault to the liquidator/lender)
Initiating loan calls by lenders
Allowing borrowers to add or remove collateral from existing loans (collateral deposited into/withdrawn from the borrower's vault)
Facilitating loan refinancing for both borrowers and lenders via the
P2PLendingRefinancefacet.Managing protocol fees and authorized proxies
Revoking unused offers
Supporting loan transfers to new borrowers, including transferring collateral ownership in their respective vaults
Offers
Loans are created based on the borrower's acceptance of offers from lenders, which specify the loan terms. The general features of an offer are:
Offer Structure: An offer is defined by the
Offerstructure (fromP2PLendingBase), which includes:principal: Principal amount of the loan (optional, can be 0 for borrower-defined)apr: Annual Percentage Ratepayment_token: Address of the payment ERC20 tokencollateral_token: Address of the collateral ERC20 tokenduration: Duration of the loan in secondsorigination_fee_bps: Origination fee percentage (in basis points) paid to the lendermin_collateral_amount: Minimum amount of collateral required (optional)max_iltv: Maximum Initial Loan-to-Value (optional, used ifmin_collateral_amountisn't specified)available_liquidity: The total principal amount the lender has allocated to this offercall_eligibility: Time in seconds after loan start when the lender can call the loan (0 if not callable)call_window: Time in seconds after a loan is called for the borrower to repay before default (0 if not callable)partial_liquidation_ltv: LTV threshold (in basis points) for partial liquidation (0 if not applicable)oracle_addr: Address of the oracle contract for collateral valuationexpiration: Expiration timestamp of the offerlender: Address of the lenderborrower: Specific borrower address for the offer (empty address for general offers)tracing_id: A unique identifier for tracking offers, enabling multiple loans from one offer
Signed Offers: Lenders create and sign offers off-chain. These signed offers (
SignedOffer) combine theOfferstructure with an EIP-712 signature.Offer Validation: When a borrower wants to create a loan using an offer, the protocol verifies the offer's signature, checks if it's still valid (not expired), and if the
payment_tokenandcollateral_tokenmatch the contract's configuration, and if theoracle_addris valid.Offer Utilization: Offers track
available_liquidityandcommited_liquidity(pertracing_id). When an offer is used to create a loan, the loan's principal is deducted from the offer'savailable_liquidity(viacommited_liquidity), preventing overuse beyond the specified limit.Offer Revocation: Lenders can revoke their offers before they expire or are fully utilized. This is a one-time revocation per offer ID.
As offers are kept off-chain, to prevent abusive usage, several on-chain validations are in place:
Each offer has an
expirationtimestamp, after which it cannot be usedOffers can be revoked before expiration by calling
revoke_offerinP2PLendingErc20Each offer has
available_liquidityto define the maximum total principal that can be lent through it
Loans
Loan Creation (
create_loan): The process involves verifying the offer's signature and validity, along with KYC validation for both borrower and lender. The principal amount, minus upfront fees, is then transferred from the lender to the borrower. Upfront fees are distributed, and a loan record is created (base.Loanstruct). Initial LTV is checked againstmax_iltv. The ERC20 collateral is transferred to a dedicatedP2PLendingVaultfor the borrower. If a vault doesn't exist for the borrower, it's created via CREATE2.Loan Settlement (
settle_loan): To settle a loan, the contract calculates the total repayment amount (principal + accrued interest + protocol settlement fee). The borrower transfers this amount to the contract, which then distributes the funds to the lender and the protocol wallet. The ERC20 collateral is transferred from the borrower'sP2PLendingVaultback to the borrower.Defaulted Loan Collateral Claim (
liquidate_loan): If a loan defaults (either by reachingmaturityor failing to repay withincall_windowafter acall_loan), the lender or any other party (3rd party liquidator) can trigger a full liquidation vialiquidate_loan(handled by theP2PLendingLiquidationfacet). The collateral is transferred to the lender (or liquidator for a fee) without any fund transfers. The collateral is transferred from the borrower'sP2PLendingVault.Partial Liquidation (
partially_liquidate_loan): If the current Loan-to-Value (LTV) ratio of an active loan exceeds thepartial_liquidation_ltvthreshold defined in the offer, any address can trigger a partial liquidation viapartially_liquidate_loan(handled by theP2PLendingLiquidationfacet). In this process:A portion of the outstanding debt is "written off" (reduced).
A corresponding amount of collateral is claimed from the loan.
A
partial_liquidation_fee(in collateral tokens) is applied and sent to the liquidator. The remaining claimed collateral (if any) is sent to the lender.The loan's
accrual_start_timeis reset to the currentblock.timestamp.The goal is to bring the LTV back to the
initial_ltvratio, thereby "healing" the loan.Collateral is claimed from the borrower's
P2PLendingVault.
Call Loan (
call_loan): Lenders can initiate a loan call if thecall_eligibilityperiod has passed and the loan is not yet called or defaulted. This sets acall_timetimestamp, and the borrower then hascall_windowseconds to repay the loan before it automatically defaults.Add Collateral (
add_collateral_to_loan): Borrowers can add more ERC20 collateral to an ongoing loan at any time, which reduces the loan's LTV. The collateral is deposited into the borrower'sP2PLendingVault.Remove Collateral (
remove_collateral_from_loan): Borrowers can remove collateral from an ongoing loan as long as the remaining collateral is at leastmin_collateral_amountand the LTV does not exceed theinitial_ltv(to prevent immediately increasing risk beyond the initial agreement). The collateral is withdrawn from the borrower'sP2PLendingVault.Loan Replacement by Borrower (
replace_loan): A borrower can refinance an existing loan by accepting a new offer (which might be from the same or a different lender). The function, handled by theP2PLendingRefinancefacet, effectively settles the old loan and creates a new one using the same collateral. Liquidity adjustments are made for both borrower and lender, and any difference in collateral amount is transferred. KYC for the new lender is required. The collateral remains within the borrower's vault, with only internal adjustments if the amount changes.Loan Replacement by Lender (
replace_loan_lender): A lender can initiate a replacement of an existing loan, effectively selling it to a new lender or refinancing it themselves. This is handled by theP2PLendingRefinancefacet. The borrower's terms are protected, ensuring:No additional liquidity is required from the borrower.
The borrower's repayment obligations (principal, interest, call eligibility, LTV thresholds) under the new conditions are not worse than the original loan's conditions up until the original loan's maturity.
Any necessary compensation is calculated and handled by the protocol.
Loan Borrower Transfer (
transfer_loan): Thetransfer_loanfunction allows a privilegedtransfer_agentto change the borrower of an existing loan. This is designed to support special cases (e.g., death, lost keys, or legal transfers). When a loan is transferred, the collateral is also moved from the old borrower'sP2PLendingVaultto the new borrower'sP2PLendingVault(creating it if necessary).
Fees
The protocol supports several types of fees:
Protocol Upfront Fee: A percentage (in basis points) of the principal, paid to the
protocol_walletwhen the loan is created. Configurable by the owner.Protocol Settlement Fee: A percentage (in basis points) of the interest, paid to the
protocol_walletduring loan settlement. Configurable by the owner.Origination Fee: An upfront fee (in basis points of the principal) paid to the lender when a loan is created. It is part of the loan terms defined in the
Offerstructure.Partial Liquidation Fee: A percentage (in basis points) of the claimed collateral value, paid to the liquidator during a partial liquidation. Configurable by the owner.
Full Liquidation Fee: A percentage (in basis points) of the claimed collateral value, paid to the liquidator during a full liquidation. Configurable by the owner.
All upfront fees are paid during loan creation, while settlement fees are paid as a fraction of the interest amount during loan settlement.
Roles
The protocol defines the following key roles:
Owner: The privileged address that can update protocol-wide parameters (e.g., protocol fees, partial/full liquidation fees), manage authorized proxies, and propose/claim ownership.Borrower: The recipient of the loan, identified byloan.borrower. Can settle loans, add/remove collateral, and initiate loan replacements.Lender: The provider of the loan, identified byloan.lender. Can initiate loan replacements and claim collateral for defaulted loans, and call loans.Liquidator: Any address that can trigger apartially_liquidate_loanorliquidate_loanif the LTV conditions are met. Receives thepartial_liquidation_feeorfull_liquidation_feefor performing this action.KYC Validator: An external address registered in theKYCValidatorcontract that signs wallet attestations, ensuring compliance.Transfer Agent: A privileged address that can transfer a loan's ownership to a new borrower, primarily for compliance and recovery scenarios.
Proxy Support
The P2PLendingErc20 contract includes support for authorized proxies, allowing for more flexible interaction with the protocol. This feature is particularly useful for integrations with other protocols or for implementing advanced user interfaces.
Key aspects of proxy support include:
Authorized Proxies: The contract maintains a mapping of
authorized_proxies: public(HashMap[address, bool]). The contract owner can set or revoke proxy authorization usingset_proxy_authorization.User Checks: An internal function
_check_userverifies if themsg.senderis the expected user or anauthorized_proxies[msg.sender]acting on behalf oftx.origin. This is used for user-specific actions (e.g., settling loans, revoking offers).Proxy Usage: When an authorized proxy calls a function,
tx.originis used to identify the actual user, allowing proxies to perform actions on behalf of users while maintaining access control.Security Considerations: Only the contract owner can authorize or deauthorize proxies.
tx.originis only considered when themsg.senderis an authorized proxy; otherwise,msg.senderis used for authentication.
Oracles
Zharta uses Chainlink's industry-standard decentralized oracles as its primary data source, providing highly secure, reliable, and tamper-resistant data feeds across crypto and RWA.
Chainlink oracles are used across our Ethereum Mainnet instance:
BTC
USD
cbBTC
USD
USDC
WETH
Key Innovations
Partial Liquidation: Protects against market volatility without full liquidation.
Callable Loans: Provides flexibility for lenders while protecting borrowers.
Dynamic Collateral Management: Allows borrowers to adjust collateral levels.
KYC Integration: Ensures regulatory compliance through signed validations.
Gas Optimization: Externalized state design reduces transaction costs.
Refinancing Support: Both borrowers and lenders can replace existing loans.
Vault Collateral System (v2): Individualized, minimal proxy vaults for each borrower's collateral, improving security, compliance, and asset segregation.
The protocol represents a significant advancement in DeFi lending by providing sophisticated risk management tools while maintaining user-friendly operations.
Future Enhancements
Potential future developments include:
Support for multiple collateral types.
Cross-chain functionality.
Advanced risk management features.
Governance mechanisms for protocol upgrades.
Insurance integration options.
Last updated