# Solidity Interface for Uncollateralized Onchain Microfinance

By [Scott Onchain](https://paragraph.com/@scottonchain) · 2025-02-17

---

This is a technical specification for a smart contract interface, intended for implementation by a solidity engineer. For an overview of onchain microlending targeted to a more general reader, please see the article [Decentralized Onchain Microcredit](https://mirror.xyz/scottonchain.eth/gEHZUrusd_jY3KQtXJY-XOKKSu_Vlj9dNo_rnQhr4T8).

### Functions

*   `depositFunds(uint256 amount)`
    
    *   Allows lenders to deposit funds into the protocol. The amount is in USDC, scaaled to 6 decimals. For example, `1,000,000` corresponds to 1 USDC, and passing `5,000,000` corresponds to 5 USDC.
        
*   `previewLoanTerms`
    
    *   This function provides a _read-only_ preview of the loan terms for a given borrower, principal, and repayment period _before_ any state-changing action.
        
*   `requestLoan(uint256 amount) → (uint256 loanId)`
    
    *   Borrowers call this to request a certain principal amount (in scaled USDC). The contract looks up their credit score to determine the interest rate, repayment period, and other terms. It returns a `loanId` to track this loan.
        
*   `disburseLoan(uint256 loanId)`
    
    *   A follow-up function that actually sends the funds to the borrower. Depending on your logic, this might be part of `requestLoan`, or restricted so only the protocol (or an admin/oracle) can call it after validating the loan.
        
*   `repayLoan(uint256 loanId, uint256 amount)`
    
    *   Allows the borrower to repay part or all of the outstanding amount. In practice, this needs to update on-chain state, reduce the loan balance, and call the oracle to trigger updates to the borrower’s and attesters’ personalization vectors. It would also handle the distribution of the “attester reward” portion.
        
*   `recordAttestation(address borrower, uint256 weight)`
    
    *   Lets an attester vouch for a borrower’s creditworthiness. This is recorded on-chain and integrated with EAS. The `weight` is a value in the range \[0, 1\] scaled to 0-1000000.
        
*   `updateCreditScore(address user, uint256 newScore)`
    
    *   Because a reputation score is too expensive to compute on-chain, it is computed off-chain and updated on-chain via an oracle or a trusted service. This function is where that oracle posts the updated score.
        
*   `getCreditScore(address user) → (uint256 score)`
    
    *   A public/view function returning the on-chain record of someone’s credit score.
        
*   `getLoan(uint256 loanId)`
    
    *   A public/view function that returns structured data about the loan (principal, outstanding balance, borrower address, etc.).
        
*   `computeAttesterReward(uint256 loanId, address attester) → (uint256 reward)`
    
    *   A view function to calculate how much of the borrower’s latest repayment belongs to this attester, based on the attestation weight.
        

### Interest Rate Calculation

For the initial implementation, the interest rate is computed as follows:

$$interest(x)=r\_{min}​+(r\_{max}​−r\_{min}​)\\times(1−x)$$,

where

*   $$C\_i$$ is the borrower’s reputation score (between 0 and 1).
    
*   $$C\_{max}$$ is the maximum reputation score among all borrowers
    
*   $$x = {{C\_i}\\over{C\_{max}}}$$
    
*   $$⁡r\_{\\min}$$​ is the smallest interest rate offered (for $$ x=1$$),
    
*   ⁡$$r\_{\\max}$$ is the largest interest rate offered (for $$x=0$$).
    

### Interface Signature

    pragma solidity ^0.8.17;
    
    interface IDecentralizedMicrocredit {
        uint256 public rMin; 
        uint256 public rMax;
    
        /**
         * @notice Record an attestation of one participant's creditworthiness.
         * @dev Constructor takes the min and max interest rate.
         * @param _rMin, _rMax:  Min and max interest rate (varies by       
         *      reputation of borrower.  Default:  5% to 20%
         */
        constructor(uint256 _rMin, uint256 _rMax) 
        {
            require(_rMin < _rMax, "rMin must be < rMax");
            rMin = _rMin;
            rMax = _rMax;
        }
    
        /**
         * @notice Owner-only setter for interest rate range
         * @dev  This can update the interest rate range when needed.
         * @param _rMin, _rMax:  Min and max interest rate (varies by       
         *      reputation of borrower.
         */
        function setInterestRates(uint256 _rMin, uint256 _rMax) external onlyOwner {
            require(_rMin < _rMax, "rMin must be < rMax");
            rMin = _rMin;
            rMax = _rMax;
        }
    
        /**
         * @notice Deposit funds into the protocol as a lender.
         * @dev Implemented as ERC20 transferFrom in USDC.
         * @param amount Amount of USDC to deposit.
         */
        function depositFunds(uint256 amount) external;
    
        /**
         * @notice Previews the loan terms for a potential borrower,
         *      duration, and principal amount.
         * @dev 
         *  - This is a `view` function and does not alter on-chain state.
         *  - The returned values can be used by a front end to understand 
         *         the interest rate, repayment schedule, and other loan     
         *         conditions before actually requesting the loan.
         * @param borrower The address requesting the loan.
         * @param principal The requested loan amount (6-decimal USDC).
         * @param repaymentPeriod The requested repayment period (in seconds).
         * @return interestRate The annualized interest rate for this loan,       
         *         expressed in basis points
         *         (i.e., 100 = 1%, 250 = 2.50%, etc.).
         * @return payment The estimated periodic payment amount, 
         *     in 6-decimal USDC units, due every 30 days.
         */
        function previewLoanTerms(
            address borrower, 
            uint256 principal,
            uint256 repaymentPeriod
        )
            external 
            view
            returns (
                uint256 interestRate,
                uint256 payment
            );
    
        /**
         * @notice Request a new microloan.
         * @dev See the notes for the interest rate. 
         * @param amount The requested principal amount in USDC.
         * @return loanId A unique identifier for the newly created loan.
         */
        function requestLoan(uint256 amount) external returns (uint256 loanId);
    
        /**
         * @notice Disburse an approved loan to the borrower.
         * @dev This function might be restricted so only the protocol
         *      can call it after validating the loan terms.
         * @param loanId The ID of the loan being disbursed.
         */
        function disburseLoan(uint256 loanId) external;
    
        /**
         * @notice Repay an existing loan (principal + interest +
         * attester rewards).
         * @dev Must do these:
         *       * track payment progress
         *       * update the pagerank personalization vector 
         *       * distribute attester rewards
         *       *  handle partial or full repayments.
         * @param loanId The ID of the loan to repay.
         * @param amount Amount sent for repayment (USDC).
         */
        function repayLoan(uint256 loanId, uint256 amount) external;
    
        /**
         * @notice Record an attestation of one participant's creditworthiness.
         * @dev Weight can be a value from 0 to 1 
         *     (scale up, 0–1000000 for integer parameter).
         * @param borrower The address of the borrower being attested to.
         * @param weight 
         *      A measure of how strongly the attester 
         *      vouches for the borrower, scaled to 0-1e6
         */
        function recordAttestation(address borrower, uint256 weight) external;
    
        /**
         * @notice Update a participant's credit score.
         * @dev This should be restricted to an oracle that calculates
         *      reputation scores off-chain and posts them on-chain.
         * @param user The address whose credit score is being updated.
         * @param newScore The new credit score of the user.
         */
        function updateCreditScore(address user, uint256 newScore) external;
    
        /**
         * @notice Retrieve the current credit score for a given address.
         * @param user The address to look up.
         * @return score The current on-chain credit score of the user 
         *      (retrieved from an oracle).
         */
        function getCreditScore(address user) external view returns (uint256 score);
    
        /**
         * @notice Fetch details of a loan, e.g. principal, interest, borrower, outstanding balance.
         * @param loanId The ID of the loan to fetch.
         * @return principal The original principal.
         * @return outstanding The current remaining balance.
         * @return borrower The address of the borrower.
         * @return interestRate The interest rate scaled to 0-1000000
         * @return isActive Whether the loan is still active 
         *   (not fully repaid or defaulted).
         */
        function getLoan(uint256 loanId)
            external
            view
            returns (
                uint256 principal,
                uint256 outstanding,
                address borrower,
                uint256 interestRate,
                bool isActive
            );
        
        /**
         * @notice Compute the reward owed to an attester for a specific loan.
         * @param loanId The ID of the loan.
         * @param attester The address of the attester.
         * @return reward The amount of reward owed to the attester, 
         *     scaled by x100 (so that dollars and cents are scaled 
         to an integer.
         */
        function computeAttesterReward(uint256 loanId, address attester)
            external
            view
            returns (uint256 reward);
    }

---

*Originally published on [Scott Onchain](https://paragraph.com/@scottonchain/solidity-interface-for-uncollateralized-onchain-microfinance)*
