A decentralised lending protocol built on Ethereum. Deposit WETH as collateral, borrow USDC at 10% APR, and manage your position through a clean on-chain UI.
| Action | Description |
|---|---|
| Deposit | Lock WETH as collateral, receive iCOL receipt tokens 1:1 |
| Borrow | Borrow USDC up to 80% of collateral USD value |
| Repay | Pay back USDC debt (interest accrues per-second at 10% APR) |
| Withdraw | Reclaim WETH collateral (health factor must stay ≥ 1) |
| Supply | Provide USDC liquidity to the pool |
| Liquidate | Repay an undercollateralised position and claim collateral + 5% bonus |
Prices are fed by Chainlink ETH/USD with a staleness check (3-hour timeout). The protocol freezes if the feed goes stale rather than acting on bad data.
Contracts
- Solidity
^0.8.24 - Foundry (forge, cast, anvil)
- OpenZeppelin v5 (IERC20, ERC20Mock)
- Chainlink AggregatorV3Interface
Frontend
- Next.js 14 (App Router)
- wagmi v2 + viem
- RainbowKit
- Tailwind CSS v4
lending-protocol/
├── contracts/ # Foundry project
│ ├── src/
│ │ ├── LendingPool.sol
│ │ ├── InterestToken.sol
│ │ ├── interfaces/
│ │ │ └── AggregatorV3Interface.sol
│ │ ├── libraries/
│ │ │ └── OracleLib.sol
│ │ └── mocks/
│ │ └── MockV3Aggregator.sol
│ ├── script/
│ │ ├── Deploy.s.sol
│ │ └── HelperConfig.s.sol
│ ├── test/
│ │ └── LendingPoolTest.t.sol
│ └── foundry.toml
└── frontend/ # Next.js project
├── src/
│ ├── app/
│ │ └── page.tsx
│ ├── components/
│ │ ├── ActionPanel.tsx
│ │ └── PositionCard.tsx
│ ├── hooks/
│ │ └── useLendingPool.ts
│ ├── contracts/
│ │ ├── abis.ts
│ │ └── addresses.json
│ └── lib/
│ └── wagmi.ts
└── package.json
- Foundry —
curl -L https://foundry.paradigm.xyz | bash && foundryup - Node.js v18+
- MetaMask browser extension
git clone https://github.com/Ab-hai/lending-protocol.git
cd lending-protocolInstall contract dependencies:
cd contracts
forge installInstall frontend dependencies:
cd frontend
npm installanvilLeave this running. Anvil starts at http://127.0.0.1:8545 with 10 funded accounts. The default account 0xf39Fd6... is what MetaMask uses when you add the Anvil network.
cd contracts
forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcastThe script:
- Deploys
LendingPool,InterestToken, mock WETH, mock USDC, andMockV3Aggregator - Seeds the pool with 500,000 USDC liquidity
- Mints 100 WETH + 10,000 USDC to Anvil accounts #0 and #1 for testing
Copy the printed contract addresses into frontend/src/contracts/addresses.json:
{
"lendingPool": "0x...",
"iToken": "0x...",
"weth": "0x...",
"usdc": "0x..."
}Add a custom network in MetaMask:
| Field | Value |
|---|---|
| Network name | Anvil Local |
| RPC URL | http://127.0.0.1:8545 |
| Chain ID | 31337 |
| Currency symbol | ETH |
Import a test account using one of the private keys printed by anvil on startup. Account #0's key is always:
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
⚠️ Never use this key for anything other than local testing.
cd frontend
npm run devOpen http://localhost:3000.
cd contracts
forge test -vvRun with gas report:
forge test --gas-reportUse any Sepolia faucet:
- https://sepoliafaucet.com
- https://faucet.quicknode.com/ethereum/sepolia
- Alchemy or Infura dashboards (free tier)
You need at least 0.1 ETH to cover deployment gas.
Create contracts/.env:
PRIVATE_KEY=0xyour_deployer_private_key
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/your_api_key
ETHERSCAN_API_KEY=your_etherscan_api_keyGet a free RPC URL from Alchemy or Infura.
Get an Etherscan API key from etherscan.io/myapikey (used for contract verification).
Load the variables:
source contracts/.envcd contracts
forge script script/Deploy.s.sol \
--rpc-url $SEPOLIA_RPC_URL \
--broadcast \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY--verify uploads the source code to Etherscan automatically. After a minute you'll be able to read and write the contract directly on Etherscan.
The deploy script prints all addresses. Paste them into frontend/src/contracts/addresses.json.
The Sepolia Chainlink ETH/USD feed (0x694AA1769357215DE4FAC081bf1f309aDC325306) and token addresses are already hardcoded in HelperConfig.s.sol — no changes needed there.
| Contract | Address |
|---|---|
| LendingPool | 0x... |
| InterestToken (iCOL) | 0x... |
| WETH (Sepolia) | 0xdd13E55209Fd76AfE204dBda4007C227904f0a81 |
| USDC (Aave Sepolia) | 0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8 |
| ETH/USD Price Feed | 0x694AA1769357215DE4FAC081bf1f309aDC325306 |
Update the first two rows after your Sepolia deployment.
| Parameter | Value |
|---|---|
| Collateral asset | WETH |
| Borrow asset | USDC |
| Loan-to-value (LTV) | 80% |
| Liquidation threshold | 90% |
| Liquidation bonus | 5% |
| Borrow APR | 10% (linear, per-second) |
| Oracle staleness timeout | 3 hours |
This is a learning project and has not been audited. Do not use it with real funds on mainnet.
Known limitations:
- Interest model is linear (not compound) — real protocols use compound interest
- Single collateral asset only
- No governance or upgradability
- Liquidity providers earn no yield (interest goes to the protocol, not tracked)
- Cyfrin Updraft — DeFi course structure and DSCEngine patterns
- Chainlink — Price feed infrastructure
- OpenZeppelin — ERC20 standards