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/samcrew/memba_weighted_host

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
memba_weighted_host
Namespace
samcrew
Files
32 (gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/samcrew/memba_weighted_host
gno
0.9

Files (32)

  • gnomod.tomltoml
  • appstore_actions.gnogno
  • appstore_host.gnogno
  • appstore_reads.gnogno
  • arcade_actions.gnogno
  • arcade_host.gnogno
  • arcade_reads.gno
gno
  • badges_actions.gnogno
  • badges_host.gnogno
  • badges_reads.gnogno
  • channels_actions.gnogno
  • channels_host.gnogno
  • channels_reads.gnogno
  • escrow_actions.gnogno
  • escrow_host.gnogno
  • escrow_reads.gnogno
  • feed_actions.gnogno
  • feed_host.gnogno
  • feed_reads.gnogno
  • feedback_actions.gnogno
  • feedback_host.gnogno
  • feedback_reads.gnogno
  • host.gnogno
  • market_actions.gnogno
  • market_host.gnogno
  • quest_actions.gnogno
  • quest_host.gnogno
  • quest_reads.gnogno
  • reads.gnogno
  • reviews_actions.gnogno
  • reviews_host.gnogno
  • reviews_reads.gnogno
  • reads.gnogno
    1package memba_weighted_host23import (4	"strconv"5	"strings"6	"time"78

    Functions

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

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

    "gno.land/p/samcrew/memba_weighted_policy"
    9)
    10
    11const ReadSchema = "memba-weighted-host/v2"
    12const MaxProposalPage = 50
    13
    14func (h *Host) readSchema() string {
    15 if h.feedbackPolicy != nil {
    16 return "memba-weighted-host/v12"
    17 }
    18 if h.channelsPolicy != nil {
    19 return "memba-weighted-host/v11"
    20 }
    21 if h.feedPolicy != nil {
    22 return "memba-weighted-host/v10"
    23 }
    24 if h.badgesPolicy != nil {
    25 return "memba-weighted-host/v9"
    26 }
    27 if h.escrowPolicy != nil {
    28 return "memba-weighted-host/v8"
    29 }
    30 if h.appstorePolicy != nil {
    31 return "memba-weighted-host/v7"
    32 }
    33 if h.arcadePolicy != nil {
    34 return "memba-weighted-host/v6"
    35 }
    36 if h.questPolicy != nil {
    37 return "memba-weighted-host/v5"
    38 }
    39 if h.reviewsPolicy != nil {
    40 return "memba-weighted-host/v4"
    41 }
    42 if h.marketPolicy != nil {
    43 return "memba-weighted-host/v3"
    44 }
    45 return ReadSchema
    46}
    47
    48func (h *Host) marketConfigJSON() string {
    49 if h.marketPolicy == nil {
    50 return ""
    51 }
    52 return `,"marketPolicy":{"target":` + quoteJSON(MarketConfigPath) + `,"treasury":` + quoteJSON(string(h.marketPolicy.Treasury())) + `,"successor":` + quoteJSON(string(h.marketPolicy.Successor())) + `,"feeCategory":"financial","treasuryCategory":"financial","returnStagesOnly":true,"invalidatesOtherProposals":true}`
    53}
    54
    55// JSON strings use JSON escapes, not Go's \xNN/\a/\v escapes. Invalid UTF-8
    56// decodes as U+FFFD, matching JSON's Unicode string domain.
    57func quoteJSON(value string) string {
    58 var b strings.Builder
    59 b.WriteByte('"')
    60 const hex = "0123456789abcdef"
    61 for _, r := range value {
    62 switch r {
    63 case '"':
    64 b.WriteString(`\"`)
    65 case '\\':
    66 b.WriteString(`\\`)
    67 default:
    68 if r < 0x20 {
    69 b.WriteString(`\u00`)
    70 b.WriteByte(hex[byte(r)>>4])
    71 b.WriteByte(hex[byte(r)&15])
    72 } else {
    73 b.WriteRune(r)
    74 }
    75 }
    76 }
    77 b.WriteByte('"')
    78 return b.String()
    79}
    80
    81func timestampJSON(value time.Time) string {
    82 if value.IsZero() {
    83 return "null"
    84 }
    85 return quoteJSON(value.UTC().Format(time.RFC3339Nano))
    86}
    87
    88// ConfigJSON describes only implemented host capabilities. Fixed founding
    89// thresholds are not configurable through a role action. Operational role labels
    90// have no additional vote or execution privilege.
    91func (h *Host) ConfigJSON() string {
    92 return `{"schema":` + quoteJSON(h.readSchema()) + `,"kind":"config","realmPath":` + quoteJSON(h.path) + `,"rosterSize":7,"totalPoints":8,"founderWeight":2,"developerWeight":1,"votingPeriodSeconds":604800,"roleChanges":{"category":"critical","weightedPoints":6,"weightedPeople":4,"weightedDelaySeconds":86400,"independentDevelopers":5,"independentDelaySeconds":259200},"mutableRoles":["admin","finance"],"capabilities":{"roleProposals":true,"memberReplacement":true,"migration":false,"treasuryExecution":false,"applicationActions":` + strconv.FormatBool(h.marketPolicy != nil || h.reviewsPolicy != nil || h.questPolicy != nil || h.arcadePolicy != nil || h.appstorePolicy != nil || h.escrowPolicy != nil || h.badgesPolicy != nil || h.feedPolicy != nil || h.channelsPolicy != nil || h.feedbackPolicy != nil) + `},"maxProposalPage":50` + h.marketConfigJSON() + h.reviewsConfigJSON() + h.questConfigJSON() + h.arcadeConfigJSON() + h.appstoreConfigJSON() + h.escrowConfigJSON() + h.badgesConfigJSON() + h.feedConfigJSON() + h.channelsConfigJSON() + h.feedbackConfigJSON() + `}`
    93}
    94
    95func (h *Host) MembersJSON() string {
    96 var b strings.Builder
    97 b.WriteString(`{"schema":` + quoteJSON(h.readSchema()) + `,"kind":"members","members":[`)
    98 for i, seat := range h.seats {
    99 if i > 0 {
    100 b.WriteByte(',')
    101 }
    102 weight := 1
    103 if seat.Member.Founder {
    104 weight = 2
    105 }
    106 b.WriteString(`{"personId":` + quoteJSON(seat.Member.PersonID) + `,"address":` + quoteJSON(string(seat.Member.Address)) + `,"founder":` + strconv.FormatBool(seat.Member.Founder) + `,"weight":` + strconv.Itoa(weight) + `,"admin":` + strconv.FormatBool(seat.Admin) + `,"finance":` + strconv.FormatBool(seat.Finance) + `}`)
    107 }
    108 b.WriteString(`]}`)
    109 return b.String()
    110}
    111
    112func status(s memba_weighted_policy.State) string {
    113 // Successful role execution also advances the configuration generation.
    114 // Consumed therefore takes precedence over subsequent invalidation.
    115 if s.Consumed {
    116 return "EXECUTED"
    117 }
    118 if s.Invalidated {
    119 return "INVALIDATED"
    120 }
    121 if s.Expired {
    122 return "EXPIRED"
    123 }
    124 if s.Ready {
    125 return "READY"
    126 }
    127 if s.Qualified {
    128 return "TIMELOCKED"
    129 }
    130 return "VOTING"
    131}
    132
    133// viewStatus keeps EXPIRED sticky: a proposal whose voting closed without
    134// qualifying reports EXPIRED even after a later reconfiguration.
    135func viewStatus(v ProposalView) string {
    136 if !v.State.Consumed && v.ExpiredBeforeInvalidation {
    137 return "EXPIRED"
    138 }
    139 return status(v.State)
    140}
    141
    142// invalidationJSON is null unless the status is INVALIDATED. cause is
    143// "superseded-execution" (proposalId is the executed proposal) or "pause"
    144// (proposalId is null). target is the application realm, or null for a
    145// role or recovery execution.
    146func invalidationJSON(v ProposalView) string {
    147 if !v.Invalidated {
    148 return "null"
    149 }
    150 id, target := "null", "null"
    151 if v.InvalidationProposal != 0 {
    152 id = quoteJSON(strconv.FormatUint(v.InvalidationProposal, 10))
    153 }
    154 if v.InvalidationTarget != "" {
    155 target = quoteJSON(v.InvalidationTarget)
    156 }
    157 return `{"cause":` + quoteJSON(v.InvalidationCause) + `,"height":` + quoteJSON(strconv.FormatInt(v.InvalidationHeight, 10)) + `,"proposalId":` + id + `,"target":` + target + `}`
    158}
    159
    160// Terminal policy states clear current tallies; they are not evidence of zero
    161// historical votes. Do not invent a receipt the host did not retain.
    162func tallyJSON(n int, s memba_weighted_policy.State) string {
    163 if s.Consumed || s.Invalidated {
    164 return "null"
    165 }
    166 return strconv.Itoa(n)
    167}
    168
    169func proposalActionJSON(v ProposalView) string {
    170 if v.Feedback {
    171 return feedbackActionJSON(v.FeedbackAction, v.FeedbackBefore)
    172 }
    173 if v.Channels {
    174 return channelsActionJSON(v.ChannelsAction, v.ChannelsBefore)
    175 }
    176 if v.Feed {
    177 return feedActionJSON(v.FeedAction, v.FeedBefore)
    178 }
    179 if v.Badges {
    180 return badgesActionJSON(v.BadgesAction, v.BadgesBefore)
    181 }
    182 if v.Escrow {
    183 return escrowActionJSON(v.EscrowAction, v.EscrowBefore)
    184 }
    185 if v.Appstore {
    186 return appstoreActionJSON(v.AppstoreAction, v.AppstoreBefore)
    187 }
    188 if v.Arcade {
    189 return arcadeActionJSON(v.ArcadeAction, v.ArcadeBefore)
    190 }
    191 if v.Quest {
    192 return questActionJSON(v.QuestAction, v.QuestBefore)
    193 }
    194 if v.Reviews {
    195 return reviewsActionJSON(v.ReviewsAction, v.ReviewsBefore)
    196 }
    197 if v.Market {
    198 a := v.MarketAction
    199 b := v.MarketBefore
    200 return `{"type":"market-config","target":` + quoteJSON(MarketConfigPath) + `,"operation":` + quoteJSON(string(a.Kind())) + `,"lane":` + quoteJSON(string(a.Lane())) + `,"bps":` + quoteJSON(strconv.FormatInt(a.BPS(), 10)) + `,"recipient":` + quoteJSON(string(a.Recipient())) + `,"before":{"admin":` + quoteJSON(string(b.Admin)) + `,"pendingAdmin":` + quoteJSON(string(b.PendingAdmin)) + `,"treasury":` + quoteJSON(string(b.Treasury)) + `,"bps":` + quoteJSON(strconv.FormatInt(b.BPS, 10)) + `}}`
    201 }
    202 if v.Recovery {
    203 return `{"type":"recover-member","personId":` + quoteJSON(v.PersonID) + `,"oldAddress":` + quoteJSON(string(v.Target)) + `,"newAddress":` + quoteJSON(string(v.Replacement)) + `}`
    204 }
    205 return `{"type":"set-role","target":` + quoteJSON(string(v.Target)) + `,"role":` + quoteJSON(string(v.Role)) + `,"grant":` + strconv.FormatBool(v.Grant) + `}`
    206}
    207
    208func proposalJSON(v ProposalView) string {
    209 s := v.State
    210 return `{"id":` + quoteJSON(strconv.FormatUint(v.ID, 10)) + `,"proposer":` + quoteJSON(string(v.Proposer)) + `,"action":` + proposalActionJSON(v) + `,"category":` + quoteJSON(string(s.Category)) + `,"status":` + quoteJSON(viewStatus(v)) + `,"qualified":` + strconv.FormatBool(s.Qualified) + `,"ready":` + strconv.FormatBool(s.Ready) + `,"votingClosed":` + strconv.FormatBool(s.VotingClosed) + `,"talliesAvailable":` + strconv.FormatBool(!s.Consumed && !s.Invalidated) + `,"weightYes":` + tallyJSON(s.WeightYes, s) + `,"peopleYes":` + tallyJSON(s.PeopleYes, s) + `,"developersYes":` + tallyJSON(s.DevelopersYes, s) + `,"createdAt":` + timestampJSON(s.CreatedAt) + `,"votingDeadline":` + timestampJSON(s.VotingDeadline) + `,"weightedAfter":` + timestampJSON(s.WeightedAfter) + `,"developerAfter":` + timestampJSON(s.DeveloperAfter) + `,"invalidation":` + invalidationJSON(v) + `}`
    211}
    212
    213func (h *Host) ProposalJSON(id uint64) string {
    214 return `{"schema":` + quoteJSON(h.readSchema()) + `,"kind":"proposal","proposal":` + proposalJSON(h.Proposal(id)) + `}`
    215}
    216
    217// ProposalsJSON uses an exclusive descending ID cursor. before=0 means newest;
    218// a returned nextBefore remains stable when newer proposals are appended.
    219// IDs/cursors/counts are decimal strings so uint64 values never lose precision
    220// in a JavaScript client. A null cursor ends pagination, not an empty page guess.
    221func (h *Host) ProposalsJSON(before uint64, limit int) string {
    222 if limit < 1 || limit > MaxProposalPage {
    223 panic("invalid proposal page size")
    224 }
    225 count := h.ProposalCount()
    226 if before > count {
    227 panic("invalid proposal cursor")
    228 }
    229 id := count
    230 if before > 0 {
    231 id = before - 1
    232 }
    233 var b strings.Builder
    234 b.WriteString(`{"schema":` + quoteJSON(h.readSchema()) + `,"kind":"proposals","total":` + quoteJSON(strconv.FormatUint(count, 10)) + `,"proposals":[`)
    235 n := 0
    236 last := uint64(0)
    237 for id > 0 && n < limit {
    238 if n > 0 {
    239 b.WriteByte(',')
    240 }
    241 b.WriteString(proposalJSON(h.Proposal(id)))
    242 last = id
    243 id--
    244 n++
    245 }
    246 b.WriteString(`],"nextBefore":`)
    247 if id > 0 {
    248 b.WriteString(quoteJSON(strconv.FormatUint(last, 10)))
    249 } else {
    250 b.WriteString("null")
    251 }
    252 b.WriteByte('}')
    253 return b.String()
    254}
    255
    256// Ballot reads. Pending pages hold at most MaxPendingPage proposals, and one
    257// call examines at most MaxPendingScan proposals before handing back a cursor.
    258const MaxPendingPage = 50
    259const MaxPendingScan = 200
    260
    261// parseDecimalID accepts only canonical unsigned decimal strings, the same
    262// form every read emits, so one ID has exactly one spelling.
    263func parseDecimalID(value, what string) uint64 {
    264 n, err := strconv.ParseUint(value, 10, 64)
    265 if err != nil || strconv.FormatUint(n, 10) != value {
    266 panic("invalid " + what)
    267 }
    268 return n
    269}
    270
    271func ballotChoiceJSON(v memba_weighted_policy.Vote) string {
    272 if v == "" {
    273 return "null"
    274 }
    275 return quoteJSON(string(v))
    276}
    277
    278// BallotJSON reports one address's ballot on one proposal. Eligibility is the
    279// electorate frozen when the proposal was created, so a recovered key keeps
    280// its ballot on older proposals and has none on newer ones. choice is "yes",
    281// "no" or "abstain" (the host's three ballot values), or null with a null
    282// votedAtHeight when the address has not voted. Ballots stay readable after a
    283// proposal is executed, invalidated or expired; tallies do not.
    284func (h *Host) BallotJSON(proposalID string, voter address) string {
    285 id := parseDecimalID(proposalID, "proposal id")
    286 p := h.proposal(id)
    287 i := rosterIndex(h.rosters[p.roster], voter)
    288 choice, height := "null", "null"
    289 if i >= 0 && p.choices[i] != "" {
    290 choice = ballotChoiceJSON(p.choices[i])
    291 height = quoteJSON(strconv.FormatInt(p.votedAt[i], 10))
    292 }
    293 return `{"schema":` + quoteJSON(h.readSchema()) + `,"proposalId":` + quoteJSON(strconv.FormatUint(id, 10)) + `,"voter":` + quoteJSON(string(voter)) + `,"eligible":` + strconv.FormatBool(i >= 0) + `,"choice":` + choice + `,"votedAtHeight":` + height + `}`
    294}
    295
    296// PendingVotesJSON lists, newest first, the proposals that are still open for
    297// voting where voter is in the frozen electorate and has not voted. before is
    298// an exclusive decimal cursor ("" or "0" for newest); limit is clamped to
    299// 1..MaxPendingPage. Executing any action invalidates every older open
    300// proposal, and deadlines follow creation order, so the scan stops at the first
    301// proposal that no longer accepts votes: nothing older can be pending. The
    302// scan also stops after MaxPendingScan proposals; next then resumes it. next
    303// is null when nothing older can be pending.
    304func (h *Host) PendingVotesJSON(voter address, before string, limit int) string {
    305 if limit < 1 {
    306 limit = 1
    307 }
    308 if limit > MaxPendingPage {
    309 limit = MaxPendingPage
    310 }
    311 count := h.ProposalCount()
    312 id := count
    313 if before != "" && before != "0" {
    314 cursor := parseDecimalID(before, "proposal cursor")
    315 if cursor > count {
    316 panic("invalid proposal cursor")
    317 }
    318 id = cursor - 1
    319 }
    320 var b strings.Builder
    321 b.WriteString(`{"schema":` + quoteJSON(h.readSchema()) + `,"voter":` + quoteJSON(string(voter)) + `,"items":[`)
    322 n, scanned, closed := 0, 0, false
    323 for id > 0 && n < limit && scanned < MaxPendingScan {
    324 p := h.proposals[id-1]
    325 s := p.ballot.State()
    326 if s.Consumed || s.Invalidated || s.VotingClosed {
    327 closed = true
    328 break
    329 }
    330 scanned++
    331 i := rosterIndex(h.rosters[p.roster], voter)
    332 if i >= 0 && p.choices[i] == "" {
    333 if n > 0 {
    334 b.WriteByte(',')
    335 }
    336 b.WriteString(proposalJSON(h.Proposal(id)))
    337 n++
    338 }
    339 id--
    340 }
    341 b.WriteString(`],"next":`)
    342 if closed || id == 0 {
    343 b.WriteString("null")
    344 } else {
    345 b.WriteString(quoteJSON(strconv.FormatUint(id+1, 10)))
    346 }
    347 b.WriteByte('}')
    348 return b.String()
    349}
    350