grc20factory.gno
4.05 Kb ยท 167 lines
1package foo20
2
3import (
4 "std"
5 "strings"
6
7 "gno.land/p/demo/avl"
8 "gno.land/p/demo/grc/grc20"
9 "gno.land/p/demo/ownable"
10 "gno.land/p/demo/ufmt"
11 "gno.land/r/demo/grc20reg"
12)
13
14var instances avl.Tree // symbol -> instance
15
16type instance struct {
17 token *grc20.Token
18 ledger *grc20.PrivateLedger
19 admin *ownable.Ownable
20 faucet uint64 // per-request amount. disabled if 0.
21}
22
23func New(name, symbol string, decimals uint, initialMint, faucet uint64) {
24 caller := std.PreviousRealm().Address()
25 NewWithAdmin(name, symbol, decimals, initialMint, faucet, caller)
26}
27
28func NewWithAdmin(name, symbol string, decimals uint, initialMint, faucet uint64, admin std.Address) {
29 exists := instances.Has(symbol)
30 if exists {
31 panic("token already exists")
32 }
33
34 token, ledger := grc20.NewToken(name, symbol, decimals)
35 if initialMint > 0 {
36 ledger.Mint(admin, initialMint)
37 }
38
39 inst := instance{
40 token: token,
41 ledger: ledger,
42 admin: ownable.NewWithAddress(admin),
43 faucet: faucet,
44 }
45 instances.Set(symbol, &inst)
46 grc20reg.Register(token.Getter(), symbol)
47}
48
49func (inst instance) Token() *grc20.Token {
50 return inst.token
51}
52
53func (inst instance) CallerTeller() grc20.Teller {
54 return inst.token.CallerTeller()
55}
56
57func Bank(symbol string) *grc20.Token {
58 inst := mustGetInstance(symbol)
59 return inst.token
60}
61
62func TotalSupply(symbol string) uint64 {
63 inst := mustGetInstance(symbol)
64 return inst.token.ReadonlyTeller().TotalSupply()
65}
66
67func BalanceOf(symbol string, owner std.Address) uint64 {
68 inst := mustGetInstance(symbol)
69 return inst.token.ReadonlyTeller().BalanceOf(owner)
70}
71
72func Allowance(symbol string, owner, spender std.Address) uint64 {
73 inst := mustGetInstance(symbol)
74 return inst.token.ReadonlyTeller().Allowance(owner, spender)
75}
76
77func Transfer(symbol string, to std.Address, amount uint64) {
78 inst := mustGetInstance(symbol)
79 caller := std.PreviousRealm().Address()
80 teller := inst.ledger.ImpersonateTeller(caller)
81 checkErr(teller.Transfer(to, amount))
82}
83
84func Approve(symbol string, spender std.Address, amount uint64) {
85 inst := mustGetInstance(symbol)
86 caller := std.PreviousRealm().Address()
87 teller := inst.ledger.ImpersonateTeller(caller)
88 checkErr(teller.Approve(spender, amount))
89}
90
91func TransferFrom(symbol string, from, to std.Address, amount uint64) {
92 inst := mustGetInstance(symbol)
93 caller := std.PreviousRealm().Address()
94 teller := inst.ledger.ImpersonateTeller(caller)
95 checkErr(teller.TransferFrom(from, to, amount))
96}
97
98// faucet.
99func Faucet(symbol string) {
100 inst := mustGetInstance(symbol)
101 if inst.faucet == 0 {
102 panic("faucet disabled for this token")
103 }
104 // FIXME: add limits?
105 // FIXME: add payment in gnot?
106 caller := std.PreviousRealm().Address()
107 checkErr(inst.ledger.Mint(caller, inst.faucet))
108}
109
110func Mint(symbol string, to std.Address, amount uint64) {
111 inst := mustGetInstance(symbol)
112 inst.admin.AssertCallerIsOwner()
113 checkErr(inst.ledger.Mint(to, amount))
114}
115
116func Burn(symbol string, from std.Address, amount uint64) {
117 inst := mustGetInstance(symbol)
118 inst.admin.AssertCallerIsOwner()
119 checkErr(inst.ledger.Burn(from, amount))
120}
121
122// instance admin functionality
123func DropInstanceOwnership(symbol string) {
124 inst := mustGetInstance(symbol)
125 checkErr(inst.admin.DropOwnership())
126}
127
128func TransferInstanceOwnership(symbol string, newOwner std.Address) {
129 inst := mustGetInstance(symbol)
130 checkErr(inst.admin.TransferOwnership(newOwner))
131}
132
133func Render(path string) string {
134 parts := strings.Split(path, "/")
135 c := len(parts)
136
137 switch {
138 case path == "":
139 return "TODO: list existing tokens and admins"
140 case c == 1:
141 symbol := parts[0]
142 inst := mustGetInstance(symbol)
143 return inst.token.RenderHome()
144 case c == 3 && parts[1] == "balance":
145 symbol := parts[0]
146 inst := mustGetInstance(symbol)
147 owner := std.Address(parts[2])
148 balance := inst.token.CallerTeller().BalanceOf(owner)
149 return ufmt.Sprintf("%d", balance)
150 default:
151 return "404\n"
152 }
153}
154
155func mustGetInstance(symbol string) *instance {
156 t, exists := instances.Get(symbol)
157 if !exists {
158 panic("token instance does not exist")
159 }
160 return t.(*instance)
161}
162
163func checkErr(err error) {
164 if err != nil {
165 panic(err.Error())
166 }
167}