Pular para o conteúdo

Lending

Este conteúdo não está disponível em sua língua ainda.

This page is the precise version of How lending works.

The next election id equals utime_until of the current validator set (config 34). Timings come from config 15.

Moment Time
Requests accepted until since − endBefore − window
Decision window [since − endBefore − window, since − endBefore − 300) lends; later it only refunds
Recovery allowed config 34 shows a newer set and now ≥ newSet.since + heldFor + 600

window = min(2048, (startBefore − endBefore) / 2), 2,048 seconds on mainnet. The Elector unfreezes a stake stake_held seconds after it actually replaces the validator set, so recovery waits for that replacement plus 10 minutes for the Elector’s tick.

  • The stake signature must be exactly 512 bits with no references, so nobody can bloat the masterchain message.
  • minPayment ≥ minRateBps × amount.
  • minAmount is the smallest principal the validator accepts; a smaller partial loan is refunded instead.
  • Collateral of undecided requests is tracked as held and never counts as liquidity.

Requests live in two maps: one keyed by borrower, one keyed by

efficiency << 192 | hash >> 65 << 1 | isMasterchain efficiency = minPayment / amount, 32.32 fixed point

The worst request is the first key and the decision walks from the last. Nothing is sorted on chain. When the round is full, a request better than the worst evicts it and its collateral is returned.

The budget is the smaller of:

  • lendable liquidity: balance minus claims, held collateral, reserve and a bufferBps buffer;
  • the cohort cap: cohortShareBps of total coins.

Requests are funded from the most efficient down; the last may be partly funded with a pro-rata minimum payment. Principal plus collateral never exceeds max_stake from config 17. If the decision comes after the elections close, everyone is refunded.

A stake earns while its round is active and then stays frozen for heldFor, so the same Gram can work only every other round. The cohort cap keeps each round at about half of the pool. Gram of round N returns before the decision of round N+2.

net = returned − settleCost
reward = max(net − principal − collateral, 0)
earned = reward × principal / (principal + collateral)
poolTake = min(max(minPayment, earned × poolShareBps), net − principal)
payout = net − principal − poolTake
  • poolShareBps is fixed in the loan when it is issued; later governance changes do not reprice it.
  • A rejected stake pays minPayment from collateral.
  • A fine beyond collateral makes poolTake negative; the loss rules apply.
  • The payout and keeper bounty are sent with IGNORE_ERRORS, so settlement cannot revert after the loan has paid out.
  • The Loan stays deployed. Anything the Elector credits later can be recovered again and is booked as pool profit.
  • insuranceShareBps of every positive pool take goes to the fund, capped at 50% and never above poolShareBps. Anyone can add to it with FundInsurance.
  • A loss on a loan is covered from the fund first.
  • The fund is excluded from liquidity.

Deciding rounds and recovering stakes are public calls paid from the keeper fund.

Action Who Paid
DecideRound anyone in the decision window, or any time for a stale round decideBounty
RecoverRound anyone after unfreeze per settled loan: recoverBounty plus the gas sent for it
  • profitShareBps of every positive pool take funds the keepers, capped at 20%.
  • Bounties never exceed the fund. The keeper who triggered RecoverRound is paid for every loan settled after it, even if someone else recovers a loan directly.
  • get_due_actions returns what is due and the exact value to attach. The protocol repository ships a keeper bot that acts on it, closes and finalizes prize draws with drand beacons, and waits ten minutes before retrying an action.

The bid engine and the tests use a port of the Elector’s try_elect. The protocol’s tests compile the real Elector from source, run elections on random participant sets and check that elected stakes, surplus credits and totals match exactly. Lending is also tested end to end against the real Elector: a rewarded round, a rejected stake, a stake that loses the cut, one capped by max_factor, and a real fine through a complaint and a validator vote.