Interest Rate Model Explorer

A live demo of the kinked interest rate curve nearly every DeFi lending protocol uses: gentle while the pool has spare liquidity, steep once it does not. Every parameter is fixed at deployment — no owner, no setter, no upgrade path — and every figure on this page is read straight off the contract on Base Sepolia.

BaseBase Sepolia · testnet only

This demo is read-only. There is no wallet to connect and nothing to sign: every function on the contract is a view, so the whole page — including the slider below — is built from eth_call. You will not be asked for a signature and you will not spend any gas.

Model 0x3F5F…CeC8 · Deployed in block 44788685, tx 0xbd8b…d760 · Source on GitHub

Watch: 30 seconds

What a kinked curve is

A lending pool has to answer one question continuously: given how much of it is currently lent out — its utilization — what should borrowers pay, and what should suppliers earn?

A single straight line does not work. If the rate rises evenly from empty to full, taking the last of the pool costs barely more than taking the first, and a pool that runs dry cannot honor withdrawals. So the curve has two segments joined at a bend called the kink: below it the rate rises gently, above it steeply. The steep half is what makes the final slice of liquidity expensive to borrow and profitable to replace.

borrow rate
  ^
  |                                        /
  |                                      /   <- slope2, steep
  |                                    /
  |                        __________/       <- the kink
  |             __________/
  |  __________/                             <- slope1, gentle
  | /
  +-------------------------------------> utilization
  0                       kink            100%

The parameters, read from the chain

These six numbers are the contract. It has no setter, so what was passed to the constructor is what it means forever — which is why this table is read from the deployed contract on every page load rather than written into this page. A hardcoded table would be asserting that the curve cannot change; reading it demonstrates it.

Constructor argumentWhat it doesValueOn chain (WAD)
baseRatePerYear charged on a pool with nothing lent out 2.00% 20000000000000000
slope1PerYear added across the whole first segment, from idle to the kink 8.00% 80000000000000000
kink the utilization at which the curve steepens 80.00% 800000000000000000
slope2PerYear added across the second segment, from the kink to fully lent out 100.00% 1000000000000000000
reserveFactor the share of borrow interest the protocol keeps 10.00% 100000000000000000
maxBorrowRatePerYear the ceiling — the rate at 100% utilization, derived at construction 110.00% 1100000000000000000

Read at block 44792366. Every value is WAD-scaled: 1e18 means 1.0, so a rate of 20000000000000000 is 2% per year. The right-hand column is exactly what Basescan’s Read Contract tab returns, so you can check this page against the chain without scaling anything by hand.

The curve

UtilizationBorrow rateSupply rate
0% 2.00% 0.00%
25% 4.50% 1.01%
50% 7.00% 3.15%
80% the kink 10.00% 7.20%
90% 60.00% 48.60%
95% 85.00% 72.67%
100% 110.00% 99.00%

The supply rate is always the lower of the two, and not only because of the reserve factor: borrowers pay interest on the borrowed portion, while suppliers are paid across everything they supplied, lent out or idle. At 50% utilization half the pool is earning nothing, which is most of the gap you can see in the table.

The seam

The kink is the one place a fixed-point model breaks if it breaks at all: it is where two different formulas have to agree, to the wei. Here is the deployed contract asked for the borrow rate one wei either side of it.

UtilizationBorrow rateOn chain (WAD)
kink − 1 wei10.00%100000000000000000
kink — 80.00%10.00%100000000000000000
kink + 1 wei10.00%100000000000000005

The gentle segment arrives at exactly the value the steep segment starts from — the two middle figures are the same integer, not merely close. One wei further and the rate moves by 5, which is the steep segment’s rise per wei of utilization. That is what “no step at the kink” means for a function on the integers, where no jump cannot mean no change at all.

A worked pool

A pool holding 150 idle, with 50 lent out and 25 held as protocol reserves. Reserves come out of the denominator because they are not lending capacity, so the ratio is 50 over 175 — and the contract, not this page, computes it: 28.57% utilization, a borrow rate of 4.85% and a supply rate of 1.24%.

Move the utilization

  • Utilization
  • Borrow rate
  • Supply rate

Each move reads the deployed contract with eth_call. No wallet, no signature, no gas.


How it is verified

The contract passes the Pigfox Solidity pipeline on every push: formatting, build, tests, 100% line, statement, branch and function coverage with no exclusions, Slither at fail-on: low, and property fuzzing under both Echidna and Medusa.

Eight invariants are claimed — not for the one curve deployed here, but for the whole valid parameter space, so the harness constructs six curves including the awkward ones (a kink one wei above zero, one wei below full, every rate at its ceiling):

The property count is declared, not counted: the harness states it as a literal, a static gate counts the predicates, and each fuzzer is checked against what it actually registered at runtime — so a property that quietly stops being picked up fails the build instead of reporting a smaller green run. The harness’s own detectors are tested too, by installing a model built to break each property and requiring the matching predicate to notice. Full detail, including the rounding decisions and the live read-back, in the repository.