How StockLend works
Borrow a tokenized stock against USDG, sell it into a weekend premium, and buy it back when the feed comes home. Why the debt is valued at two prices instead of one, and every way both sides can still lose money.
A short, priced at what buying it back costs
Chainlink's equity feeds are 24/5. From Friday's close to Sunday evening they hold the last value while the token keeps trading, so the pool can sit at a premium for two days with nothing to arbitrage it. StockLend turns that into a position: post USDG, borrow the stock token, sell it, buy it back when the feed reopens.
- It is our own contract, not Morpho. Debt is valued at max(oracle, pool TWAP), not at the oracle.
- It is public and permissionless. There is no keeper: liquidation and buy-in are open to anyone and pay a bonus.
- The only lever the owner holds is a borrow cap. Every other parameter is bounded by the contract itself.
:::note Who is on each side
A lender deposits the stock token and earns the borrowing fee in USDG. A borrower posts USDG and owes the stock. Both are underwriting the same thing from opposite ends: how far the pool can run away from the feed before the feed comes back.
:::
Why one price is not enough
A lending market that values debt at the oracle prices the loan at a number that has stopped moving. Over a weekend that hands the borrower a free call option: once the token trades above the oracle divided by the loan-to-value, not repaying is strictly better than repaying, and the liquidation settles the lender in USDG at the frozen price. The lender never gets the shares back.
This is not hypothetical. It is what the last weekend we have data for looked like.
Over that weekend $1.93M of the $2.89M traded went through above a 60% premium. Chainlink held $127.52 the entire time and the token was back at $129.68 by Monday 02:00 UTC.
A Morpho-style market would have been drained by design, not by a bug — and it is the reason StockLend is a contract we wrote instead of a market we created on somebody else's.
Two prices, and a clamp
The oracle is what Monday reverts to and what fees are charged against. The pool's TWAP is what buying the stock back actually costs. The debt is marked at the higher of the two, so the position tracks the squeeze while the squeeze is on.
Taking the pool at face value would be a different, worse mistake. A concentrated position has an empty tail: buying through the narrow range leaves the tick anywhere for almost nothing, and in testing a 30-minute TWAP read 53x within five minutes of that. So the mark is clamped.
mark = min( max(oracle, pool TWAP), oracle × (1 + band) )
The clamp alone would not be enough
If the initial margin sat below maintenance × (1 + band), someone could push the pool to the clamp and liquidate healthy loans at the ceiling. The contract refuses to be configured that way: it enforces IM ≥ MM × (1 + band) at both regimes, which is why the live margins are the odd numbers you see in the app rather than something rounder.
The band is frozen into each loan
A review found the gap this closes: if the band were read at the current regime, a loan opened in the open regime at the tighter band would fall under the closed band every evening the feed stops updating, and could be liquidated on a push it was never margined for. The band, the maintenance ratio and the liquidation bonus are all copied into the loan when it opens, and the owner changing a parameter cannot reach an existing one.
What a borrower pays
The fee is charged the moment the loan opens, in USDG, and it is a share of the premium rather than an interest rate: α × premium × shares × the oracle price. The reason is the one thing an adaptive rate cannot do — a two-hour weekend squeeze is over long before a utilisation curve has finished reacting to it.
| What | Why it is that |
|---|---|
| Fee at the open (α) | A share of the premium, charged once, up front. The premium is taken as max(TWAP, spot) against the oracle, and the borrower passes a maxFeeOpen so the quote cannot move under them. |
| Initial margin | One value for the open market, a higher one for the closed market. It is charged at the regime the loan opens in, and margined against the mark — not against the oracle, which is the whole point. |
| Maturity | The on-chain trading calendar binds first and the configured term is a cap. A loan opened while the market is open matures at that day's close, so nobody borrows on Thursday evening and holds a zero-premium loan across the weekend. A loan opened while closed matures a fixed period after the next open, plus a grace window. |
| Buy-in ceiling | Past maturity anyone may buy the shares back with the borrower's collateral, but only at the settlement price plus an allowance. It starts tight and grows a point an hour, so a block that pumps the pool makes the buy-in revert rather than drain the borrower — and a real premium still clears within a day. |
:::caution The borrower's tail
If maturity lands in a window where the feed is still frozen, the settlement price is the oracle and the ceiling grows from there. In the worst case a borrower is bought in at the oracle plus the full slippage cap. That is the price of a ceiling that cannot be gamed by whoever is guarding the tail.
:::
What a lender earns, and what they are underwriting
Deposit the stock, take shares, and the fees accrue in USDG per share the way every staking contract does it. Principal only moves on a write-off. There is no interest-rate curve to watch: the income is the α cut of each borrow's premium plus the time fee, and both are paid by borrowers who chose to be there.
The protection stops at the band
Below the clamp the pool price is what protects a lender — the debt grows with the squeeze. Above it, it does not. Past the band the extra premium is on the screen but not in the debt, and what stands behind the lender is the collateral and the fact that the feed reopens. If a name genuinely re-rates by more than the band and does not come back, that collateral is not enough.
So the band is not a safety setting, it is a product decision: it is the largest premium this market promises to carry for lenders, and it is chosen per market from that name's own history. On the MSTR weekend above, covering the full 2.7x move would have taken an initial margin of 310%.
How a loan ends
Four exits, and the protocol needs none of them to be us. Repay is the borrower's. Liquidate is open to anyone once health falls under maintenance and pays a bonus. Buy-in is open to anyone once the loan matures and pays a bonus. Write-off is the last one, and it is the only path where a lender's principal moves.
Two details that came out of review rather than design. Collateral refunds are pull-based, so a USDG account that
gets frozen cannot brick somebody else's close. And while a token's oraclePaused() is set for a corporate
action there is no health liquidation and no write-off at all — the feed is frozen at the last good value while
the multiplier changes, and acting on it would be acting on a number that is known to be wrong.
What is proved, and what is only measured
A pushed pool cannot liquidate a collateralised loan
This one is arithmetic, not judgement. The mark cannot exceed the oracle × (1 + band); the initial margin is at or above maintenance × (1 + band); the band is fixed at open. Compose them and the health factor of a fresh loan cannot be driven under maintenance by pool price alone — only a real move in the feed can do it.
Three attack scenarios were run against the deployed contract: a closed-regime loan at the closed initial margin, an open-regime loan carried across the nightly gap in the feed, and a healthy loan at maturity with the pool genuinely up 22%. All three were rejected, and the attacker's net was negative every time — the cost of buying through the narrow range and back.
The buy-in cannot be held hostage forever
Someone can push the pool just before each buy-in and make it revert. The ceiling grows a point an hour to its cap, so the delay that costs the griefer a range round trip each time is bounded at roughly a day — and the time fee over that period accrues to the lenders, not to the griefer.
Not proved: that lending it out beats holding it
We have one weekend of a real squeeze, on one name, and it is the event the parameters were calibrated against. Calibrating on your only sample is not evidence that the calibration generalises. The honest statement is that the mechanism survives that event by construction; whether the fees pay for the tail across many weekends is a measurement nobody has yet.
What can go wrong
Above the band, the pool stops protecting lenders
Stated once more because it is the one that costs money: past the band the debt stops following the price, and the lender is relying on the posted collateral and on the name coming back when the feed reopens.
The issuer can pause the token
Stock tokens are beacon proxies with a global pause. If transfers stop, everything in the market stops with them — nobody can repay, liquidate or buy in until it lifts. There is no blacklist, but the pause is enough.
One market, one cap, one recorded event
The first market's cap is the size at which we are willing to be wrong, not a view about demand. The legal characterisation of borrowing a stock token in order to sell it has not been assessed.
:::info One sentence
The debt is priced at what buying the stock back would actually cost, capped at a premium the market has promised to carry — and beyond that cap, collateral and the feed reopening are all there is.
:::
Reference
| Role | What it decides |
|---|---|
StockLend | one market, one stock: deposits, loans, liquidation, buy-in, write-off |
TwoPriceOracle | the feed, the pool TWAP, the clamped mark, the regime |
TradingCalendar | 24/5 sessions, DST and NYSE holidays, computed from the timestamp — nobody feeds it |
| Pool | the USDG pair the TWAP is read from and the buy-in executes against |
| Owner | a Safe: parameters within the contract's own bounds, and the cap. No keeper role exists. |
Addresses and the live value of every parameter above are on the market's own page in the app: hedgehood.app/lending. See also the three prices and the glossary.