For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

  1. A lender provides a loan offer with specific terms

  2. A borrower creates a loan using their ERC20 tokens as collateral

  3. The loan is created when the borrower accepts an offer

  4. The borrower repays the loan within the specified term

  5. If the borrower defaults, the lender or a liquidator can trigger a full liquidation to claim the ERC20 collateral

  6. The loan can be partially liquidated if the Loan-to-Value (LTV) ratio exceeds a certain threshold

  7. The lender can "call" a loan, initiating a repayment window before maturity

  8. Borrowers can add or remove collateral from an ongoing loan

  9. A loan may be replaced by the borrower while still ongoing, by accepting a new offer (refinancing)

  10. 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 via delegatecall) handling loan refinancing logic.

  • P2PLendingLiquidation.vy: A facet contract (called via delegatecall) 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:

  1. Support for any ERC20 token as collateral, specified at deployment

  2. Use of an ERC20 token (e.g., USDC) as a payment token, defined at deployment time for each instance of P2PLendingErc20

  3. Integration with an oracle (Chainlink AggregatorV3) for collateral valuation

  4. All participants (borrower and lender) must have valid KYC attestations signed by a whitelisted KYC validator.

  5. Loan terms are part of the lender's offers, which are signed and kept off-chain

  6. Offers have an expiration timestamp and can be revoked on-chain

  7. Loans can be callable by the lender after a specified call_eligibility period, starting a call_window for repayment before default

  8. Loans can be partially liquidated if the LTV exceeds a partial_liquidation_ltv threshold

  9. Dynamic collateral management (add/remove collateral tokens) is supported

  10. Additional fees are supported for both the protocol (upfront and settlement) and for the lender (origination)

  11. 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 P2PLendingRefinance facet.

  • 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:

  1. Offer Structure: An offer is defined by the Offer structure (from P2PLendingBase), which includes:

    • principal: Principal amount of the loan (optional, can be 0 for borrower-defined)

    • apr: Annual Percentage Rate

    • payment_token: Address of the payment ERC20 token

    • collateral_token: Address of the collateral ERC20 token

    • duration: Duration of the loan in seconds

    • origination_fee_bps: Origination fee percentage (in basis points) paid to the lender

    • min_collateral_amount: Minimum amount of collateral required (optional)

    • max_iltv: Maximum Initial Loan-to-Value (optional, used if min_collateral_amount isn't specified)

    • available_liquidity: The total principal amount the lender has allocated to this offer

    • call_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 valuation

    • expiration: Expiration timestamp of the offer

    • lender: Address of the lender

    • borrower: 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

  2. Signed Offers: Lenders create and sign offers off-chain. These signed offers (SignedOffer) combine the Offer structure with an EIP-712 signature.

  3. 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_token and collateral_token match the contract's configuration, and if the oracle_addr is valid.

  4. Offer Utilization: Offers track available_liquidity and commited_liquidity (per tracing_id). When an offer is used to create a loan, the loan's principal is deducted from the offer's available_liquidity (via commited_liquidity), preventing overuse beyond the specified limit.

  5. 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 expiration timestamp, after which it cannot be used

  • Offers can be revoked before expiration by calling revoke_offer in P2PLendingErc20

  • Each offer has available_liquidity to define the maximum total principal that can be lent through it

Loans

  1. 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.Loan struct). Initial LTV is checked against max_iltv. The ERC20 collateral is transferred to a dedicated P2PLendingVault for the borrower. If a vault doesn't exist for the borrower, it's created via CREATE2.

  2. 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's P2PLendingVault back to the borrower.

  3. Defaulted Loan Collateral Claim (liquidate_loan): If a loan defaults (either by reaching maturity or failing to repay within call_window after a call_loan), the lender or any other party (3rd party liquidator) can trigger a full liquidation via liquidate_loan (handled by the P2PLendingLiquidation facet). The collateral is transferred to the lender (or liquidator for a fee) without any fund transfers. The collateral is transferred from the borrower's P2PLendingVault.

  4. Partial Liquidation (partially_liquidate_loan): If the current Loan-to-Value (LTV) ratio of an active loan exceeds the partial_liquidation_ltv threshold defined in the offer, any address can trigger a partial liquidation via partially_liquidate_loan (handled by the P2PLendingLiquidation facet). 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_time is reset to the current block.timestamp.

    • The goal is to bring the LTV back to the initial_ltv ratio, thereby "healing" the loan.

    • Collateral is claimed from the borrower's P2PLendingVault.

  5. Call Loan (call_loan): Lenders can initiate a loan call if the call_eligibility period has passed and the loan is not yet called or defaulted. This sets a call_time timestamp, and the borrower then has call_window seconds to repay the loan before it automatically defaults.

  6. 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's P2PLendingVault.

  7. Remove Collateral (remove_collateral_from_loan): Borrowers can remove collateral from an ongoing loan as long as the remaining collateral is at least min_collateral_amount and the LTV does not exceed the initial_ltv (to prevent immediately increasing risk beyond the initial agreement). The collateral is withdrawn from the borrower's P2PLendingVault.

  8. 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 the P2PLendingRefinance facet, 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.

  9. 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 the P2PLendingRefinance facet. 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.

  10. Loan Borrower Transfer (transfer_loan): The transfer_loan function allows a privileged transfer_agent to 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's P2PLendingVault to the new borrower's P2PLendingVault (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_wallet when the loan is created. Configurable by the owner.

  • Protocol Settlement Fee: A percentage (in basis points) of the interest, paid to the protocol_wallet during 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 Offer structure.

  • 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 by loan.borrower. Can settle loans, add/remove collateral, and initiate loan replacements.

  • Lender: The provider of the loan, identified by loan.lender. Can initiate loan replacements and claim collateral for defaulted loans, and call loans.

  • Liquidator: Any address that can trigger a partially_liquidate_loan or liquidate_loan if the LTV conditions are met. Receives the partial_liquidation_fee or full_liquidation_fee for performing this action.

  • KYC Validator: An external address registered in the KYCValidator contract 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:

  1. Authorized Proxies: The contract maintains a mapping of authorized_proxies: public(HashMap[address, bool]). The contract owner can set or revoke proxy authorization using set_proxy_authorization.

  2. User Checks: An internal function _check_user verifies if the msg.sender is the expected user or an authorized_proxies[msg.sender] acting on behalf of tx.origin. This is used for user-specific actions (e.g., settling loans, revoking offers).

  3. Proxy Usage: When an authorized proxy calls a function, tx.origin is used to identify the actual user, allowing proxies to perform actions on behalf of users while maintaining access control.

  4. Security Considerations: Only the contract owner can authorize or deauthorize proxies. tx.origin is only considered when the msg.sender is an authorized proxy; otherwise, msg.sender is 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

  1. Partial Liquidation: Protects against market volatility without full liquidation.

  2. Callable Loans: Provides flexibility for lenders while protecting borrowers.

  3. Dynamic Collateral Management: Allows borrowers to adjust collateral levels.

  4. KYC Integration: Ensures regulatory compliance through signed validations.

  5. Gas Optimization: Externalized state design reduces transaction costs.

  6. Refinancing Support: Both borrowers and lenders can replace existing loans.

  7. 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