Imagine a fintech startup needs a DeFi lending smart contract service that lets users deposit USDC as collateral and borrow ETH, with liquidation rules enforced by code. The idea sounds straightforward—until you ask what happens when ETH prices rise sharply or the pool runs short of liquidity. Those questions shape the smart contract development process before anyone writes the first function.
For this walkthrough, we’ll use Solidity, Hardhat, OpenZeppelin, and Chainlink price feeds. We’ll follow a hypothetical lending platform through architecture, development, testing, audit, and deployment, explaining the decisions behind each stage.
If you’re evaluating how to build a DeFi lending smart contract, this example should help you understand the engineering involved and what to ask a development partner. The snippets illustrate individual concepts; they aren’t a complete, deployable protocol.
Our platform uses a non-custodial, peer-to-pool model. Borrowers interact with shared liquidity rather than finding individual lenders. For an established reference, see how Aave’s lending pool architecture works.
The proposed scope includes:
- Collateral: USDC deposits.
- Borrowed asset: ETH, represented internally as WETH.
- Initial collateral requirement: At least 150% of the borrowed value.
- Interest: A variable rate linked to utilisation.
- Network: Ethereum mainnet, with a Layer 2 option.
- Core functions: deposit(), borrow(), repay(), liquidate(), and getHealthFactor().
There’s one essential dependency: liquidity providers must supply WETH. Depositing USDC as collateral doesn’t create ETH for borrowers.
The user’s wallet interacts with the LendingPool. The pool reads validated oracle prices, while a LiquidationManager checks whether a position qualifies for liquidation. External liquidators submit the transactions; contracts don’t wake up and execute themselves.
Choosing the Right Contract Structure
A monolithic contract keeps everything together but can become difficult to review as features grow. For this example, we’d separate three responsibilities:
- LendingPool: Deposits, borrowing, repayments, and balances.
- PriceOracle: Feed validation and price normalisation.
- LiquidationManager: Eligibility checks and collateral transfers.
This DeFi smart contract architecture makes responsibilities easier to inspect. It doesn’t automatically isolate every vulnerability: shared permissions and cross-contract calls still need careful review.
Upgradeability is a separate decision. A proxy enables changes but introduces administrator and storage-layout risks.
Key Data Structures
A simplified account could look like this:
struct UserAccount {
uint256 depositedAmount;
uint256 borrowedAmount;
uint256 lastInterestAccrual;
bool isActive;
}
mapping(address => UserAccount) public accounts;
depositedAmount records USDC collateral. borrowedAmount tracks WETH debt in this simplified model. lastInterestAccrual records when interest was last updated. isActive identifies an active account.
Production accounting also needs reserve totals, lender claims, and interest indexes.
Oracle Integration Decision
A thinly traded exchange’s spot price is a risky basis for lending decisions.
We’d validate ETH/USD and USDC/USD feeds, including positive prices, timestamps, and decimals. A one-hour freshness limit is only appropriate if it matches the selected feed’s update behaviour. The Chainlink DeFi price feeds documentation explains the underlying feed model.
The Deposit Function
A Solidity smart contract for lending needs reliable token transfers and consistent accounting.
This excerpt assumes the surrounding contract defines its token address, events, access controls, and OpenZeppelin dependencies:
using SafeERC20 for IERC20;
function deposit(uint256 amount)
external
nonReentrant
whenNotPaused
{
require(amount > 0, "Amount must be greater than zero");
accounts[msg.sender].depositedAmount += amount;
accounts[msg.sender].isActive = true;
IERC20(USDC).safeTransferFrom(
msg.sender,
address(this),
amount
);
emit Deposited(msg.sender, amount);
}
IERC20 provides the token interface. SafeERC20 handles transfer failures, including tokens that return false. If the transfer reverts, the accounting changes revert too. See OpenZeppelin’s ERC-20 utilities.
nonReentrant blocks nested entry into guarded functions, helping address the class of vulnerability made infamous by the DAO hack. It complements careful state management; it doesn’t replace it.
The Borrow Function with Health Factor Check
At 150% collateralisation, the maximum initial loan-to-value ratio is approximately 66.67%. Collateral worth $1,500 therefore supports up to $1,000 of initial debt.
Borrowing should accrue interest, fetch current validated prices, check available WETH, and evaluate the resulting position.
Health factor = collateral value × liquidation threshold ÷ debt value
The liquidation threshold is a separate parameter from the borrowing limit. For example, an illustrative 75% threshold leaves a buffer above a 66.67% initial loan-to-value ratio.
The Liquidation Mechanism
Liquidation becomes available below a health factor of 1.
For this pair, risk increases when USDC loses value, ETH rises, or interest accumulates. A liquidator repays eligible WETH debt and receives USDC collateral plus an incentive.
A 5% bonus means $100 repaid earns $105 of collateral—not precisely a 5% purchase discount. Partial liquidation can limit forced selling, but severely unhealthy positions may require more extensive liquidation.
Interest Rate Model
Calculate utilisation within the WETH reserve:
Utilisation = outstanding WETH debt ÷ (available WETH + outstanding WETH debt)
An illustrative model could target 2–5% annualised borrowing rates below an 80% utilisation kink, then increase rates more steeply.
A per-block model can accrue accumulated interest when users interact, as illustrated in Compound’s interest-accrual documentation. No transaction needs to run every block.
Common DeFi Attack Vectors We Test For
The test plan should cover ordinary transactions and attempts to break the protocol:
- Reentrancy: Protect sensitive entry points and inspect cross-contract interactions.
- Oracle manipulation: Reject invalid or stale prices; validate any TWAP fallback separately.
- Flash-loan-assisted attacks: Test whether temporary liquidity can distort collateral or accounting.
- Arithmetic errors: Check rounding, decimals, and unchecked operations.
- Access control: Test unauthorised upgrades, parameter changes, and pauses.
- Front-running: Test transaction ordering and execution limits; consider commitment schemes only where suitable.
A fallback price source can introduce new vulnerabilities. If neither source is trustworthy, blocking new risk may be safer than continuing with questionable prices.
Testing Stack
Use Hardhat for integration and mainnet-fork tests, with Foundry for fuzz and invariant testing.
For this project, set 100% function coverage as a pre-audit target, then examine branch coverage and failure cases. Coverage alone cannot prove that the lending economics work.
Pre-Audit Internal Review
Review implementation against the specification, inspect storage and loops, and test emergency controls. Pause behaviour should preserve safe repayment paths where feasible.
Ethereum’s smart contract security best practices provide useful guidance. Independent smart contract security audit services add another layer of scrutiny.
Internal review is necessary, but developers can overlook assumptions they’ve become accustomed to.
Euler’s March 2023 exploit is a reminder that lending failures can emerge from interactions between otherwise legitimate functions. Its published account of the incident and recovery offers valuable context.
For this build, the audit workflow should combine static analysis, using tools such as Slither, with manual review of accounting, liquidations, permissions, and upgrades.
Auditors need to ask more than “Does this compile?” They should examine whether valid transactions can leave lenders with unbacked debt.
Allow an illustrative one to three weeks for an initial review of a limited scope, plus time for fixes and retesting. A clean report describes findings within a particular scope and version. It is not a guarantee against exploitation.
The smart contract development and audit scope should explicitly include remediation.
Start with Sepolia and rehearse deposits, borrowing, repayment, liquidation, and emergency procedures. A two-to-four-week test window is a planning assumption, not proof of readiness.
Mainnet-fork testing remains important because testnet liquidity and oracle conditions differ from production.
For deployment:
- Use reviewed scripts and multisig-controlled administration.
- Verify contract addresses, parameters, and deployed source code.
- If upgradeability is required, use a reviewed proxy design such as OpenZeppelin’s TransparentUpgradeableProxy.
- Launch with conservative borrowing and deposit caps.
- Monitor oracle freshness, liquidity, health factors, and failed liquidations.
The incident plan must identify who can pause operations and how changes are approved. If DAO governance is planned, define its powers alongside emergency authority.
Ongoing blockchain development services should cover these operational responsibilities, not just contract deployment.
For this hypothetical scope, the initial planning assumptions are 8–14 weeks and $25,000–$60,000. These are illustrative figures, not verified Eminence quotations or universal market rates.
The estimate must specify whether it includes the interface, independent audits, remediation, infrastructure, and deployment.
Likewise, $3,000–$8,000 annually might describe limited maintenance, but shouldn’t be treated as a budget for continuous monitoring, emergency response, upgrades, and repeat audits.
Before approving a proposal, ask for deliverables, exclusions, and acceptance criteria. The same development phases apply across projects, while chain choice, asset behaviour, and governance change the work involved.
Start with the decisions that determine the system’s risk: supported assets, liquidity sources, borrowing limits, liquidation rules, and administrator powers. Those choices make a development brief far more useful than a feature list alone.
Eminence Technology’s DeFi lending protocol development services cover lending and borrowing platform development. Use the initial discussion to review the proposed architecture, relevant delivery experience, audit responsibilities, and post-launch support.
Discuss your DeFi lending requirements with Eminence Technology to define the scope, security needs, and delivery plan.






