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}