diff --git a/examples/gno.land/r/matijamarjanovic/tokenhub/gno.mod b/examples/gno.land/r/matijamarjanovic/tokenhub/gno.mod new file mode 100644 index 00000000000..19deb1b830d --- /dev/null +++ b/examples/gno.land/r/matijamarjanovic/tokenhub/gno.mod @@ -0,0 +1 @@ +module gno.land/r/matijamarjanovic/tokenhub diff --git a/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno b/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno new file mode 100644 index 00000000000..6ab2812e520 --- /dev/null +++ b/examples/gno.land/r/matijamarjanovic/tokenhub/test.gno @@ -0,0 +1,54 @@ +package tokenhub + +import ( + "std" + + "gno.land/p/demo/grc/grc20" +) + +var ( + tokenA *grc20.Token + tokenB *grc20.Token + tokenC *grc20.Token + tokenD *grc20.Token + tokenE *grc20.Token +) + +func init() { + tokenA = grc20.NewToken("Token A", "TKNA", 6) + tokenB = grc20.NewToken("Token B", "TKNB", 6) + tokenC = grc20.NewToken("Token C", "TKNC", 6) + tokenD = grc20.NewToken("Token D", "TKND", 6) + tokenE = grc20.NewToken("Token E", "TKNE", 6) + + Send5OfEach("g1ej0qca5ptsw9kfr64ey8jvfy9eacga6mpj2z0y") + RegisterToken(tokenA) + RegisterToken(tokenB) + RegisterToken(tokenC) + RegisterToken(tokenD) + RegisterToken(tokenE) +} + +func Send5OfEach(to std.Address) error { + if !to.IsValid() { + return grc20.ErrInvalidAddress + } + + if err := adminA.Mint(to, 5); err != nil { + return err + } + if err := adminB.Mint(to, 5); err != nil { + return err + } + if err := adminC.Mint(to, 5); err != nil { + return err + } + if err := adminD.Mint(to, 5); err != nil { + return err + } + if err := adminE.Mint(to, 5); err != nil { + return err + } + + return nil +} diff --git a/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno b/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno new file mode 100644 index 00000000000..c5264378600 --- /dev/null +++ b/examples/gno.land/r/matijamarjanovic/tokenhub/tokenhub.gno @@ -0,0 +1,83 @@ +package tokenhub + +import ( + "std" + "errors" + "strings" + "gno.land/p/demo/avl" + "gno.land/p/demo/grc/grc20" + "gno.land/p/moul/md" + "gno.land/p/demo/ufmt" +) + +var ( + registeredTokens = avl.NewTree() // symbol -> *grc20.Token + + ErrTokenAlreadyRegistered = errors.New("token already registered") + ErrTokenNotFound = errors.New("token not found") +) + +func RegisterToken(token *grc20.Token) error { + symbol := token.GetSymbol() + + if registeredTokens.Has(symbol) { + return ErrTokenAlreadyRegistered + } + + registeredTokens.Set(symbol, token) + return nil +} + +func getBalances(addr std.Address) string { + balances := avl.NewTree() + var sb strings.Builder + + registeredTokens.Iterate("", "", func(key string, value interface{}) bool { + token := value.(*grc20.Token) + balance := token.BalanceOf(addr) + balances.Set(key, balance) + return false + }) + + sb.WriteString("Balances: ") + balances.Iterate("", "", func(key string, value interface{}) bool { + balance := value.(uint64) + sb.WriteString(ufmt.Sprintf("%s: %d ", key, balance)) + return false + }) + + return sb.String() +} + +func GetMyBalances() string { + return getBalances(std.GetOrigCaller()) +} + +func Render(path string) string { + var sb strings.Builder + + sb.WriteString(md.H1("TokenHub")) + sb.WriteString(md.Paragraph("A central registry for GRC20 tokens on gno.land")) + + sb.WriteString(md.H2("Registered Tokens")) + + var tokenItems []string + registeredTokens.Iterate("", "", func(key string, value interface{}) bool { + token := value.(*grc20.Token) + tokenItems = append(tokenItems, ufmt.Sprintf("%s (%s) - %d decimals", + token.GetName(), + token.GetSymbol(), + token.GetDecimals())) + return false + }) + + if len(tokenItems) > 0 { + sb.WriteString(md.BulletList(tokenItems)) + } else { + sb.WriteString(md.Italic("No tokens registered yet")) + sb.WriteString("\n") + } + + return sb.String() +} +