docs / reference
Contracts
Three contracts on chain 4663, none of them upgradeable. Sources are verified on Sourcify.
Addresses
Nenrin: writes
| function | who | what |
| stake(amount) | backer | Pulls USDG into the backer's stake. |
| unstake(amount) | backer | Withdraws stake not committed to lines or offers. Never paused. |
| bindAgent(agentId) | agent wallet | Declares the wallet is that agent's. Once, permanent. |
| offerLine(agentId, amount, rateBps, ttl) | backer | Offers a line and reserves the amount. Bound wallets must be elders. |
| cancelOffer(agentId) | backer | Releases a pending offer. |
| acceptLine(agentId, backer) | agent | Takes an offer. Switching backer needs nothing borrowed. |
| releaseLine(agentId) | agent or backer | Ends a line with nothing borrowed. |
| reduceLine(agentId, newLine) | backer | Shrinks a line, never below what is out. |
| borrow(agentId, amount, term) | agent | Borrows within the line; USDG goes to the identity's owner. |
| repay(loanId) | anyone | Pays principal and fee; records rings. |
| markDefault(loanId) | anyone | After due plus 3 days: backer loses principal, agent is scarred. |
| claimFees() | backer | Withdraws earned fees. |
Nenrin: views
| function | returns |
| getAgent(agentId) | backer, rateBps, openLoans, scarred, firstLoanAt, line, out, lastRingAt, scarredAt, rings, incomeRings, thinRings, loansRepaid, volumeRepaid, dollarDays |
| getBacker(address) | stake, lent, committed, feesEarned, agentId, scorches, bound |
| getLoan(loanId) | backer, term, status, principal, fee, start, due, agentId |
| getOffer(agentId, backer) | amount, rateBps, expiresAt |
| standing(agentId) | 0 to 1000 |
| isElder(agentId) | bool |
| available(agentId) | line minus out |
| free(address) | stake minus committed |
| loansOf / openLoansOf(agentId) | loan ids |
| feeFor(principal, rateBps, term) | the fee a loan would pay |
Events
Staked(backer, amount) Unstaked(backer, amount)
AgentBound(backer, agentId)
LineOffered(agentId, backer, amount, rateBps, expiresAt)
OfferCancelled(agentId, backer, amount)
LineAccepted(agentId, backer, line, rateBps)
LineReleased(agentId, backer, line)
LineReduced(agentId, backer, newLine)
Borrowed(loanId, agentId, backer, amount, fee, due)
Repaid(loanId, agentId, principal, fee, payer, ring, incomeRing, late)
Defaulted(loanId, agentId, backer, principal)
Scarred(agentId, backer) FeesClaimed(backer, amount)
Taps and Tap
| function | what |
| Taps.tapOf(agentId) | The CREATE2 address of the agent's tap, deployed or not. |
| Taps.open(agentId) | Deploys the tap. Anyone can call it. |
| Tap.flow() | Repays ripe loans oldest first, keeps what open loans owe, forwards the rest to the agent's wallet. |
SeedBank
Deployed after the project token, and not deployed yet. A holder stakes a fixed amount of the token on an agent with no backer and no scar; the bank offers it a 5 USDG line at 1% per 30 days. At three new rings the holder takes the tokens back with half of the fees the bank earned from that agent; on a default the tokens go to the burn address. New seed lines are capped per rolling week.
Security
- 193 unit tests, an invariant suite of 256 runs at depth 64, and fork tests against the real USDG and identity registry.
- Backer capital is segregated: nothing but a default on a loan it backed can reduce a backer's stake.
- Repayments, withdrawals and defaults cannot be paused. Incoming transfers check the balance actually received.
- Known properties: rings can be farmed by a backer lending to its own agent from another address; income rings count any payment into the tap. Standing weighs both, and every transfer is public.
- No external audit yet.