Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

views.gno

5.13 Kb · 188 lines
  1package bolo
  2
  3import "chain/banker"
  4
  5// CampaignView is a campaign as clients see it (API §2.4): a copy, holding nothing
  6// of the realm's state, its derived fields computed at now without writing.
  7type CampaignView struct {
  8	ID, Title, Description, Category, ImageCID, ImageAlt string
  9	ImageHidden                                          bool
 10	Organizer, Beneficiary                               address
 11	Mode, Status, CloseReason                            string
 12	Listed                                               bool
 13	Notice                                               string
 14
 15	Goal      int64
 16	Raised    int64
 17	Refunded  int64
 18	Withdrawn int64
 19	NetRaised int64
 20	Balance   int64
 21	Untracked int64
 22
 23	DonorCount, DonationCount, RefundCount, UpdateCount int
 24
 25	Deposit          int64
 26	Bond             int64
 27	BondSlashed      bool
 28	BondReleasableAt int64
 29
 30	CreatedAt, Deadline, ClosedAt, LastDonationAt, LastUpdateAt int64
 31
 32	ClosableByAnyoneAt int64
 33	ExitOpensAt        int64
 34	FinalizableAt      int64
 35
 36	EverWithdrawn bool
 37	ExitOpen      bool
 38
 39	EscrowAddress address
 40	BondAddress   address
 41	Params        Params
 42}
 43
 44// GetCampaign returns campaign id's view (API §4). An unknown or non-canonical ID is
 45// ErrNotFound (C9).
 46func GetCampaign(id string) CampaignView {
 47	return campaignView(campaignOf(id))
 48}
 49
 50// campaignOf returns the campaign id names, or panics with ErrNotFound (C9).
 51func campaignOf(id string) *campaign {
 52	c, ok := lookup(id)
 53	if !ok {
 54		panic(ErrNotFound)
 55	}
 56	return c
 57}
 58
 59// lookup returns the campaign id names, if id is canonical and the campaign exists.
 60func lookup(id string) (*campaign, bool) {
 61	n, ok := parseID(id)
 62	if !ok {
 63		return nil, false
 64	}
 65	v := campaigns.Get(n.Binary())
 66	if v == nil {
 67		return nil, false
 68	}
 69	return v.(*campaign), true
 70}
 71
 72// effective returns c's status, close reason and close time at now, counting a
 73// passed deadline as recorded (API §2.4, §3.1), without writing.
 74func effective(c *campaign) (status, reason string, closedAt int64) {
 75	s := c.state
 76	if s.status == statusOpen && c.deadline != 0 && now() >= c.deadline {
 77		return statusClosed, reasonDeadline, c.deadline
 78	}
 79	return s.status, s.closeReason, s.closedAt
 80}
 81
 82// trackedBalance is what the books say the escrow holds (API §2.4): 0 in direct
 83// mode.
 84func trackedBalance(c *campaign) int64 {
 85	if c.mode != modeEscrow {
 86		return 0
 87	}
 88	s := c.state
 89	return s.raised - s.withdrawn - s.refunded
 90}
 91
 92// campaignView builds c's view at now (API §2.4).
 93func campaignView(c *campaign) CampaignView {
 94	s, p := c.state, c.params
 95	status, reason, closedAt := effective(c)
 96	balance := trackedBalance(c)
 97	untracked := banker.NewReadonlyBanker().GetCoin(escrowAddr(c.id), "ugnot") - balance
 98	if untracked < 0 {
 99		untracked = 0
100	}
101	v := CampaignView{
102		ID:          idString(c.id),
103		Title:       c.text.title,
104		Description: c.text.description,
105		Category:    c.category,
106		ImageCID:    c.text.imageCID,
107		ImageAlt:    c.text.imageAlt,
108		ImageHidden: s.imageHidden,
109		Organizer:   c.organizer,
110		Beneficiary: c.beneficiary,
111		Mode:        c.mode,
112		Status:      status,
113		CloseReason: reason,
114		Listed:      s.listed,
115		Notice:      s.notice,
116
117		Goal:      c.goal,
118		Raised:    s.raised,
119		Refunded:  s.refunded,
120		Withdrawn: s.withdrawn,
121		NetRaised: s.raised - s.refunded,
122		Balance:   balance,
123		Untracked: untracked,
124
125		DonorCount:    s.donorCount,
126		DonationCount: s.donationCount,
127		RefundCount:   s.refundCount,
128		UpdateCount:   s.updateCount,
129
130		Deposit:     p.CreationDeposit,
131		Bond:        s.bond,
132		BondSlashed: s.bondSlashed,
133
134		CreatedAt:      c.createdAt,
135		Deadline:       c.deadline,
136		ClosedAt:       closedAt,
137		LastDonationAt: s.lastDonationAt,
138		LastUpdateAt:   s.lastUpdateAt,
139
140		EverWithdrawn: s.everWithdrawn,
141		EscrowAddress: escrowAddr(c.id),
142		BondAddress:   bondAddr(c.id),
143		Params:        p,
144	}
145	switch status {
146	case statusOpen:
147		v.ClosableByAnyoneAt = dormantAt(c)
148		if c.deadline != 0 {
149			v.FinalizableAt = finalizableAt(c, c.deadline, balance)
150		}
151	case statusClosed:
152		v.BondReleasableAt = closedAt + p.BondHold
153		v.FinalizableAt = finalizableAt(c, closedAt, balance)
154	case statusSettled:
155		v.BondReleasableAt = closedAt + p.BondHold
156	}
157	if c.mode == modeEscrow && status != statusOpen {
158		v.ExitOpensAt = closedAt + p.ExitDelay
159		v.ExitOpen = s.everWithdrawn && balance > 0 && now() >= v.ExitOpensAt
160	}
161	return v
162}
163
164// dormantAt is when anyone may close c for dormancy: its last activity plus its
165// snapshot's dormancy period (API §3.1).
166func dormantAt(c *campaign) int64 { return lastActivity(c) + c.params.DormancyPeriod }
167
168// lastActivity is the latest of c's creation, its last gift and its last update:
169// dormancy counts from it (API §3.1).
170func lastActivity(c *campaign) int64 {
171	last := c.createdAt
172	if c.state.lastDonationAt > last {
173		last = c.state.lastDonationAt
174	}
175	if c.state.lastUpdateAt > last {
176		last = c.state.lastUpdateAt
177	}
178	return last
179}
180
181// finalizableAt is when Finalize first succeeds for c closed at closedAt (API §2.4,
182// §3.4): at once in direct mode or with nothing tracked, else once the exit opens.
183func finalizableAt(c *campaign, closedAt, balance int64) int64 {
184	if c.mode == modeDirect || balance == 0 {
185		return closedAt
186	}
187	return closedAt + c.params.ExitDelay
188}