appstore_actions.gno
4.87 Kb · 136 lines
1package memba_weighted_host
2
3import (
4 "chain"
5 "gno.land/p/samcrew/memba_weighted_policy"
6 "strconv"
7 "strings"
8)
9
10const AppstorePath = "gno.land/r/samcrew/memba_appstore_v3"
11const AppstoreMaxFee = int64(100000000)
12
13type AppstoreKind string
14
15const (
16 AppstoreAccept AppstoreKind = "accept-owner"
17 AppstoreReturn AppstoreKind = "return-owner"
18 AppstoreAbortReturn AppstoreKind = "abort-return"
19 AppstoreAddCurator AppstoreKind = "add-curator"
20 AppstoreRemoveCurator AppstoreKind = "remove-curator"
21 AppstoreFee AppstoreKind = "set-fee"
22 AppstoreTreasury AppstoreKind = "set-treasury"
23 AppstoreUnpause AppstoreKind = "unpause"
24 AppstoreSeal AppstoreKind = "seal-import"
25 AppstoreApprove AppstoreKind = "approve"
26 AppstoreReject AppstoreKind = "reject"
27 AppstoreDelist AppstoreKind = "delist"
28 AppstoreRestore AppstoreKind = "restore"
29 AppstoreClearFlags AppstoreKind = "clear-flags"
30)
31
32type AppstorePolicy struct{ dao, successor, treasury address }
33
34func NewAppstorePolicy(dao, successor, treasury address) AppstorePolicy {
35 if dao != chain.PackageAddress("gno.land/r/samcrew/memba_dao") {
36 panic("appstore policy requires the founding DAO address")
37 }
38 for _, a := range []address{successor, treasury} {
39 if !a.IsValid() || a == dao || a == chain.PackageAddress(AppstorePath) {
40 panic("appstore destination must be valid and distinct from DAO and target")
41 }
42 }
43 return AppstorePolicy{dao, successor, treasury}
44}
45func (p AppstorePolicy) DAO() address { return p.dao }
46func (p AppstorePolicy) Successor() address { return p.successor }
47func (p AppstorePolicy) Treasury() address { return p.treasury }
48
49type AppstoreAction struct {
50 kind AppstoreKind
51 recipient address
52 fee int64
53 path, reason string
54}
55
56func (p AppstorePolicy) Accept() AppstoreAction { return AppstoreAction{kind: AppstoreAccept} }
57func (p AppstorePolicy) Return() AppstoreAction {
58 return AppstoreAction{kind: AppstoreReturn, recipient: p.successor}
59}
60func (p AppstorePolicy) AbortReturn() AppstoreAction {
61 return AppstoreAction{kind: AppstoreAbortReturn, recipient: p.successor}
62}
63func (p AppstorePolicy) SetTreasury() AppstoreAction {
64 return AppstoreAction{kind: AppstoreTreasury, recipient: p.treasury}
65}
66func AppstoreCurator(who address, grant bool) AppstoreAction {
67 k := AppstoreRemoveCurator
68 if grant {
69 k = AppstoreAddCurator
70 }
71 a := AppstoreAction{kind: k, recipient: who}
72 a.Bytes()
73 return a
74}
75func AppstoreRegistrationFee(fee int64) AppstoreAction {
76 a := AppstoreAction{kind: AppstoreFee, fee: fee}
77 a.Bytes()
78 return a
79}
80func AppstoreResume() AppstoreAction { return AppstoreAction{kind: AppstoreUnpause} }
81func AppstoreSealImport() AppstoreAction { return AppstoreAction{kind: AppstoreSeal} }
82func AppstoreModeration(kind AppstoreKind, path, reason string) AppstoreAction {
83 a := AppstoreAction{kind: kind, path: path, reason: reason}
84 if !a.IsListing() {
85 panic("unsupported appstore moderation")
86 }
87 a.Bytes()
88 return a
89}
90func (a AppstoreAction) Kind() AppstoreKind { return a.kind }
91func (a AppstoreAction) Recipient() address { return a.recipient }
92func (a AppstoreAction) Fee() int64 { return a.fee }
93func (a AppstoreAction) Path() string { return a.path }
94func (a AppstoreAction) Reason() string { return a.reason }
95func (a AppstoreAction) IsListing() bool {
96 return a.kind == AppstoreApprove || a.kind == AppstoreReject || a.kind == AppstoreDelist || a.kind == AppstoreRestore || a.kind == AppstoreClearFlags
97}
98func (a AppstoreAction) Bytes() string {
99 if a.IsListing() {
100 if a.recipient != "" || a.fee != 0 || len(a.path) > 200 || !(strings.HasPrefix(a.path, "gno.land/r/") || strings.HasPrefix(a.path, "gno.land/p/")) || len(a.reason) > 500 || (a.kind != AppstoreReject && a.reason != "") {
101 panic("invalid appstore moderation")
102 }
103 } else {
104 if a.path != "" || a.reason != "" {
105 panic("malformed appstore action")
106 }
107 switch a.kind {
108 case AppstoreAccept, AppstoreUnpause, AppstoreSeal:
109 if a.recipient != "" || a.fee != 0 {
110 panic("malformed appstore action")
111 }
112 case AppstoreReturn, AppstoreAbortReturn, AppstoreTreasury, AppstoreAddCurator, AppstoreRemoveCurator:
113 if !a.recipient.IsValid() || a.fee != 0 {
114 panic("invalid appstore recipient")
115 }
116 case AppstoreFee:
117 if a.recipient != "" || a.fee < 0 || a.fee > AppstoreMaxFee {
118 panic("invalid appstore fee")
119 }
120 default:
121 panic("unsupported appstore action")
122 }
123 }
124 return "appstore/v1|" + AppstorePath + "|" + quoteJSON(string(a.kind)) + "|" + quoteJSON(string(a.recipient)) + "|" + strconv.FormatInt(a.fee, 10) + "|" + quoteJSON(a.path) + "|" + quoteJSON(a.reason)
125}
126func (a AppstoreAction) Category() memba_weighted_policy.Category {
127 a.Bytes()
128 if a.IsListing() {
129 return memba_weighted_policy.Routine
130 }
131 switch a.kind {
132 case AppstoreFee, AppstoreTreasury, AppstoreUnpause:
133 return memba_weighted_policy.Financial
134 }
135 return memba_weighted_policy.Critical
136}