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/r/moul/x/daily/splitter/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / splitter
Files
3 (README)(gnomod.toml)
Exported functions
3
Module
gno.land/r/moul/x/daily/splitter/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • splitter.gnogno
splitter.gnogno
1// Package splitter is a share-based payment splitter for gno.land.2//3// It is an accounting-only port of the Solidity PaymentSplitter pattern:4// no real coins move. A group is registered with a list of payees and a5// matching list of integer shares. Income recorded against a group is6// pooled, and each payee is owed a slice of that pool proportional to7// their shares: owed = pool * share / totalShares.8package splitter910import (11	"errors"12	"strconv"13	"strings"1415	"chain"16	"chain/runtime/unsafe"1718	"gno.land/p/nt/avl/v0"19)2021// payee is a single share holder inside a group.22type payee struct {23	addr   address24	shares int25}2627// group is one payment-splitting arrangement.28type group struct {29	id          int30	owner       address31	payees      []payee32	totalShares int33	pool        int // total income recorded, in abstract units34}3536var (37	groups   avl.Tree // id (zero-padded string) -> *group38	nextID   int39	errEmpty = errors.New("splitter: no payees")40)4142// Register creates a new group from comma-separated payees and shares.43// payees:  "g1abc...,g1def..."  (addresses)44// shares:  "3,1"                (positive integers, same count as payees)45// Returns the new group id. Panics on malformed input.46func Register(cur realm, payees string, shares string) int {47	caller := unsafe.PreviousRealm().Address()4849	addrParts := splitTrim(payees)50	shareParts := splitTrim(shares)5152	if len(addrParts) == 0 {53		panic(errEmpty)54	}55	if len(addrParts) != len(shareParts) {56		panic("splitter: payees and shares count mismatch")57	}5859	g := &group{60		id:    nextID,61		owner: caller,62	}63	for i := range addrParts {64		if addrParts[i] == "" {65			panic("splitter: empty payee address")66		}67		s, err := strconv.Atoi(shareParts[i])68		if err != nil {69			panic("splitter: bad share value: " + shareParts[i])70		}71		if s <= 0 {72			panic("splitter: share must be positive")73		}74		g.payees = append(g.payees, payee{75			addr:   address(addrParts[i]),76			shares: s,77		})78		g.totalShares += s79	}8081	groups.Set(key(g.id), g)82	nextID++8384	chain.Emit(85		"GroupRegistered",86		"id", strconv.Itoa(g.id),87		"payees", strconv.Itoa(len(g.payees)),88		"totalShares", strconv.Itoa(g.totalShares),89	)90	return g.id91}9293// RecordIncome adds amount to the pool of group id. amount must be positive.94func RecordIncome(cur realm, id int, amount int) {95	if amount <= 0 {96		panic("splitter: amount must be positive")97	}98	v := groups.Get(key(id))99	if v == nil {100		panic("splitter: unknown group id: " + strconv.Itoa(id))101	}102	g := v.(*group)103	g.pool += amount104	groups.Set(key(id), g)105106	chain.Emit(107		"IncomeRecorded",108		"id", strconv.Itoa(id),109		"amount", strconv.Itoa(amount),110		"pool", strconv.Itoa(g.pool),111	)112}113114// owed returns the amount owed to a payee: pool * shares / totalShares.115func (g *group) owed(p payee) int {116	if g.totalShares == 0 {117		return 0118	}119	return g.pool * p.shares / g.totalShares120}121122// Render shows all groups, their payees, shares, and computed owed amounts.123func Render(path string) string {124	if groups.Size() == 0 {125		return "# Payment Splitter\n\n_No groups registered yet._\n"126	}127128	var b strings.Builder129	b.WriteString("# Payment Splitter\n\n")130	b.WriteString("Share-based accounting. `owed = pool * share / totalShares`.\n\n")131132	groups.Iterate("", "", func(k string, v interface{}) bool {133		g := v.(*group)134		b.WriteString("## Group #" + strconv.Itoa(g.id) + "\n\n")135		b.WriteString("- Owner: `" + g.owner.String() + "`\n")136		b.WriteString("- Pool: " + strconv.Itoa(g.pool) + "\n")137		b.WriteString("- Total shares: " + strconv.Itoa(g.totalShares) + "\n\n")138139		b.WriteString("| Payee | Shares | Owed |\n")140		b.WriteString("|---|---:|---:|\n")141		distributed := 0142		for _, p := range g.payees {143			o := g.owed(p)144			distributed += o145			b.WriteString("| `" + p.addr.String() + "` | " +146				strconv.Itoa(p.shares) + " | " + strconv.Itoa(o) + " |\n")147		}148		remainder := g.pool - distributed149		if remainder > 0 {150			b.WriteString("| _remainder (rounding)_ | | " +151				strconv.Itoa(remainder) + " |\n")152		}153		b.WriteString("\n")154		return false155	})156157	return b.String()158}159160// splitTrim splits on commas and trims whitespace around each element.161func splitTrim(s string) []string {162	if strings.TrimSpace(s) == "" {163		return nil164	}165	parts := strings.Split(s, ",")166	out := make([]string, 0, len(parts))167	for _, p := range parts {168		out = append(out, strings.TrimSpace(p))169	}170	return out171}172173// key produces a zero-padded, lexicographically-sortable avl key for an id,174// so Render iterates groups in ascending numeric order.175func key(id int) string {176	s := strconv.Itoa(id)177	for len(s) < 12 {178		s = "0" + s179	}180	return s181}182

Functions

  • RecordIncome(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, id int, amount int)

  • Register(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, payees string, shares string) int

  • Render(path string) string

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

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.