1// Package grants is a grant board governed by a member set: anyone may ask2// the board for money, the members vote in the open, and the money leaves in3// tranches that each have to be earned by producing a proof the members4// accept.5//6// The package is pure. It holds no coins, reads no chain state and imports7// nothing from `chain`: the caller supplies the acting address and the block
Functions
not supported for pure packages by the node (vm/qfuncs)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
8// height, and the caller performs the transfer. That is what makes the whole
9// state machine unit-testable without a node, and it is what lets the same
10// board be driven by a realm, by a test, or by a different payment rail.
11// Live board: gno.land/r/moul/grant/v0.
12//
13// # The shape of a grant
14//
15// A Request is a title, a body, and an ordered list of Milestones, each with
16// its own amount. Approving a request does not pay anything: it only makes the
17// first milestone claimable. To get a tranche the applicant submits a Proof
18// (a URL, a hash, or plain text) and the members review that specific proof.
19// A rejected proof does not kill the grant, it just closes one Attempt; the
20// applicant submits another. Every attempt, accepted or not, stays on the
21// record with the ballots that decided it.
22//
23// # Asking for someone else
24//
25// A request has an applicant, who files it and answers for it, and a
26// beneficiary, who gets paid. SubmitFor separates the two and takes a reason
27// for the detour; Submit is the common case where they are the same address.
28//
29// The split is not a convenience. An account with nothing in it cannot pay the
30// gas to ask for its first coins, so on a board whose whole purpose is to fund
31// empty accounts, "someone else files it" is the ONLY path that works. Both
32// addresses are then barred from voting on the request, and either of them may
33// submit a proof, for the same reason: the payee may not be able to transact
34// at all until the first tranche lands.
35//
36// # Who may vote
37//
38// Every member, once, per decision. The party the decision is about is
39// excluded: the applicant does not vote on their own grant, and the subject of
40// a membership change does not vote on their own membership. The bar is a
41// majority of the addresses that are actually eligible, recomputed on each
42// ballot, so a board that grows mid-vote raises its own bar.
43//
44// # What this deliberately does not do
45//
46// No weights, no delegation, no quadratic anything, no deadline. A request
47// with no majority either way simply stays Pending until someone breaks the
48// tie or the applicant withdraws it. Those are all reasonable things to add on
49// top; none of them is needed to show the shape.
50package grants
51
52import (
53"errors"
54"strconv"
55
56"gno.land/p/nt/avl/v0"
57)
58
59// Errors returned by the mutators. They are sentinels so a realm can map them
60// onto its own messages, or simply panic with them.
61var (
62 ErrNotMember = errors.New("grants: not a board member")
63 ErrNotApplicant = errors.New("grants: only the applicant may do this")
64 ErrNoRequest = errors.New("grants: no such request")
65 ErrNoMilestone = errors.New("grants: no such milestone")
66 ErrNotPending = errors.New("grants: the request is not pending")
67 ErrNotApproved = errors.New("grants: the request is not approved")
68 ErrAlreadyVoted = errors.New("grants: this member already voted")
69 ErrConflict = errors.New("grants: the party a decision is about may not vote on it")
70 ErrOutOfOrder = errors.New("grants: milestones are claimed in order")
71 ErrProofPending = errors.New("grants: a proof is already under review")
72 ErrNoProof = errors.New("grants: no proof is under review")
73 ErrBadTitle = errors.New("grants: title must be 1 to 100 characters")
74 ErrBadBody = errors.New("grants: body must be at most 2000 characters")
75 ErrBadMilestones = errors.New("grants: a grant needs 1 to 10 milestones")
76 ErrBadAmount = errors.New("grants: every milestone must ask for a positive amount")
77 ErrBadProof = errors.New("grants: proof kind must be url, hash or text, with a reference")
78 ErrBadReason = errors.New("grants: reason must be at most 300 characters")
79 ErrNeedReason = errors.New("grants: filing for someone else needs a reason")