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/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/fee_split/v2

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v2
Namespace
g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39 / fee_split
Files
3 (gnomod.toml)
Exported functions
17
Module
gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/fee_split/v2
gno
0.9

Files (3)

  • gnomod.tomltoml
  • fee_split.gnogno
  • fee_split_test.gnogno
fee_split.gnogno
1package fee_split23import (4	"chain"5	"chain/banker"6	"chain/runtime/unsafe"7	"sort"8	"strconv"9	"strings"10)1112// Split holds a fee-splitting configuration with percentage-based shares13// denominated in basis points (1 bp = 0.01%, 10000 bp = 100%).14type Split struct {15	Owner          address16	PendingOwner   address // two-step handover, must AcceptOwnership17	Recipients     []address18	Shares         []int64 // basis points, must sum to 1000019	Balances       map[address]int6420	TotalDeposited int6421	TotalClaimed   int6422	Frozen         bool23	Archived       bool24}2526const (27	MaxRecipients     = 2028	MaxSplitsPerOwner = 1029	// Quotas are PER-OWNER only (round-4 audit): a global cap is a shared30	// resource 50 sybil accounts could fill forever — and seeding grief31	// splits with balances to keyless recipients made the fill32	// unrecoverable even by the sybils. Per-owner quotas mean an attacker33	// consumes only their own budget; state growth is gas-priced.34	// Render is bounded separately (MaxRenderSplits).35	MaxRenderSplits = 10036	// MaxFeeBps is an IMMUTABLE ceiling on the protocol fee (1%). The37	// admin can set any fee from 0 up to this cap, never above it — the38	// cap, not the current setting, is what users must trust.39	MaxFeeBps = int64(100)4041	// Pre-parse input bounds (round-4 audit): caps were enforced only42	// AFTER full parsing, so a 1MB recipient list burned ~11B gas before43	// refusal. 20 bech32 addresses + separators fit well within these.44	MaxRecipientListLen = 102445	MaxShareListLen     = 1284647	// Denomination handled by this realm. Deposits must be exactly one48	// coin of this denom; claims pay out in it.49	Denom = "ugnot"5051	// Largest single deposit for which share math (amount * share,52	// share <= 10000) cannot overflow int64.53	MaxDepositAmount = int64(9223372036854775807) / 1000054)5556var (57	splits      map[string]*Split58	splitIDs    []string // insertion-ordered for deterministic Render59	ownerSplits map[address]int60	nextID      int6162	// Protocol fee: taken from each deposit BEFORE distribution, at the63	// rate in force at deposit time (never retroactive — credited64	// balances are never touched). Defaults to zero.65	feeBps          int6466	feeAdmin        address // deployer; can set the fee and claim accrued fees67	pendingFeeAdmin address // two-step handover, must AcceptFeeAdmin68	feesAccrued     int6469	feesClaimed     int6470)7172func init() {73	splits = make(map[string]*Split)74	splitIDs = []string{}75	ownerSplits = make(map[address]int)76	nextID = 177	// The package deployer becomes the fee admin: on-chain, AddPackage78	// runs init with the message creator as origin caller (verified79	// against the VM keeper — a MsgAddPackage's creator is never zero).80	// If OriginCaller() were ever empty (e.g. the gno test VM, which has81	// no MsgAddPackage), the fee feature degrades SAFELY to disabled:82	// SetFee requires the runtime-derived caller to equal feeAdmin and83	// that caller is never empty, so84	// feeBps can never leave 0 and no fee ever accrues — zero funds at85	// risk. Do not "harden" this into a panic; the soft-disable is the86	// safe behavior. Fee starts at ZERO regardless.87	feeAdmin = unsafe.OriginCaller()88	feeBps = 089}9091// ---------- helpers ----------9293func formatPct(bp int64) string {94	whole := strconv.FormatInt(bp/100, 10)95	frac := strconv.FormatInt(bp%100, 10)96	if len(frac) == 1 {97		frac = "0" + frac98	}99	return whole + "." + frac + "%"100}101102func mustGetSplit(id string) *Split {103	s, ok := splits[id]104	if !ok {105		panic("split not found: " + id)106	}107	return s108}109110func mustGetActive(id string) *Split {111	s := mustGetSplit(id)112	if s.Archived {113		panic("split is archived: " + id)114	}115	return s116}117118func boolStr(v bool) string {119	if v {120		return "yes"121	}122	return "no"123}124125func parseBasisPoints(raw string) []int64 {126	if len(raw) > MaxShareListLen {127		panic("share list too long")128	}129	parts := strings.Split(raw, ",")130	out := make([]int64, len(parts))131	var total int64132	for i, s := range parts {133		v, err := strconv.Atoi(strings.TrimSpace(s))134		if err != nil || v <= 0 || v > 10000 {135			// the upper bound is a security invariant, not hygiene: unbounded136			// shares let the int64 total wrap back to exactly 10000, minting137			// unbacked balances paid from the shared pool (re-audit P1)138			panic("invalid share value: " + strings.TrimSpace(s))139		}140		out[i] = int64(v)141		total += int64(v)142	}143	if total != 10000 {144		panic("shares must sum to 10000 basis points, got " + strconv.FormatInt(total, 10))145	}146	return out147}148149func parseAddresses(raw string) []address {150	if len(raw) > MaxRecipientListLen {151		panic("recipient list too long")152	}153	parts := strings.Split(raw, ",")154	out := make([]address, len(parts))155	for i, r := range parts {156		a := address(strings.TrimSpace(r))157		if a == "" {158			panic("empty recipient address at position " + strconv.Itoa(i))159		}160		if !a.IsValid() || string(a) != strings.ToLower(string(a)) {161			// lowercase is required, not cosmetic (round-3 audit): bech32162			// accepts ALL-UPPERCASE as valid, but the runtime always returns163			// the lowercase canonical form — an uppercase-keyed balance164			// could never be claimed and would block Archive forever, and165			// upper/lower duplicates would bypass the duplicate check166			panic("invalid recipient address: " + string(a))167		}168		// NOTE: IsValid is a format check only — a well-formed address with169		// no key holder (e.g. another package's derived address) will170		// accumulate a balance nobody can claim, which also blocks Archive171		// forever. Owners must list addresses they know can call Claim.172		out[i] = a173	}174	return out175}176177func validateRecipients(recipients []address, shares []int64) {178	if len(recipients) != len(shares) {179		panic("recipients and shares must have the same length")180	}181	if len(recipients) == 0 {182		panic("at least one recipient is required")183	}184	if len(recipients) > MaxRecipients {185		panic("too many recipients (max " + strconv.Itoa(MaxRecipients) + ")")186	}187	seen := make(map[address]bool)188	for _, r := range recipients {189		if seen[r] {190			panic("duplicate recipient: " + string(r))191		}192		seen[r] = true193	}194}195196// sortedBalanceAddrs returns the balance-map keys in deterministic order,197// so panics and renders never depend on map iteration order.198func sortedBalanceAddrs(s *Split) []string {199	addrs := make([]string, 0, len(s.Balances))200	for a := range s.Balances {201		addrs = append(addrs, string(a))202	}203	sort.Strings(addrs)204	return addrs205}206207// rejectStraySend aborts when coins are attached to a call that does not208// accept them — the abort reverts the transfer back to the sender instead209// of stranding the coins on the realm address (re-audit P3). Direct bank210// transfers to the realm address remain unrecoverable by design.211func rejectStraySend(cur realm) {212	if !cur.IsCurrent() {213		// every call site passes the entrypoint's own first cur; this214		// pins that discipline against future call-site drift (v2215		// audit G3 hardening)216		panic("realm capability is not current")217	}218	if cur.Previous().IsUserCall() && len(unsafe.OriginSend()) > 0 {219		panic("this function does not accept coins; attach coins to Deposit only")220	}221}222223// ---------- write operations ----------224225// CreateSplit registers a new split. The caller becomes the owner.226// Recipients and shares are comma-separated; shares are in basis points227// summing to 10000.228func CreateSplit(cur realm, recipientList, shareList string) string {229	rejectStraySend(cur)230	owner := cur.Previous().Address()231	if ownerSplits[owner] >= MaxSplitsPerOwner {232		panic("per-owner split limit reached")233	}234235	recipients := parseAddresses(recipientList)236	shares := parseBasisPoints(shareList)237	validateRecipients(recipients, shares)238239	id := "split_" + strconv.Itoa(nextID)240	nextID++241242	balances := make(map[address]int64)243	for _, r := range recipients {244		balances[r] = 0245	}246247	splits[id] = &Split{248		Owner:      owner,249		Recipients: recipients,250		Shares:     shares,251		Balances:   balances,252	}253	splitIDs = append(splitIDs, id)254	ownerSplits[owner]++255	return id256}257258// Deposit distributes the coins sent with the call across recipients259// proportionally.260//261// DEPLOYMENT PRECONDITION (round-4 audit): on a network with262// restricted/token-locked ugnot transfers, the bank gate is263// SENDER-whitelist-based — a whitelisted user's Deposit succeeds but264// Claim sends FROM this realm's (non-whitelisted) address and reverts.265// Funds would flow in and not out until the restriction lifts. Deploy266// only to networks with unrestricted ugnot, or have governance267// whitelist this realm's address first.268//269// LIMITATION (round-3 audit, documented): only direct user calls can270// deposit. A DAO/realm treasury has NO deposit path — a realm-routed271// call is refused, and a bare banker send to this realm's address is272// an unrecoverable donation. Realm treasuries must route deposits273// through a user account. The deposit is the ACTUAL attached send — exactly one274// coin of Denom — so balances are always backed by funds this realm275// holds. Direct user calls only: a deposit routed through an276// intermediary realm would deliver its coins to that realm, not here,277// and must be rejected. Rounding dust goes to the highest-share278// recipient (deterministic, not order-dependent).279func Deposit(cur realm, splitID string) {280	s := mustGetActive(splitID)281	if s.Frozen {282		panic("split is frozen")283	}284285	// IsUserCall, not IsUser: MsgRun passes IsUser but its attached send286	// goes caller->caller — the coins never reach this realm, and OriginSend287	// could be re-read across k calls in one run script (re-audit P1). A288	// direct MsgCall's send provably lands on the called package address.289	if !cur.Previous().IsUserCall() {290		panic("deposits must be sent by direct call, not through another realm or a run script")291	}292	sent := unsafe.OriginSend()293	if len(sent) != 1 || sent[0].Denom != Denom {294		panic("deposit must send exactly one coin of " + Denom)295	}296	amount := sent[0].Amount297	if amount <= 0 {298		panic("amount must be greater than zero")299	}300	if amount > MaxDepositAmount {301		panic("deposit exceeds maximum supported amount")302	}303	if s.TotalDeposited > int64(9223372036854775807)-amount {304		panic("deposit would overflow split accounting")305	}306307	// Protocol fee comes off the top; everything below distributes the308	// NET amount, so the per-split conservation invariant309	// (sum(balances)+TotalClaimed == TotalDeposited) is untouched.310	// amount <= MaxDepositAmount and feeBps <= 100, so the product is311	// far below overflow.312	fee := (amount * feeBps) / 10000313	if fee > 0 {314		if feesAccrued > int64(9223372036854775807)-fee {315			panic("fee accrual would overflow")316		}317		feesAccrued += fee318		amount -= fee319	}320	if amount == 0 {321		panic("deposit too small: fully consumed by the protocol fee")322	}323324	s.TotalDeposited += amount325326	// Find the highest-share recipient for dust assignment327	dustIdx := 0328	for i := 1; i < len(s.Shares); i++ {329		if s.Shares[i] > s.Shares[dustIdx] {330			dustIdx = i331		}332	}333334	var distributed int64335	for i, r := range s.Recipients {336		share := (amount * s.Shares[i]) / 10000337		s.Balances[r] += share338		distributed += share339	}340341	// Assign dust to highest-share recipient342	dust := amount - distributed343	if dust > 0 {344		s.Balances[s.Recipients[dustIdx]] += dust345	}346}347348// Claim withdraws the caller's accumulated balance and SENDS the coins349// to the caller's address. Balance is zeroed before the transfer.350// Claims remain possible on frozen splits, and by ex-recipients whose351// accrued balance predates a share update.352func Claim(cur realm, splitID string) int64 {353	rejectStraySend(cur)354	s := mustGetActive(splitID)355	addr := cur.Previous().Address()356357	bal, exists := s.Balances[addr]358	if !exists {359		panic("not a recipient of this split")360	}361	if bal == 0 {362		panic("nothing to claim")363	}364365	s.Balances[addr] = 0366	s.TotalClaimed += bal367368	b := banker.NewBanker(banker.BankerTypeRealmSend, cur)369	b.SendCoins(cur.Address(), addr,370		chain.Coins{{Denom: Denom, Amount: bal}})371	return bal372}373374// UpdateShares replaces recipients and shares. Owner only. Not if frozen.375// Removed recipients keep any accrued balance and can still Claim it.376func UpdateShares(cur realm, splitID, recipientList, shareList string) {377	rejectStraySend(cur)378	s := mustGetActive(splitID)379	if cur.Previous().Address() != s.Owner {380		panic("only the owner can update shares")381	}382	if s.Frozen {383		panic("split is frozen")384	}385386	recipients := parseAddresses(recipientList)387	shares := parseBasisPoints(shareList)388	validateRecipients(recipients, shares)389390	for _, r := range recipients {391		if _, ok := s.Balances[r]; !ok {392			s.Balances[r] = 0393		}394	}395396	s.Recipients = recipients397	s.Shares = shares398}399400// TransferOwnership stages a two-step ownership handover; nothing401// moves until the nominee calls AcceptOwnership. Two-step for the same402// reason as the fee admin, plus one more (v2 audit Y1): a one-step403// transfer consumed the RECIPIENT's per-owner quota without consent,404// so poisoned splits could burn a victim's slots unarchivably. Staging405// consumes nothing of the nominee's. Pass "" to clear a pending406// nomination.407func TransferOwnership(cur realm, splitID string, newOwner address) {408	rejectStraySend(cur)409	s := mustGetActive(splitID)410	if cur.Previous().Address() != s.Owner {411		panic("only the owner can transfer ownership")412	}413	if newOwner == "" {414		s.PendingOwner = ""415		return416	}417	if !newOwner.IsValid() || string(newOwner) != strings.ToLower(string(newOwner)) {418		// see parseAddresses: an uppercase owner could never match the419		// runtime-derived caller again — the split would be owner-less420		panic("invalid new owner address: " + string(newOwner))421	}422	if newOwner == s.Owner {423		panic("new owner is already the owner")424	}425	s.PendingOwner = newOwner426}427428// AcceptOwnership completes the handover; only the nominee can accept.429// The nominee's quota is checked HERE, at consent time — the split430// slot moves only with the acceptor's own signature (v2 audit Y1: a431// recipient's quota is never consumed without consent). A nomination432// on a split that is later archived is inert (mustGetActive).433func AcceptOwnership(cur realm, splitID string) {434	rejectStraySend(cur)435	s := mustGetActive(splitID)436	caller := cur.Previous().Address()437	if s.PendingOwner == "" || caller != s.PendingOwner {438		panic("caller is not the pending owner")439	}440	if ownerSplits[caller] >= MaxSplitsPerOwner {441		panic("new owner is at the per-owner split limit")442	}443444	ownerSplits[s.Owner]--445	if ownerSplits[s.Owner] <= 0 {446		delete(ownerSplits, s.Owner)447	}448	ownerSplits[caller]++449	s.Owner = caller450	s.PendingOwner = ""451}452453// Freeze permanently locks shares and stops further deposits. One-way,454// cannot be undone. Claims remain possible.455func Freeze(cur realm, splitID string) {456	rejectStraySend(cur)457	s := mustGetActive(splitID)458	if cur.Previous().Address() != s.Owner {459		panic("only the owner can freeze")460	}461	s.Frozen = true462}463464// Archive marks a fully-claimed split as archived. Only the owner can465// archive, and only if EVERY balance — including balances held by466// ex-recipients removed in a share update — is zero, since archiving467// blocks all further claims. Cannot be undone.468func Archive(cur realm, splitID string) {469	rejectStraySend(cur)470	s := mustGetActive(splitID)471	if cur.Previous().Address() != s.Owner {472		panic("only the owner can archive")473	}474475	for _, a := range sortedBalanceAddrs(s) {476		if s.Balances[address(a)] > 0 {477			panic("cannot archive: outstanding balance for " + a)478		}479	}480481	s.Archived = true482483	// Free the owner's slot so they can create new splits484	ownerSplits[s.Owner]--485	if ownerSplits[s.Owner] <= 0 {486		delete(ownerSplits, s.Owner)487	}488489	// Remove from active ID list (keeps map entry for audit)490	for i, id := range splitIDs {491		if id == splitID {492			splitIDs = append(splitIDs[:i], splitIDs[i+1:]...)493			break494		}495	}496}497498// ---------- protocol fee ----------499500// SetFee sets the protocol fee in basis points, admin only, hard-capped501// at MaxFeeBps. Applies to FUTURE deposits only.502func SetFee(cur realm, bps int64) {503	rejectStraySend(cur)504	if cur.Previous().Address() != feeAdmin {505		panic("only the fee admin can set the fee")506	}507	if bps < 0 || bps > MaxFeeBps {508		panic("fee must be between 0 and " + strconv.FormatInt(MaxFeeBps, 10) + " basis points")509	}510	feeBps = bps511}512513// ClaimFees sends all accrued protocol fees to the fee admin.514func ClaimFees(cur realm) int64 {515	rejectStraySend(cur)516	if cur.Previous().Address() != feeAdmin {517		panic("only the fee admin can claim fees")518	}519	if feesAccrued == 0 {520		panic("no fees accrued")521	}522	amount := feesAccrued523	feesAccrued = 0524	feesClaimed += amount525526	b := banker.NewBanker(banker.BankerTypeRealmSend, cur)527	b.SendCoins(cur.Address(), feeAdmin,528		chain.Coins{{Denom: Denom, Amount: amount}})529	return amount530}531532// NominateFeeAdmin begins a two-step admin handover; the nominee must533// AcceptFeeAdmin. Pass "" to clear a pending nomination. Two-step534// because the admin address is a funds destination: a typo'd one-step535// transfer would strand all future fees.536func NominateFeeAdmin(cur realm, nominee address) {537	rejectStraySend(cur)538	if cur.Previous().Address() != feeAdmin {539		panic("only the fee admin can nominate a successor")540	}541	if nominee == "" {542		pendingFeeAdmin = ""543		return544	}545	if !nominee.IsValid() || string(nominee) != strings.ToLower(string(nominee)) {546		panic("invalid nominee address: " + string(nominee))547	}548	pendingFeeAdmin = nominee549}550551// AcceptFeeAdmin completes the handover; only the nominee can accept.552func AcceptFeeAdmin(cur realm) {553	rejectStraySend(cur)554	if pendingFeeAdmin == "" || cur.Previous().Address() != pendingFeeAdmin {555		panic("caller is not the pending fee admin")556	}557	feeAdmin = pendingFeeAdmin558	pendingFeeAdmin = ""559}560561// GetFeeInfo returns the current fee configuration and accrued total.562func GetFeeInfo() string {563	return "fee: " + formatPct(feeBps) + " (cap " + formatPct(MaxFeeBps) +564		") | admin: " + string(feeAdmin) +565		" | accrued: " + strconv.FormatInt(feesAccrued, 10) +566		" | claimed: " + strconv.FormatInt(feesClaimed, 10)567}568569// ---------- read-only queries ----------570571// GetSplitInfo returns a human-readable summary.572func GetSplitInfo(splitID string) string {573	s := mustGetSplit(splitID)574575	var b strings.Builder576	b.WriteString("Split: " + splitID + "\n")577	b.WriteString("Owner: " + string(s.Owner) + "\n")578	if s.PendingOwner != "" {579		// a nominee must be able to READ the offer before spending gas580		// probing it with AcceptOwnership (v2 audit Y1-obs)581		b.WriteString("Pending owner: " + string(s.PendingOwner) + "\n")582	}583	b.WriteString("Frozen: " + boolStr(s.Frozen) + "\n")584	b.WriteString("Archived: " + boolStr(s.Archived) + "\n")585	b.WriteString("Total deposited: " + strconv.FormatInt(s.TotalDeposited, 10) + "\n")586	b.WriteString("Total claimed: " + strconv.FormatInt(s.TotalClaimed, 10) + "\n")587	b.WriteString("Recipients:\n")588	for i, r := range s.Recipients {589		b.WriteString("  " + string(r) + "  " + formatPct(s.Shares[i]) + "  claimable: " + strconv.FormatInt(s.Balances[r], 10) + "\n")590	}591	return b.String()592}593594// GetPendingOwner returns the staged nominee for a split, or "" when no595// handover is pending. The consent half of a two-step transfer only means596// something if the nominee can inspect the offer without paying gas to597// probe it (v2 audit Y1-obs); this is that read path.598func GetPendingOwner(splitID string) string {599	return string(mustGetSplit(splitID).PendingOwner)600}601602// GetClaimable returns claimable balance for an address.603func GetClaimable(splitID string, addr address) int64 {604	s := mustGetSplit(splitID)605	return s.Balances[addr]606}607608// ---------- render ----------609610// Render returns a markdown overview. Never panics.611func Render(path string) string {612	if len(splitIDs) == 0 {613		return "# Fee Split\n\nNo active splits.\n"614	}615616	var b strings.Builder617	b.WriteString("# Fee Split\n\n")618	if feeBps > 0 {619		b.WriteString("**Protocol fee:** " + formatPct(feeBps) + " (hard cap " + formatPct(MaxFeeBps) + ")\n\n")620	}621622	show := splitIDs623	if len(show) > MaxRenderSplits {624		b.WriteString("_Showing the most recent " + strconv.Itoa(MaxRenderSplits) + " active splits._\n\n")625		show = show[len(show)-MaxRenderSplits:]626	}627	for _, id := range show {628		s := splits[id]629		b.WriteString("## " + id + "\n\n")630		if s == nil {631			b.WriteString("_(invalid)_\n\n")632			continue633		}634		b.WriteString("```\n")635		b.WriteString("Owner: " + string(s.Owner) + "\n")636		if s.PendingOwner != "" {637			b.WriteString("Pending owner: " + string(s.PendingOwner) + "\n")638		}639		b.WriteString("Frozen: " + boolStr(s.Frozen) + "\n")640		b.WriteString("Total deposited: " + strconv.FormatInt(s.TotalDeposited, 10) + "\n")641		b.WriteString("Total claimed: " + strconv.FormatInt(s.TotalClaimed, 10) + "\n")642		if len(s.Recipients) > 0 {643			b.WriteString("Recipients:\n")644			for i, r := range s.Recipients {645				share := "??%"646				if i < len(s.Shares) {647					share = formatPct(s.Shares[i])648				}649				bal := "0"650				if s.Balances != nil {651					bal = strconv.FormatInt(s.Balances[r], 10)652				}653				b.WriteString("  " + string(r) + "  " + share + "  claimable: " + bal + "\n")654			}655		}656		b.WriteString("```\n\n")657	}658	return b.String()659}660

Functions

  • AcceptFeeAdmin(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})

  • AcceptOwnership(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}, splitID string)

  • Archive(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}, splitID string)

  • Claim(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}, splitID string) int64

  • ClaimFees(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}) int64

  • CreateSplit(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}, recipientList string, shareList string) string

  • Deposit(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}, splitID string)

  • Freeze(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}, splitID string)

  • GetClaimable(splitID string, addr string) int64

  • GetFeeInfo() string

  • GetPendingOwner(splitID string) string

  • GetSplitInfo(splitID string) string

  • NominateFeeAdmin(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}, nominee string)

  • Render(path string) string

  • SetFee(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}, bps int64)

  • TransferOwnership(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}, splitID string, newOwner string)

  • UpdateShares(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}, splitID string, recipientList string, shareList 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.