PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/games/prorata/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / games / prorata
Files
4 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/games/prorata/v0
gno
0.9

Files (4)

  • README.mdmarkdown
  • gnomod.tomltoml
  • prorata.gnogno
  • prorata_test.gnogno
README.mdPreviewRaw
# `gno.land/p/moul/x/games/prorata/v0`

**A weighted split of an integer amount that adds up**: `Split`, `Share`,
`Total`.

```go
import "gno.land/p/moul/x/games/prorata/v0"

prorata.Split(100, []int64{1, 2, 3})  // [17 33 50], and it sums to exactly 100
prorata.Split(10, []int64{1, 1, 1})   // [4 3 3], the dust goes to the lowest index
prorata.Share(100, 1, 3)              // 33, floored: "what would I get"
```

Every payout in a game is this operation: a pot, a roster, a weight each. Written
the obvious way, `amount*weight/total` per claimant, it is wrong in two ways that
only show up once there is real money in the contract.

**The shares do not add up.** Each one is rounded down, so their sum is short by
up to one unit per claimant. That dust either sits in the realm forever or lands
on whoever the loop happened to pay last, which is a rule nobody chose. `Split`
distributes by **largest remainder**: floor every share, then hand the leftover
units out one at a time to the claimants whose truncated fraction was largest,
ties going to the lower index. The result sums to **exactly** the amount, and the
rule is deterministic, so every node computes the same split and a `Render` of it
does not change between calls.

**`amount*weight` overflows an int64** long before either factor does, which
turns a large payout negative. Nothing here ever computes that product: it splits
the amount into whole multiples of the total and what is left over, so
`amount*weight/total` becomes `q*weight + r*weight/total` with `r` already
smaller than the total. A pot of 10^18 ugnot across billion-unit weights is
exact, and what genuinely cannot fit returns `ErrOverflow` rather than wrapping.

Two smaller decisions, each with a test:

- **A zero weight is paid nothing, including no remainder unit.** Somebody with
  no claim is not handed dust.
- **An empty roster, or one where every weight is zero, is an error**, not an
  empty split. Silently returning nothing would strand the amount, and only the
  caller knows where it should go instead.

Nothing here reads the chain and nothing holds coins: the caller owns the roster
and the custody.

**Live game:** [`r/moul/x/games/lastwords`](https://github.com/moul/gno-contracts/tree/main/r/moul/x/games/lastwords)
· render it at [`/r/moul/x/games/lastwords/v0`](https://gno.land/r/moul/x/games/lastwords/v0).

<!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) -->

---

Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

> 🧪 **Highly experimental — potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md).

<!-- END GNOCONTRACTS FOOTER -->

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.