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.

payroll state

Back to all declarations

RealmPath

untyped string

RealmPath is this realm's own path, used to build Render links.

Value

"/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/payroll"

Denom

untyped string

Denom is the only asset this realm holds.

Value

"ugnot"

MaxFeeBps

int64

MaxFeeBps is the hard ceiling on any accrual fee this realm could ever charge, enforced by the feeledger the realm is constructed with — a feeBps above it is refused by the primitive's own validation, not by a check in this file. 500 bps = 5%.

Value

500

AccrueFeeBps

int64

AccrueFeeBps is the fee charged on each accrual, on the gross amount, floor-rounded in the EMPLOYEE's favour: 100 bps = 1%. It matches the most conservative live fee in this portfolio (fee\_split, crowdfund, budgets). It is a compile-time constant and there is no setter, so a position's economics cannot be changed under the employee after the position is opened.

Value

100

FeeCollector

.uverse.address

FeeCollector receives withdrawn fees and swept surplus. Compile-time constant: there is no setter and no transfer path. It is the deploying namespace's address — stated plainly: the operator of this realm. NOTE FOR ANY RE-NAMESPACED PORT: this is the address-as-data hazard that a namespace substitution rewrites silently while every byte-comparison still reports the tree faithful, because the rewrite IS the intended transformation. Re-state it deliberately per chain; never let it be derived.

Value

<gnolang.StringValue>

MinFunding

int64

MinFunding keeps dust pools out: 1 GNOT per Fund call.

Value

1000000

MinPerPeriod

int64

MinPerPeriod is the smallest salary a position may carry. Below the fee denominator a 1% fee floors to zero, so a per-period amount of a few ugnot would be a fee-free position by accident rather than by design; 1000 ugnot keeps the fee arithmetic meaningful.

Value

1000

MinPeriodBlocks

int64

MinPeriodBlocks is the shortest period a position may use. A period of a handful of blocks is a rate rather than a salary, and it makes the arrears rule meaningless. Unlike budgets, a period of 0 is NOT accepted here: there is no "one lifetime window" reading of a salary, and dividing by it would panic.

Value

100

MaxRoster

untyped bigint

MaxRoster caps simultaneously-open positions per employer. Hire is permissionless to anyone with a funded pool, so this is an AVAILABILITY BOUND and it is documented rather than hidden: an employer can exhaust their OWN roster and no one else's, because the roster is per-employer. The cost of filling one is gas plus the storage deposit on every position record, held until Release.

Value

(64 <untyped> bigint)

OpenEnded

int64

OpenEnded is the EndHeight value meaning "no end": the position accrues until it is terminated.

Value

0

position

type

Value

payroll.position

self

.uverse.address

Value

<gnolang.StringValue>

employers

*v0.Tree

// address string -> \*employer

Open
OID
0d8092…b90a:5
employers details

Inspect pointer

positions

*v0.Tree

// "employer|employee" -> \*position

Open
OID
0d8092…b90a:8
positions details

Inspect pointer

employer

type

Value

payroll.employer

rejectStraySend

func()

rejectStraySend aborts when a direct EOA MsgCall attaches coins to a non-payable entrypoint. This realm holds funds, so such a send would become sweepable surplus, silently converting a user's coins into operator funds. THE PREDICATE IS NARROWER THAN THE FIRST SENTENCE OF THIS COMMENT USED TO BE, and the narrowing is correct rather than a gap. OriginSend() reports the coins attached to the ORIGINATING TRANSACTION, not coins this realm received in this call — there is no per-call msg.value in Gno. MsgCall is the one caller shape where the two coincide: the envelope is delivered to the realm being called. Under MsgRun the envelope lands in the caller's own ephemeral /e/ realm, and under a realm caller it lands at the first realm in the chain; in both, coins that genuinely reach payroll do so through an explicit SendCoins that OriginSend() does not describe. So widening this guard to IsUser(), or dropping the conjunct entirely, would refuse calls that sent payroll nothing while still not seeing the sends it was widened to catch. The stdlib guidance is explicit that OriginSend pairs with IsUserCall. What remains uncovered is therefore not a hole in this guard: coins can always arrive at an address by a bare MsgSend with no call at all, which no entrypoint check can intercept. That is exactly what Surplus() and SweepSurplus exist to name and reclaim.

Open
OID
0d8092…b90a:17
rejectStraySend details

Inspect func

Fund

func() int64

Fund adds the attached coins to the caller's own pool. Direct EOA calls with -send only (the receipt-guaranteed shape); exactly one positive ugnot coin, at least MinFunding. Anyone may fund; funding is what makes an address an employer.

Open
OID
0d8092…b90a:18
Fund details

Inspect func

WithdrawPool

func(amount int64) int64

WithdrawPool returns unallocated pool coins to the employer. There is no lock and no notice period, and that is a DOCUMENTED asymmetry rather than an oversight: see the package doc on solvency. An employer may withdraw a pool while positions are open, which leaves those positions accruing against an empty pool — due but unsettleable until the pool is refunded. What an employer can never do is reduce a balance already accrued to an employee's ledger account.

Open
OID
0d8092…b90a:19
WithdrawPool details

Inspect func

WithdrawPoolAll

func() int64

WithdrawPoolAll is WithdrawPool for the whole pool. It panics on an empty pool rather than succeeding with a zero transfer, so a caller cannot read success as evidence that coins moved.

Open
OID
0d8092…b90a:20
WithdrawPoolAll details

Inspect func

Hire

func(employee .uverse.address, perPeriod int64, periodBlocks int64, startHeight int64, endHeight int64)

Hire opens a position. The caller is the employer and must already have a funded pool, which is this realm's only barrier to opening records at someone else's expense. startHeight must not be in the past. A backdated start would make a large number of periods due in the same transaction that opened the position, draining the pool to one employee in one call — the hire would look like a schedule and behave like a withdrawal. Refusing it is cheaper to reason about than bounding it. ### perPeriod is bounded below and NOT above, and the slot cost is permanent {#hdr-perPeriod_is_bounded_below_and_NOT_above__and_the_slot_cost_is_permanent} MinPerPeriod is a floor; there is no ceiling. A position opened with a perPeriod larger than any pool that can be funded is unsettleable, because Accrue's solvency check is integer division — e.pool/perPeriod is 0 for every reachable pool, so Accrue panics on "cannot cover one period" forever. Once that position's first period completes, duePeriods is permanently non-zero, so Release refuses forever too, and the record consumes one of the employer's MaxRoster slots for good. This is a DECLARED LIMITATION rather than a defect, and the reason is that it is strictly self-harm: owner comes from cur.Previous().Address() below and is never a parameter, so no caller can open an unpayable position on anyone else's roster, and the pool itself stays fully withdrawable through WithdrawPool. The mitigation is available and narrow: Terminate then Release BEFORE the first period completes, while duePeriods is still zero. After that the slot does not come back.

Open
OID
0d8092…b90a:21
Hire details

Inspect func

Accrue

func(employer .uverse.address, employee .uverse.address) int64

Accrue settles every whole period that has completed and not yet been paid, as far as the employer's pool reaches, and credits the gross minus the accrual fee to the employee's ledger balance. ANYONE may call this — see the package doc. It returns the gross amount settled.

Open
OID
0d8092…b90a:22
Accrue details

Inspect func

Terminate

func(employee .uverse.address)

Terminate stops the clock on a position. The employer only. It does NOT remove the record and does not settle anything: whatever was due stays due, and anyone may still Accrue it. That separation is the employee's protection — see the package doc. Use Release to remove a settled position. If the position has not yet reached its first complete period, this pays nothing, by the arrears rule.

Open
OID
0d8092…b90a:23
Terminate details

Inspect func

Release

func(employer .uverse.address, employee .uverse.address)

Release removes an ended, fully-settled position and frees its storage. Permissionless: the chain refunds the freed storage deposit to the caller, which is the standing incentive to tidy up a settled position that is not your own. It refuses while anything is due, which is what makes it safe to let a stranger call: a Release cannot destroy an unpaid obligation.

Open
OID
0d8092…b90a:24
Release details

Inspect func

Claim

func() int64

Claim pays the caller their whole accrued balance. The employee only — there is no "claim on behalf of", because that would let a third party choose the moment someone else's coins move.

Open
OID
0d8092…b90a:25
Claim details

Inspect func

WithdrawFees

func() int64

WithdrawFees moves the accrued fee pot to FeeCollector. Anyone may call it; the destination is a compile-time constant, so the caller cannot influence where the coins go.

Open
OID
0d8092…b90a:26
WithdrawFees details

Inspect func

SweepSurplus

func() int64

SweepSurplus sends coins held beyond every obligation to FeeCollector. The reserve passed to coinio is the realm's full liability — pooled coins plus ledger liabilities — so a sweep can never reach a coin that an employer or an employee is owed.

Open
OID
0d8092…b90a:27
SweepSurplus details

Inspect func

duePeriods

func(p *payroll.position, now int64) int64

duePeriods is the number of whole periods that have completed and not been paid. It is a pure function of the position and the clock, which is what makes it unit-testable without a chain. Periods are ANCHORED to startHeight: period k closes at startHeight + k\*periodBlocks. Nothing is due at startHeight itself — salary is paid in arrears.

Open
OID
0d8092…b90a:28
duePeriods details

Inspect func

DuePeriods

func(employer .uverse.address, employee .uverse.address) int64

DuePeriods is duePeriods for a live position, at the current height.

Open
OID
0d8092…b90a:29
DuePeriods details

Inspect func

DueAmount

func(employer .uverse.address, employee .uverse.address) int64

DueAmount is the gross that DuePeriods would settle if the pool were unbounded. Read it beside AccruableAmount: the difference between them is exactly the employer's shortfall. It is the one arithmetic here with NO pool bound behind it, so it is the one place an int64 can wrap: perPeriod has no ceiling and due grows with the chain. Accrue cannot wrap, because its product is bounded by the pool it is about to debit (see the comment there). An unpayable position is a legal state in this realm, so the overflow is reachable in principle, and this panics rather than returning a negative salary — a view that refuses is recoverable, a view that lies is not.

Open
OID
0d8092…b90a:30
DueAmount details

Inspect func

AccruableAmount

func(employer .uverse.address, employee .uverse.address) int64

AccruableAmount is the gross an Accrue would settle right now, pool bound included. It is the honest number, and it can be less than DueAmount without anything being wrong — see the package doc on solvency.

Open
OID
0d8092…b90a:31
AccruableAmount details

Inspect func

PoolOf

func(employer .uverse.address) int64

PoolOf is an employer's unallocated pool. Zero for an address that has never funded one.

Open
OID
0d8092…b90a:32
PoolOf details

Inspect func

RosterOf

func(employer .uverse.address) int

RosterOf is the number of open positions an employer holds.

Open
OID
0d8092…b90a:33
RosterOf details

Inspect func

BalanceOf

func(employee .uverse.address) int64

BalanceOf is an employee's accrued, unclaimed balance.

Open
OID
0d8092…b90a:34
BalanceOf details

Inspect func

PerPeriodOf

func(employer .uverse.address, employee .uverse.address) int64

PerPeriodOf is a position's gross salary per period.

Open
OID
0d8092…b90a:35
PerPeriodOf details

Inspect func

PaidPeriodsOf

func(employer .uverse.address, employee .uverse.address) int64

PaidPeriodsOf is how many whole periods a position has settled.

Open
OID
0d8092…b90a:36
PaidPeriodsOf details

Inspect func

EndHeightOf

func(employer .uverse.address, employee .uverse.address) int64

EndHeightOf is a position's end height, or OpenEnded.

Open
OID
0d8092…b90a:37
EndHeightOf details

Inspect func

HasPosition

func(employer .uverse.address, employee .uverse.address) bool

HasPosition reports whether a position is open, without panicking on absence — every other position accessor panics, which makes them unusable as an existence probe.

Open
OID
0d8092…b90a:38
HasPosition details

Inspect func

OpenPositions

func() int

OpenPositions is the number of open positions across every employer.

Open
OID
0d8092…b90a:39
OpenPositions details

Inspect func

Employers

func() int

Employers is the number of addresses that have ever funded a pool. Note the tense: an employer record survives a pool going to zero, so this is not a count of currently-funded employers.

Open
OID
0d8092…b90a:40
Employers details

Inspect func

TotalPooled

func() int64

TotalPooled is the sum of every employer's unallocated pool.

Open
OID
0d8092…b90a:41
TotalPooled details

Inspect func

AccruedTotal

func() int64

AccruedTotal is the sum of every employee's unclaimed balance.

Open
OID
0d8092…b90a:42
AccruedTotal details

Inspect func

FeesAccrued

func() int64

FeesAccrued is the fee pot awaiting WithdrawFees.

Open
OID
0d8092…b90a:43
FeesAccrued details

Inspect func

Liabilities

func() int64

Liabilities is every coin this realm owes to anyone: pooled coins plus the ledger's own total (employee balances plus the fee pot).

Open
OID
0d8092…b90a:44
Liabilities details

Inspect func

Held

func() int64

Held is the realm's actual ugnot balance, read from the chain.

Open
OID
0d8092…b90a:45
Held details

Inspect func

Surplus

func() int64

Surplus is coins held beyond every obligation — what SweepSurplus would move. It is zero when every coin arrived through an entrypoint.

Open
OID
0d8092…b90a:46
Surplus details

Inspect func

Height

func() int64

Height is the current chain height, exposed so a caller can compute period boundaries against the same clock this realm uses.

Open
OID
0d8092…b90a:48
Height details

Inspect func

posKey

func(employer .uverse.address, employee .uverse.address) string
Open
OID
0d8092…b90a:49
posKey details

Inspect func

getEmployer

func(key string) *payroll.employer
Open
OID
0d8092…b90a:50
getEmployer details

Inspect func

mustEmployer

func(key string) *payroll.employer
Open
OID
0d8092…b90a:51
mustEmployer details

Inspect func

mustPosition

func(employer .uverse.address, employee .uverse.address) *payroll.position
Open
OID
0d8092…b90a:52
mustPosition details

Inspect func

checkedAdd

func(a int64, b int64) (int64, bool)
Open
OID
0d8092…b90a:53
checkedAdd details

Inspect func

checkedMul

func(a int64, b int64) (int64, bool)

checkedMul reports a\*b and whether it is exact. Both operands here are non-negative (duePeriods never returns a negative, perPeriod is validated at or above MinPerPeriod), so the division test is sufficient and the sign cases a general version would need are deliberately absent.

Open
OID
0d8092…b90a:54
checkedMul details

Inspect func
RealmPath : untyped string ="/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/payroll"
Denom : untyped string ="ugnot"
MaxFeeBps : int64 =500
AccrueFeeBps : int64 =100
FeeCollector : .uverse.address =<gnolang.StringValue>
MinFunding : int64 =1000000
MinPerPeriod : int64 =1000
MinPeriodBlocks : int64 =100
MaxRoster : untyped bigint =(64 <untyped> bigint)
OpenEnded : int64 =0
position : type =payroll.position
self : .uverse.address =<gnolang.StringValue>
employers : *v0.Tree Inspect
positions : *v0.Tree Inspect
ledger : *feeledger.Ledger Inspect
employer : type =payroll.employer
init.16 : func() Inspect
rejectStraySend : func() Inspect
Fund : func() int64 Inspect
WithdrawPool : func(amount int64) int64 Inspect
WithdrawPoolAll : func() int64 Inspect
Hire : func(employee .uverse.address, perPeriod int64, periodBlocks int64, startHeight int64, endHeight int64) Inspect
Accrue : func(employer .uverse.address, employee .uverse.address) int64 Inspect
Terminate : func(employee .uverse.address) Inspect
Release : func(employer .uverse.address, employee .uverse.address) Inspect
Claim : func() int64 Inspect
WithdrawFees : func() int64 Inspect
SweepSurplus : func() int64 Inspect
duePeriods : func(p *payroll.position, now int64) int64 Inspect
DuePeriods : func(employer .uverse.address, employee .uverse.address) int64 Inspect
DueAmount : func(employer .uverse.address, employee .uverse.address) int64 Inspect
AccruableAmount : func(employer .uverse.address, employee .uverse.address) int64 Inspect
PoolOf : func(employer .uverse.address) int64 Inspect
RosterOf : func(employer .uverse.address) int Inspect
BalanceOf : func(employee .uverse.address) int64 Inspect
PerPeriodOf : func(employer .uverse.address, employee .uverse.address) int64 Inspect
PaidPeriodsOf : func(employer .uverse.address, employee .uverse.address) int64 Inspect
EndHeightOf : func(employer .uverse.address, employee .uverse.address) int64 Inspect
HasPosition : func(employer .uverse.address, employee .uverse.address) bool Inspect
OpenPositions : func() int Inspect
Employers : func() int Inspect
TotalPooled : func() int64 Inspect
AccruedTotal : func() int64 Inspect
FeesAccrued : func() int64 Inspect
Liabilities : func() int64 Inspect
Held : func() int64 Inspect
Surplus : func() int64 Inspect
Address : func() .uverse.address Inspect
Height : func() int64 Inspect
posKey : func(employer .uverse.address, employee .uverse.address) string Inspect
getEmployer : func(key string) *payroll.employer Inspect
mustEmployer : func(key string) *payroll.employer Inspect
mustPosition : func(employer .uverse.address, employee .uverse.address) *payroll.position Inspect
checkedAdd : func(a int64, b int64) (int64, bool) Inspect
checkedMul : func(a int64, b int64) (int64, bool) Inspect
itoa : func(n int64) string Inspect
Render : func(path string) string Inspect