Model
Three roles share one pool on Robinhood Chain.
- Lenders deposit USDG and hold pool shares. They take 50% of every fee.
- Backers (the treasury, sponsors, seat vaults, stock vaults, or an owner staking $NOVASI) lock value behind one agent's line. They take 25% of that agent's fees and cover its defaults.
- Agents are ERC-8004 identities. An agent borrows inside its line, from its own wallet, and builds a record by repaying.
A line can never exceed what backs it. The pool lends lenders' USDG, but a lender's deposit is never the thing that pays for a default.
Loan lifecycle
- Consent. The agent's owner chooses its sponsor on the pool,
setSponsor(agentId, sponsor). Only the owner can, and only while the agent owes nothing. - Line opened. The backer's stake is locked for the full line.
LineOpened(agentId, backer, amount) - Borrow. The agent draws up to its free line for 1 to 30 days. Amount, due time and fee are fixed now.
Borrowed(agentId, loanId, amount, due, fee) - Repay. Principal plus fee, any time before it is due. The fee splits 50 / 25 / 25.
Repaid(agentId, loanId, amount, fee) - Late. Repaying after the due time still settles the loan, but it counts for less in the score.
What a default does
Seven days after the due time, anyone can mark an unpaid loan as defaulted. The backer's locked stake repays the pool the principal plus the fee, in full, in the same transaction. Lenders are made whole; the backer takes the loss; the agent's record shows the default permanently. For an owner's $NOVASI stake, three quarters of the slashed amount burns and the rest returns to the owner. For a stock line, the vault takes tokens worth what was owed plus 20% at the feed price and returns the rest.
Nova Score
A number from 0 to 1000, recomputed from events, never stored by hand.
- The base is dollar-days repaid on time: amount × days held, for loans held 7 days or more.
- Debt someone else put at risk counts in full. Debt backed only by the agent owner's own collateral counts at a quarter.
- A late repayment counts at half. A default subtracts heavily and caps the score at 600 for good.
- The curve is logarithmic, so the first month matters and farming size matters less.
// sketch; the reference implementation ships with the SDK
score = min(1000, 140 * ln(1 + weighted_dollar_days / 100))
weighted_dollar_days = Σ amount × days × backing_weight × timing_weight
backing_weight = 1.0 (someone else's stake) | 0.25 (owner's own)
timing_weight = 1.0 (on time) | 0.5 (late) ; loans under 7 days = 0.05
Invariants
- For every agent: open principal ≤ line ≤ locked backing.
- A default is always repaid from backing in the same call; pool assets never fall because of one.
- Withdrawals are paid from idle USDG and never wait for agents to repay.
- Only the agent's owner, or a wallet the owner named as its operator, can borrow, and the USDG goes to that caller.
- New stake cannot leave for a day, so nobody can stake just around a default or a repayment.
- A sponsor may name a view-only guard the pool asks before each loan on its lines; it can refuse a loan, never block a repayment.
- Parameters move inside hard bounds written into the contract.
Parameters
$NOVASI and the treasury
$NOVASI is the NovaSI token on Robinhood Chain. It has two jobs in the protocol: an agent's owner can lock it as collateral behind their own agent, and part of what the protocol earns buys it back. Creator fees from $NOVASI fund the treasury, and the treasury funds the $5 first lines. The treasury is topped up in USDG.
posts here once $NOVASI launchesInterface
Read-only checks need no key: any app can ask whether to trust an agent before paying it.
// NovaPool: reads
getAgent(agentId) → sponsor, line, principalOut, loansRepaid, qualifiedOnTime, weightedDollarDays, defaults…
loansOf(agentId) · getLoan(loanId) · stats()
canBorrow(agentId, amount, term) → (ok, fee)
quoteFee(amount, term)
// agents (the ERC-8004 owner)
setSponsor(agentId, sponsor) · setOperator(agentId, operator)
borrow(agentId, amount, term, maxFee)
repay(loanId, maxDue) // anyone may repay
markDefault(loanId) // anyone, 7 days after due
// lenders and sponsors
deposit(assets, minShares) · withdraw(shares, to, minAssets)
stake(assets) · unstake(shares, to) · setLine(agentId, line) · claimSponsorFees(to)
// sponsor contracts
NovaTreasury.open(agentId) · openLane(agentId, deadline, sig) · releaseBond(agentId) · close(agentId)
NovaSeatVault.open(agentId, steps, maxCost) · grow(…) · close(agentId) · settle(agentId)
NovaStockVault.open(agentId, token, amount) · close(agentId) · settle(agentId)
// check an agent from an agent (the CLI ships later)
$ npx novasi check <agentId>
# example of the shape it prints, not a real agent:
#<id> · Nova Score 412 (Flare) · 38 repaid · 0 defaults · line $50 backed by sponsor
Addresses
Robinhood Chain, chain id 4663. Every contract will be verified on the explorer at deploy.
Security
Found something? Write to before you write anywhere else. A bounty is coming.