The protocol
How the credit protocol works, in full.
§ 01
The credit pool model
pool = USDG lent by lenders, counted in shares
stake(b) = USDG backer b has locked
vouched(a) = part of one backer's stake standing behind agent a
free(b) = stake(b) - sum of vouched(a) for every agent b backs
line(a) = min( ceiling(record(a)), vouched(a) )
room(a) = line(a) - outstanding(a)
borrow(a, P, days): require 1 <= days <= 30 and P <= room(a) and P <= cash(pool)
outstanding(a) += P // USDG goes to the agent's own wallet
repay(loan): fee = P * 1% * held / 30 days // by the second, one day minimum
fee -> backer 25% | lenders 60% | treasury 15%
record(a) += loan // the ceiling grows from this, nothing else
vouch(b, a, x): require x <= free(b) and backer(a) in {none, b}- lender
- Holds pool shares for the USDG supplied and collects 60% of fees. A default could only reach lender principal if a stake were smaller than its loan, and the limit rule prevents exactly that.
- backer
- Locks at least $10.00 and vouches lines out of it. Takes 25% of the fees its agents pay. Pays first when one of them defaults. Stake that backs nothing can leave at any time.
- agent
- An owner wallet with a name and a purpose. Takes $1.00 to $500.00 per loan, one to thirty days, priced at 1% per 30 days, never above what its backer signed for. Keeps its own wallet; nothing is held for it.
- treasury
- Takes 15% of every fee. Backs first lines for bonded agents out of its own stake, and receives forfeited bonds.
§ 02
A loan from borrow to default
borrow(P, days)
past the due date, inside 3 days of grace; repaying still works but costs a rung
principal + accrued fee, any time before default
3 days past due, anyone marks it; the backer pays
markDefault(loan): require now > dueAt + 3 days // anyone can call it
owed = P + fee accrued to now
paid = min(owed, stake(backer)) // the backer pays first
pool += principal part of paid // lenders made whole up to the stake
loss = P - principal part of paid // zero whenever the vouch covered P
record(a).defaulted = true // score 0, no new line, ever
bond(a) -> treasury // if the line came from a bondRun one loan
ExampleDefaulted after 14 days plus 3 of grace. Owed: $50.283334.
- Backer's stake pays
- $50.00
- Lenders lose
- $0.00
- Fee recovered (lenders / treasury)
- $0.00 / $0.00
- Backer stake left
- $0.00
The stake covered everything. In Craf a line can never exceed what its backer vouched, so this is the normal case.
Computed in your browser by src/lib/credit/engine.ts, the same module the practice book runs on. 1 USDG = 1000000 units.
§ 03
Credit lines and the agent credit score
| Rung | Ceiling | 7-day loans repaid on time | Days on the books | Principal returned |
|---|---|---|---|---|
| 0 | $5.00 | 0 | 0 | $0.00 |
| 1 | $10.00 | 1 | 7 | $5.00 |
| 2 | $25.00 | 3 | 14 | $20.00 |
| 3 | $50.00 | 6 | 30 | $100.00 |
| 4 | $100.00 | 10 | 45 | $400.00 |
| 5 | $250.00 | 16 | 60 | $1,500.00 |
| 6 | $500.00 | 24 | 90 | $5,000.00 |
A loan counts as week-long when it is held at least 7 days and repaid by its due date. Each late repayment drops the agent one rung.
Money held and returned
USDG × days held on repaid loans, one point per 10 USDG-days
Loans held seven days or longer
20 points each
A backer's money behind it
one point per $5 vouched
Days on the books
two points a day
Repaid by the due date
five points each
Late repayments
and a default sets the score to zero for good
§ 04
Invariants: what must always hold
I1
Split adds up
backer + lenders + treasury = fee, for every fee; rounding dust goes to lenders.
I2
No lender loss inside the vouch
while the backer's stake covers principal, lenderLoss = 0.
I3
Line never exceeds the vouch
room(a) ≤ vouched(a) − outstanding(a), and a defaulted agent's room is 0.
I4
Fees only grow with time
fee(P, t2) ≥ fee(P, t1) when t2 ≥ t1; one-day minimum.
I5
Conservation on default
paid by backer = principal recovered + fee recovered; principal recovered + loss = P.
I6
Shares are fair
a deposit at the current share price mints shares worth what was paid.
Run them yourself: npm test in the repository.
§ 05
Protocol parameters
| Parameter | Value | Meaning |
|---|---|---|
| minLoan / maxLoan | $1.00 / $500.00 | size of one loan |
| term range | 1 d / 30 d | how long a loan can run |
| fee | 1% per 30 d | accrued by the second on time held, one day minimum |
| split | 25 / 60 / 15 | backer / lenders / treasury |
| grace | 3 d | after the due date, before anyone can mark a default |
| minStake | $10.00 | to count as a backer |
| bond | $5.00 | refundable, for a treasury-backed first line |
| firstLine | $5.00 | rung 0 ceiling |
| qualify | 7 d | a loan held this long and repaid on time counts toward the ladder |
§ 06
$CRAF and the treasury
The treasury earns 15% of every fee and receives forfeited bonds. It uses its own stake to back first lines for bonded agents, so a newcomer never has to find a stranger to vouch for a $5 line.
A proposal for after launch: holders could stake $CRAF as a seat behind an agent with a clean record, sharing the backer's 25% and losing part of the seat on a default. It needs a price oracle for the token and a deep enough market; it is not built and nothing on this site depends on it.
§ 07
Contract interface, as designed
| deposit(uint256 assets) → shares | lender |
| withdraw(uint256 assets) | lender |
| stake(uint256 assets) · unstake(uint256 assets) | backer |
| vouch(uint256 agentId, uint256 amount) · release(uint256 agentId) | backer |
| register(string name) → agentId | agent owner |
| postBond(uint256 agentId) | agent owner |
| borrow(uint256 agentId, uint256 amount, uint32 termDays, address to) | agent owner or its key |
| repay(uint256 loanId) | anyone |
| markDefault(uint256 loanId) | anyone, after grace |
| score(uint256 agentId) · lineOf(uint256 agentId) | view |
§ 08
What is live and what is practice
| USDG token facts (symbol, decimals, supply) | read from the token contract every few seconds | live |
| Your ETH and USDG balances | read from the chain for the connected wallet | live |
| Block, gas, ETH price | chain RPC and OKX spot | live |
| Stock token prices | Chainlink feeds on Robinhood Chain | live |
| Lend, back, register, bond, borrow, repay, default | wallet-signed actions on a shared practice book; balances reset after 30 days of inactivity | practice |
| Fee math, line ladder, waterfall, score | src/lib/credit/engine.ts, with unit tests | practice |
| Credit pool, backer vaults, agent registry | contract design written, not deployed | planned |
| $CRAF seats | proposal only | planned |
§ 09
Contract and token addresses
Explorer: https://robinhoodchain.blockscout.com