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.

latefees source realm

Realm latefees publishes a graduated late-fee penalty on an overdue invoice held in the live [r/invoices](/r/invoices...

Overview

Realm latefees publishes a graduated late-fee penalty on an overdue invoice held in the live r/invoices. A creditor (an invoice issuer) declares a late-fee SCHEDULE once — a p/tiers schedule over how many blocks an invoice is overdue — and the realm prices the penalty as a function of that overdue duration, escalating by tier. The penalty can be read live (PenaltyNow) or frozen into a sequence-numbered ASSESSMENT the creditor can point a payer to.

It is the fourth consumer of p/tiers and the one that exercises its "progressive fee" reading over TIME rather than quantity: r/meters prices usage, r/payslips prices withholding, and this prices lateness. It is the second consumer of r/invoices after r/receivables, and reads the exact integration surface that realm's header advertises — invoices.InvoiceInfo, invoices.IsOverdue, invoices.HasInvoice — all non-crossing views, no struct slice crossing a realm boundary.

It is a PUBLISHER, not a collector

r/invoices is live and immutable, so this realm CANNOT add a charge to an invoice there, and it holds no coins of its own — no banker, no deposit, no payout, no withdrawal path. A published penalty is a verifiable CLAIM backed by the invoice's own facts and the creditor's declared schedule, exactly as r/receivables publishes a loss provision and r/cashflow a statement. It compels nothing; a debtor who ignores a late fee is in the same position as one who ignores the invoice. A custodial variant that collects the fee is a separate, larger product and is deliberately out of scope.

The pricing axis, and the one it is not

The base handed to p/tiers is the OVERDUE DURATION in blocks (`now - dueHeight`), and each tier's rate is a ugnot accrual per RateScale blocks. So the penalty ESCALATES WITH TIME: the longer an invoice is overdue, the higher the marginal accrual. p/tiers' rate cap makes `penalty <= overdueBlocks` an arithmetic fact — the fee can never exceed one ugnot per overdue block, a natural ceiling.

It is NOT a percentage of the outstanding amount. p/tiers prices one amount against breakpoints — a single dimension — and a fee that is both time-escalating AND balance-scaled is two dimensions it cannot express in one call. The creditor scales the ugnot accrual to their debt magnitudes through the schedule; the assessment records the outstanding beside the penalty so a reader can compute an effective rate. Composing a balance- scaled fee as a single Charge call would be a plausible, wrong number.

The trust boundary, inherited twice over

A penalty is a self-report of a self-report of a self-report: the issuer set the invoice amount in r/invoices, the due height there, AND the late-fee schedule here. This realm computes faithfully from those; it does not validate that any of them is fair. A creditor may only assess their OWN invoices — Assess derives the issuer from `cur.Previous().Address()` and reads invoices.InvoiceInfo under that key, which returns only invoices that address issued.

Constants 4

const Denom

1const Denom = "ugnot"
source

Denom is the asset the invoices this realm prices are denominated in, and the unit a penalty is expressed in. This realm never holds it.

const InvoicesPath

1const InvoicesPath = invoices.RealmPath
source

InvoicesPath pins the realm this one reads, by value, so a reader of a published assessment can see which invoices it priced.

const MaxAssessmentsPerIssuer

1const MaxAssessmentsPerIssuer = 256
source

MaxAssessmentsPerIssuer bounds one creditor's stored assessment records, so one address cannot grow this realm's state without bound. It counts STORED records, the invoices-realm discipline.

const RenderLimit

1const RenderLimit = 20
source

RenderLimit bounds every rendered list — an unbounded Render was YELLOW in three prior audits.

Functions 13

func Assess

crossing Action
1func Assess(cur realm, invoiceID int64) int64
source

Assess freezes a late-fee penalty on one of the caller's own overdue invoices and returns its sequence number. The caller must be the invoice's issuer (the creditor), must have declared a schedule, and the invoice must be overdue right now. The invoice's facts and the current schedule are snapshotted, so the assessment is a stable claim even as the invoice keeps accruing or is later paid.

func AssessmentSchedule

Action
1func AssessmentSchedule(seq int64) (edges, rates []int64)
source

AssessmentSchedule returns the schedule snapshot an assessment was priced under — the edges and rates frozen with it, which may differ from the issuer's current schedule.

func AssessmentsOf

Action
1func AssessmentsOf(issuer address) int64
source

AssessmentsOf is the number of assessments an issuer has frozen.

func HasAssessment

Action
1func HasAssessment(seq int64) bool
source

HasAssessment reports whether a sequence number names a frozen assessment.

func HasSchedule

Action
1func HasSchedule(issuer address) bool
source

HasSchedule reports whether an issuer has declared a late-fee schedule.

func PenaltyNow

Action
1func PenaltyNow(issuer address, invoiceID int64) int64
source

PenaltyNow is the penalty an issuer's invoice has accrued as of the current height, under the issuer's CURRENT schedule. It is 0 when the invoice is not overdue — including once it is paid or voided, because r/invoices does not expose when a payment landed, so accrual is only computable while the invoice is still open and late. A frozen Assess is how a claim survives the invoice being paid. Panics only if the issuer has no schedule or the invoice does not exist.

func QuotePenalty

Action
1func QuotePenalty(issuer address, overdueBlocks int64) int64
source

QuotePenalty prices a hypothetical overdue duration against an issuer's current schedule, without reading any invoice — the preview a creditor uses to tune a schedule. Panics if the issuer has no schedule or overdueBlocks is negative.

func Render

1func Render(path string) string
source

Render shows the catalog at "", an assessment at "seq/<n>", and an issuer's schedule at "issuer/<addr>". Every user-supplied value rendered between table pipes is escaped with sanitize.TableCell; addresses carry no markdown metacharacter but are passed through InlineText for the same reason the sibling realms do.

func ScheduleOf

Action
1func ScheduleOf(issuer address) (edges, rates []int64)
source

ScheduleOf returns an issuer's current schedule as its edge and rate slices, or two empty slices if none is declared.

func SetSchedule

crossing Action
1func SetSchedule(cur realm, edges, rates string) int
source

SetSchedule declares or replaces the caller's late-fee schedule: a graduated accrual over OVERDUE BLOCKS, built from comma-separated int64 lists where len(rates) == len(edges)+1 and each rate is a ugnot accrual per RateScale blocks (0..10000). Edges are block counts — e.g. "216000,648000" is roughly ten and thirty days at ~4s blocks. A single rate with no edges is a flat accrual. Replacing a schedule does not touch already-frozen assessments, which snapshot the schedule that priced them.

Dependencies

Source Files 2