Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

loans source realm

Realm loans is an unsecured term loan with a fixed installment schedule and a flat finance charge, holding real ugnot...

Overview

Realm loans is an unsecured term loan with a fixed installment schedule and a flat finance charge, holding real ugnot. A LENDER opens a loan to a named BORROWER by attaching the principal, which the realm disburses to the borrower in the same transaction; the borrower REPAYS over a fixed number of installments; each repayment credits the lender's pull-claimable balance, the protocol fee splitting off at the ledger. A loan whose installments go unpaid past a grace window is permissionlessly DEFAULT-able — a recorded state, not a seizure, because v1 is unsecured.

It is the one financial primitive this portfolio never had: CREDIT. The accounting realms RECORD obligations (r/invoices, r/receivables — p/aging's own doc lists "invoices, loans, dues") and the disbursement realms pay a KNOWN TOTAL out on a schedule (r/vesting, r/payroll, r/budgets). A loan is the asymmetric opposite: principal OUT once, a LARGER total back over time, plus the finance charge and the default state a disbursement realm has no use for. See onyx/r/loans/DISCOVERY.md.

Custody — the conservation invariant is the product

This is the first custodial realm the factory has selected since the publishers (r/latefees, r/cashflow), so the monetary invariant governs it exactly as it does r/subscriptions and r/meters:

Example
1Held == Σ lender-claimable + fee pot   (== feeledger.Liabilities())

The principal is NEVER held across a transaction: Open receives it and pays it out to the borrower in the same call, so the only coins this realm ever holds are repayments awaiting the lender's Claim. A stuck or abandoned loan therefore strands no principal — it was disbursed — and the only value at risk is the lender's expected return, which is the real nature of unsecured credit and is disclosed, not engineered away.

The finance charge is FLAT in v1, and that is a scope decision

The total repayable is `principal + floor(principal × rateBps / 10000)` — a flat charge over the whole term, NOT compounding and NOT accruing per block. Per-installment is `ceil(total / installments)` with the rounding remainder on the FINAL installment, so the installments sum to exactly the total (the cross-foot). Compounding interest and a tiered-by-duration rate (which p/tiers could price) are a v2: pricing them in v1 would add an accrual surface whose bugs are the ones lending audits most often find.

Default is a state, not a seizure — there is no collateral in v1

A borrower past the grace window who has not repaid in full is Default-able by anyone (like the sibling realms' valves). It freezes the loan and records the shortfall; no coins move, because there is nothing to seize. Secured lending is a v2.

REALM-CALLER CAVEAT, inherited from the siblings: coinio's receipt guard admits only EOA payers, so the LENDER (who funds Open) and any REPAYER (who funds Repay) are EOAs. The BORROWER is a parameter — coinio.Payout delivers the principal to any valid address, including a realm — but a realm borrower could never Repay (Repay is payable, EOA-only), so naming one is the lender's own footgun (an un-repayable gift), not a realm or third-party hazard. assertNoSend reads the ORIGIN envelope, so every non-payable function refuses any transaction that attached coins anywhere.

Constants 4

const MinPrincipal, MaxPrincipal, MaxRateBps, MinInstallments, MaxInstallments, MinPeriodBlocks, MaxPeriodBlocks, MaxLoansPerLender, RenderLimit

 1const (
 2	// MinPrincipal keeps a loan from being dust; MaxPrincipal keeps
 3	// principal × rateBps and the total far from int64 overflow (the
 4	// checked arithmetic still guards it). The lender must ATTACH the
 5	// principal, so the real ceiling is their balance.
 6	MinPrincipal = int64(1_000)
 7	MaxPrincipal = int64(1_000_000_000_000) // 1,000,000 GNOT
 8
 9	// MaxRateBps caps the flat finance charge at 100% of principal over the
10	// whole term. A 0 rate is a legitimate interest-free loan.
11	MaxRateBps = int64(10_000)
12
13	// Installment-count and period bounds. The period bounds match the
14	// sibling realms: the floor keeps repayment off a per-block treadmill,
15	// the ceiling keeps schedule arithmetic far from overflow.
16	MinInstallments = int64(1)
17	MaxInstallments = int64(60)
18	MinPeriodBlocks = int64(10)
19	MaxPeriodBlocks = int64(7_500_000)
20
21	// MaxLoansPerLender bounds one lender's stored loans; terminal loans do
22	// NOT free the slot, because a Repaid/Defaulted loan is a permanent
23	// record a borrower and auditor may need to read.
24	MaxLoansPerLender = 50
25
26	// RenderLimit bounds every rendered list — an unbounded Render was
27	// YELLOW in three prior audits.
28	RenderLimit = 20
29)
source

Input bounds.

const Denom

1const Denom = "ugnot"
source

Denom is the only asset this realm accepts.

const MaxFeeBps

1const MaxFeeBps = int64(1000)
source

MaxFeeBps is the hard protocol-fee cap: 1000 bps = 10%.

Functions 27

func AmountDueNow

Action
1func AmountDueNow(loanID int64) int64
source

AmountDueNow is how far behind schedule the borrower is right now: ScheduledDue − repaid, floored at zero (a borrower who has prepaid is not behind).

func Claim

crossing Action
1func Claim(cur realm, amount int64)
source

Claim sends amount ugnot of the caller's claimable balance (repayments collected on their loans, net of the protocol fee) back to the caller.

func ClaimAll

crossing Action
1func ClaimAll(cur realm)
source

ClaimAll sends the caller's entire claimable balance back to the caller.

func Default

crossing Action
1func Default(cur realm, loanID int64)
source

Default marks an active loan defaulted once it is past its grace window — the final installment's due height plus one more period — and not repaid in full. Permissionless by design: no loan's terminal state may depend on either party acting. No coins move; the shortfall is recorded.

func DefaultableAt

Action
1func DefaultableAt(loanID int64) int64
source

DefaultableAt is the height at or after which an unpaid loan may be Defaulted: the final installment's due height plus one grace period.

func InstallmentAmount

Action
1func InstallmentAmount(loanID int64) int64
source

InstallmentAmount is the per-installment amount: ceil(total/installments), with the rounding remainder carried on the FINAL installment so the installments sum to exactly the total.

func IsDefaultable

Action
1func IsDefaultable(loanID int64) bool
source

IsDefaultable reports whether the loan may be Defaulted right now.

func Open

crossing Action
1func Open(cur realm, borrower address, rateBps, installments, periodBlocks int64) int64
source

Open funds a loan: the caller (the lender) attaches the principal, which is disbursed to borrower in this same transaction, and the loan is recorded with a flat finance charge of rateBps of the principal, repayable over `installments` installments of `periodBlocks` blocks each. The current protocol fee is snapshotted in. Returns the loan id.

func Repay

crossing Action
1func Repay(cur realm, loanID int64)
source

Repay pays toward the caller's own loan. The caller must be the loan's borrower; the attached amount must be positive and must not exceed the outstanding balance. The payment credits the lender's claimable balance (the protocol fee splitting off at the ledger); when the cumulative repaid equals the total, the loan is Repaid. Repaying ahead of schedule is allowed.

func ScheduledDue

Action
1func ScheduledDue(loanID int64) int64
source

ScheduledDue is the cumulative amount that should have been repaid by the current height: the sum of every installment whose due height has passed, capped at the total. Installment k (1-based) is due at start + k·period.

func SweepDenom

crossing Action
1func SweepDenom(cur realm, denom string)
source

SweepDenom recovers out-of-band coins to the fee recipient. For the ledger denom the reserve is Liabilities() — lender balances and the fee pot are structurally unreachable.

Dependencies

Source Files 2