Skip to content

Commit d2b0abe

Browse files
authoredFeb 26, 2025··
chore: move LCS from hackerspace (#71)
1 parent 0f0e381 commit d2b0abe

File tree

22 files changed

+706
-0
lines changed

22 files changed

+706
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Gno Live Coding Session #1
2+
3+
#### Topic: Minimal Constant Product GRC20 AMM in Gno
4+
#### Date: Friday, Aug 16th 2024
5+
#### Presenter: [@leohhhn](https://github.com/leohhhn)
6+
7+
This live coding session was the first Gno Live coding session.
8+
It included building a basic [`GRC20`](https://gno.land/p/demo/grc/grc20) DEX
9+
in Gno with the [constant product AMM](https://medium.com/@solidity101/the-constant-product-automated-market-maker-amm-294976dbb657)
10+
algorithm. The base implementation only handles two GRC20 tokens:
11+
[`wugnot`](https://gno.land/r/demo/wugnot) & [`foo20`](https://gno.land/r/demo/foo20).
12+
13+
## Following up
14+
15+
We encourage anyone who wishes to build upon the example given in the coding
16+
session to do so. Please make a PR adding your code to the
17+
[`followup-work/`](./followup-work) folder, and ping the presenter.
18+
19+
> Due to technical issues, the video for this session is missing. :/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package lcsdex
2+
3+
import (
4+
"std"
5+
"strconv"
6+
7+
"gno.land/p/demo/ufmt"
8+
"gno.land/p/demo/users"
9+
"gno.land/r/demo/foo20"
10+
"gno.land/r/demo/wugnot"
11+
)
12+
13+
// Possible improvements to this code
14+
// Handle multiple liquidity pools to allow for any grc20 swap
15+
// Implement rewards for liquidity providers
16+
// Improve rendering & error messages
17+
// Add tests
18+
19+
type LastTrade struct {
20+
addr std.Address
21+
amtWugnot uint64
22+
amtFoo20 uint64
23+
typ string // "wff" || "ffw"
24+
}
25+
26+
var (
27+
wugnotReserve uint64
28+
foo20Reserve uint64
29+
dexAddr = std.CurrentRealm().Addr() // Realm{pkgPath, address} // std.Address
30+
lt *LastTrade
31+
)
32+
33+
// constant product amm -> k = x * y
34+
35+
// amm -> LP (reserves of tokens) > who provides reseves
36+
// Please, use grc20.Approve before calling this function
37+
func AddLiquidity(fooAmt, wugnotAmt uint64) string {
38+
// add both wugnot & foo20 reserves
39+
// provide equal amounts
40+
// user provides amounts
41+
// approves beforehand
42+
if fooAmt == 0 || wugnotAmt == 0 {
43+
panic("you need to provide both tokens to the liquidity pool")
44+
}
45+
46+
if fooAmt != wugnotAmt {
47+
panic("provided amounts need to be the same")
48+
}
49+
50+
caller := std.PrevRealm().Addr() // std.Address // type Address string
51+
// todo: implement fee system
52+
53+
foo20.TransferFrom(users.AddressOrName(caller.String()), users.AddressOrName(dexAddr.String()), fooAmt)
54+
wugnot.TransferFrom(users.AddressOrName(caller.String()), users.AddressOrName(dexAddr.String()), wugnotAmt)
55+
56+
wugnotReserve += wugnotAmt
57+
foo20Reserve += fooAmt
58+
59+
return ufmt.Sprintf("successfully deposited %d wugnot & %d foo20", wugnotAmt, fooAmt)
60+
}
61+
62+
func SwapWugnotForFoo20(amtInWugnot, amtOutFoo20 uint64) string {
63+
if amtInWugnot == 0 || amtOutFoo20 == 0 {
64+
panic("you need to provide both in and out amounts")
65+
}
66+
67+
// k = x * y
68+
k := wugnotReserve * foo20Reserve
69+
70+
newWugnotReserve := wugnotReserve + amtInWugnot
71+
newFoo20Reserve := k / newWugnotReserve
72+
73+
amtOut := foo20Reserve - newFoo20Reserve
74+
75+
if amtOut < amtOutFoo20 {
76+
msg := ufmt.Sprintf("not enough liquidity. you can only get %d foo20 for %d wugnot", amtOut, amtInWugnot)
77+
panic(msg)
78+
}
79+
80+
caller := std.PrevRealm().Addr()
81+
wugnot.TransferFrom(users.AddressOrName(caller.String()), users.AddressOrName(dexAddr.String()), amtInWugnot)
82+
foo20.Transfer(users.AddressOrName(caller.String()), amtOutFoo20)
83+
84+
wugnotReserve = newWugnotReserve
85+
foo20Reserve = newFoo20Reserve
86+
87+
lt = &LastTrade{
88+
addr: caller,
89+
amtWugnot: amtInWugnot,
90+
amtFoo20: amtOutFoo20,
91+
typ: "wff", // wugnot for foo20
92+
}
93+
94+
return ufmt.Sprintf("successfully swapped %d wugnot for %d foo20", amtInWugnot, amtOutFoo20)
95+
}
96+
97+
func SwapFoo20ForWugnot(amtInFoo20, amountOutWugnot uint64) string {
98+
if amtInFoo20 == 0 || amountOutWugnot == 0 {
99+
panic("you need to provide both in and out amounts")
100+
}
101+
102+
// k = x * y
103+
k := wugnotReserve * foo20Reserve
104+
105+
newFoo20Reserve := foo20Reserve + amtInFoo20
106+
newWugnotReserve := k / newFoo20Reserve
107+
108+
amtOut := wugnotReserve - newWugnotReserve
109+
110+
if amtOut < amountOutWugnot {
111+
msg := ufmt.Sprintf("not enough liquidity. you can only get %d wugnot for %d foo20", amtOut, amtInFoo20)
112+
panic(msg)
113+
}
114+
115+
caller := std.PrevRealm().Addr()
116+
foo20.TransferFrom(users.AddressOrName(caller.String()), users.AddressOrName(dexAddr.String()), amtInFoo20)
117+
wugnot.Transfer(users.AddressOrName(caller.String()), amountOutWugnot)
118+
119+
wugnotReserve = newWugnotReserve
120+
foo20Reserve = newFoo20Reserve
121+
122+
lt = &LastTrade{
123+
addr: caller,
124+
amtWugnot: amountOutWugnot,
125+
amtFoo20: amtInFoo20,
126+
typ: "ffw", // foo20 for wugnot
127+
}
128+
129+
return ufmt.Sprintf("successfully swapped %d foo20 for %d wugnot", amtInFoo20, amountOutWugnot)
130+
}
131+
132+
func Render(_ string) string {
133+
output := "# GRC20 Simple DEX\n\n"
134+
135+
output += ufmt.Sprintf("DEX Address: %s\n\n", dexAddr.String())
136+
output += ufmt.Sprintf("Liquidity: %d wugnot, %d foo20\n\n", wugnotReserve, foo20Reserve)
137+
output += ufmt.Sprintf("1 wugnot = %s foo20\n\n", manualFloat(wugnotReserve, foo20Reserve))
138+
output += ufmt.Sprintf("1 foo20 = %s wugnot\n\n", manualFloat(foo20Reserve, wugnotReserve))
139+
140+
if lt != nil {
141+
output += "### Last Swap\n\n"
142+
143+
if lt.typ == "wff" {
144+
output += ufmt.Sprintf("%s traded %d wugnot for %d foo20", lt.addr.String(), lt.amtWugnot, lt.amtFoo20)
145+
} else {
146+
output += ufmt.Sprintf("%s traded %d foo20 for %d wugnot", lt.addr.String(), lt.amtFoo20, lt.amtWugnot)
147+
}
148+
}
149+
150+
return output
151+
}
152+
153+
func manualFloat(a, b uint64) string {
154+
quotient := a / b
155+
remainder := a % b
156+
157+
quotientStr := strconv.FormatUint(quotient, 10)
158+
scaledRemainder := (remainder * 1000000) / b
159+
remainderStr := strconv.FormatUint(scaledRemainder, 10)
160+
161+
return quotientStr + "." + remainderStr
162+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module gno.land/r/lcs/dex
2+
3+
require (
4+
gno.land/p/demo/ufmt v0.0.0-latest
5+
gno.land/p/demo/users v0.0.0-latest
6+
gno.land/r/demo/foo20 v0.0.0-latest
7+
gno.land/r/demo/wugnot v0.0.0-latest
8+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Followup work
2+
3+
To add your code for this GnoLCS, create a directory named after your GitHub username
4+
under this folder.
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Gno Live Coding Session #2
2+
3+
#### Topic: A gno.land home realm
4+
#### Date: Friday, Aug 30th 2024
5+
#### Presenter: [@leohhhn](https://github.com/leohhhn)
6+
7+
This live coding session showed attendees how to build their own home realm for
8+
gno.land.
9+
10+
The home realm for gno.land is meant to be similar to what a GitHub profile page
11+
is for GitHub. It's personal, and it includes information about the user.
12+
13+
In this specific example, we create a home realm that adds an image, text about
14+
the user, and also showcases dynamic imports of `r/demo/art` realms. All of this
15+
is then combined into an output to showcase how the `Render()` function works
16+
in Gno.
17+
18+
## Following up
19+
20+
We encourage anyone who wishes to build upon the example given in the coding
21+
session to do so. Please make a PR adding your code to the
22+
[`followup-work/`](./followup-work) folder, and ping the presenter.
23+
24+
## Video
25+
26+
Video recording can be found [here](https://www.youtube.com/watch?v=ZI0ZGDMbj-U).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Package config is simply Leon's configuration file.
2+
// It can be used externally to dynamically give Leon the rights to call something;
3+
// Say, an admin variable can be set to r/leon/config.Address(). Then, Leon can
4+
// update his address and still retain admin priveleges.
5+
package config
6+
7+
import (
8+
"errors"
9+
"std"
10+
)
11+
12+
var (
13+
main std.Address
14+
backup std.Address
15+
)
16+
17+
func init() {
18+
main = "g125em6arxsnj49vx35f0n0z34putv5ty3376fg5" // registered to @leon
19+
}
20+
21+
func Address() std.Address {
22+
return main
23+
}
24+
25+
func Backup() std.Address {
26+
return backup
27+
}
28+
29+
func SetAddress(newAddr std.Address) {
30+
AssertAuthorized()
31+
if !newAddr.IsValid() {
32+
panic("config: invalid address")
33+
}
34+
35+
main = newAddr
36+
}
37+
38+
func SetBackup(newAddr std.Address) {
39+
AssertAuthorized()
40+
if !newAddr.IsValid() {
41+
panic("config: invalid address")
42+
}
43+
44+
backup = newAddr
45+
}
46+
47+
func CheckAuthorized() error {
48+
caller := std.PrevRealm().Addr()
49+
50+
if caller != main || caller != backup {
51+
return errors.New("config: unauthorized")
52+
}
53+
54+
return nil
55+
}
56+
57+
func AssertAuthorized() {
58+
caller := std.PrevRealm().Addr()
59+
60+
if caller != main || caller != backup {
61+
panic("config: unauthorized")
62+
}
63+
}
64+
65+
// Possible improvements
66+
// Add errors, add a non-panicking function for Authorized
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module gno.land/r/leon/config
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module gno.land/r/leon/home
2+
3+
require (
4+
gno.land/p/demo/ufmt v0.0.0-latest
5+
gno.land/r/demo/art/gnoface v0.0.0-latest
6+
gno.land/r/leon/config v0.0.0-latest
7+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Package home is Leon's personal home realm, deployed under gno.land/r/leon/home
2+
// It is meant to act as Leon's profile page on gno.land
3+
package home
4+
5+
import (
6+
"std"
7+
"strconv"
8+
9+
"gno.land/p/demo/ufmt"
10+
"gno.land/r/demo/art/gnoface"
11+
"gno.land/r/demo/art/millipede"
12+
"gno.land/r/leon/config"
13+
)
14+
15+
var (
16+
pfp string // link to my profile pic
17+
pfpCaption string
18+
abtMe [2]string
19+
)
20+
21+
func init() {
22+
pfp = "https://i.imgflip.com/91vskx.jpg"
23+
pfpCaption = "[My favourite painting & pfp](https://en.wikipedia.org/wiki/Wanderer_above_the_Sea_of_Fog)"
24+
abtMe = [2]string{
25+
`### About me
26+
Hi, I'm Leon, a DevRel Engineer at gno.land. I am a tech enthusiast,
27+
life-long learner, and sharer of knowledge.`,
28+
`### Contributions
29+
My contributions to gno.land can mainly be found
30+
[here](https://github.com/gnolang/gno/issues?q=sort:updated-desc+author:leohhhn).
31+
32+
TODO import r/gh`,
33+
}
34+
}
35+
36+
// Updating
37+
38+
func UpdateAbtMe(col1, col2 string) {
39+
config.AssertAuthorized()
40+
abtMe[0] = col1
41+
abtMe[1] = col2
42+
}
43+
44+
// Todo: make setters for all pkg-level variables
45+
46+
// Rendering
47+
48+
func Render(_ string) string {
49+
output := "# Leon's Homepage\n\n"
50+
51+
output += renderAboutMe()
52+
output += "\n\n"
53+
output += renderArt()
54+
55+
return output
56+
}
57+
58+
func renderAboutMe() string {
59+
out := "<div class='columns-3'>"
60+
61+
out += "<div>\n\n"
62+
out += ufmt.Sprintf("![](%s)\n\n%s\n\n", pfp, pfpCaption)
63+
out += "</div>\n\n"
64+
65+
out += "<div>\n\n"
66+
out += abtMe[0] + "\n\n"
67+
out += "</div>\n\n"
68+
69+
out += "<div>\n\n"
70+
out += abtMe[1] + "\n\n"
71+
out += "</div>\n\n"
72+
73+
out += "</div>"
74+
return out
75+
}
76+
77+
func renderArt() string {
78+
out := `<div class=jumbotron>` + "\n\n"
79+
out += "## Gno Art\n\n"
80+
out += "<div class='columns-3'>"
81+
82+
out += renderGnoFace()
83+
out += renderMillipede()
84+
out += renderGnoFace()
85+
86+
out += "</div><!-- /columns-3 -->"
87+
out += "</div><!-- /jumbotron -->"
88+
89+
return out
90+
}
91+
92+
func renderGnoFace() string {
93+
out := "<div>\n\n"
94+
out += gnoface.Render(strconv.Itoa(int(std.GetHeight())))
95+
out += "</div>\n\n"
96+
97+
return out
98+
}
99+
100+
func renderMillipede() string {
101+
out := "<div>\n\n"
102+
out += "Millipede\n\n"
103+
out += "```\n" + millipede.Draw(int(std.GetHeight()%10+1)) + "```\n"
104+
out += "</div>\n\n"
105+
106+
return out
107+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"std"
6+
)
7+
8+
var (
9+
main std.Address
10+
backup std.Address
11+
)
12+
13+
func init() {
14+
main = "g1jqllg8870dcf9xtwjqd6ln9ujla2cvh0e7jwyq"
15+
}
16+
17+
func Address() std.Address {
18+
return main
19+
}
20+
21+
func Backup() std.Address {
22+
return backup
23+
}
24+
25+
func SetAddress(a std.Address) error {
26+
if !a.IsValid(){
27+
return errors.New("config: invalid address")
28+
}
29+
30+
if err := checkAuthorized(); err != nil {
31+
return err
32+
}
33+
34+
main = a
35+
return nil
36+
}
37+
38+
func SetBackup(a std.Address) error {
39+
if !a.IsValid(){
40+
return errors.New("config: invalid address")
41+
}
42+
43+
if err := checkAuthorized(); err != nil {
44+
return err
45+
}
46+
47+
main = a
48+
return nil
49+
}
50+
51+
func checkAuthorized() error {
52+
caller := std.PrevRealm().Addr()
53+
if caller != main || caller != backup {
54+
return errors.New("config: unauthorized")
55+
}
56+
57+
return nil
58+
}
59+
60+
func AssertAuthorized() {
61+
caller := std.PrevRealm().Addr()
62+
if caller != main || caller != backup {
63+
panic("config: unauthorized")
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module gno.land/r/nemanya/config
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module gno.land/r/nemanya/home
2+
3+
require (
4+
gno.land/p/demo/ufmt v0.0.0-latest
5+
gno.land/r/nemanya/config v0.0.0-latest
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package home
2+
3+
import (
4+
"gno.land/r/nemanya/config"
5+
)
6+
7+
type Project struct {
8+
Name string
9+
URL string
10+
}
11+
12+
type Social struct {
13+
Name string
14+
URL string
15+
}
16+
17+
var (
18+
aboutMe string
19+
projects map[int]Project
20+
socials map[int]Social
21+
22+
23+
fontFamily = "Inter, sans-serif"
24+
primaryColor = "#FEFEFE"
25+
borderColor = "#D30000"
26+
fontSizeLarge = "7rem"
27+
fontSizeMedium = "4rem"
28+
fontSizeSmall = "1.5rem"
29+
fontSizeExtraSmall = "1rem"
30+
)
31+
32+
func init() {
33+
aboutMe = "I'm Nemanja Matic from Serbia, an IT student and aspiring Web3 developer. I discovered gno.land at the Petnica Web3 Camp and I'm eager to make significant contributions to this project."
34+
35+
projects = map[int]Project{
36+
0: {"Liberty Bridge", "https://github.com/Milosevic02/LibertyBridge"},
37+
}
38+
39+
socials = map[int]Social{
40+
0: {"GitHub", "https://github.com/Nemanya8"},
41+
1: {"LinkedIn", "https://www.linkedin.com/in/nemanjamatic"},
42+
2: {"Email", "mailto:matic.nemanya@gmail.com"},
43+
}
44+
}
45+
46+
func UpdateAboutMe(newAboutMe string) {
47+
config.AssertAuthorized()
48+
aboutMe = newAboutMe
49+
}
50+
51+
func AddProject(index int, name string, url string) {
52+
config.AssertAuthorized()
53+
if index >= 0 && index < 4 {
54+
projects[index] = Project{Name: name, URL: url}
55+
}
56+
}
57+
58+
func RemoveProject(index int) {
59+
config.AssertAuthorized()
60+
if index >= 0 && index < 4 {
61+
delete(projects, index)
62+
}
63+
}
64+
65+
func AddSocial(index int, name string, url string) {
66+
config.AssertAuthorized()
67+
if index >= 0 && index < 3 {
68+
socials[index] = Social{Name: name, URL: url}
69+
}
70+
}
71+
72+
func RemoveSocial(index int) {
73+
config.AssertAuthorized()
74+
if index >= 0 && index < 3 {
75+
delete(socials, index)
76+
}
77+
}
78+
79+
func Render(path string) string {
80+
return "<div style='display: flex;'>\n" +
81+
" <div style='flex: 8; margin-right: 20px; padding: 2rem; border: 2px solid transparent; border-image: linear-gradient(166deg, " + borderColor + " 0%, rgba(0,0,0,0) 20%); border-image-slice: 1;'>\n" +
82+
" " + renderAboutMe() + "\n" +
83+
" </div>\n" +
84+
" <div style='flex: 2; padding: 2rem; border: 2px solid transparent; border-image: linear-gradient(324deg, " + borderColor + " 0%, rgba(0,0,0,0) 20%); border-image-slice: 1;'>\n" +
85+
" " + renderProjects() + "\n" +
86+
" </div>\n" +
87+
"</div>\n"
88+
}
89+
90+
func renderAboutMe() string {
91+
return "<div class='rows-3'>\n" +
92+
" <h1 style='font-family: " + fontFamily + "; font-weight: 100; color: " + primaryColor + "; text-align: left; font-size: " + fontSizeLarge + ";'>Nemanya.</h1>\n" +
93+
" <div style='border-left: 1px solid " + borderColor + "; padding-left: 1rem;'>\n" +
94+
" <p style='font-family: " + fontFamily + "; color: " + primaryColor + "; font-size: " + fontSizeSmall + "; margin-bottom: 5rem;'>\n" +
95+
" " + aboutMe + "\n" +
96+
" </p>\n" +
97+
" </div>\n" +
98+
" " + renderSocials() + "\n" +
99+
"</div><!-- /rows-3 -->\n"
100+
}
101+
102+
func renderSocials() string {
103+
socialsHTML := "<div class='socials-container' style='display: flex; justify-content: center; align-items: center; gap: 20px;'>\n"
104+
for _, social := range socials {
105+
socialsHTML += " <div style='display: flex; justify-content: center; align-items: center;'>\n" +
106+
" <a href='" + social.URL + "' style='color: " + primaryColor + "; font-family: " + fontFamily + "; font-size: " + fontSizeExtraSmall + "; display: flex; justify-content: center; align-items: center; width: 100%; height: 100%;'>" + social.Name + "</a>\n" +
107+
" </div>\n"
108+
}
109+
socialsHTML += "</div>\n"
110+
return socialsHTML
111+
}
112+
113+
func renderProjects() string {
114+
projectsHTML := "<div class='rows-5'>\n" +
115+
" <h2 style='font-family: " + fontFamily + "; font-weight: 200; color: " + primaryColor + "; text-align: left; font-size: " + fontSizeMedium + ";'>Projects</h2>\n"
116+
for _, project := range projects {
117+
projectsHTML += " <div style='margin-bottom: 1rem; border-left: 1px solid " + borderColor + "; padding-left: 1rem;'>\n" +
118+
" <a href='" + project.URL + "' style='color: " + primaryColor + "; font-family: " + fontFamily + "; font-size: " + fontSizeSmall + ";'>" + project.Name + "</a>\n" +
119+
" </div>\n"
120+
}
121+
projectsHTML += "</div><!-- /rows-5 -->\n"
122+
return projectsHTML
123+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Followup work
2+
3+
To add your code for this GnoLCS, create a directory named after your GitHub username
4+
under this folder.
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Gno Live Coding Session #3
2+
3+
#### Topic: Creating your own GRC20 token while Gno language features
4+
#### Date: Friday, Sept 13th 2024
5+
#### Presenter: [@leohhhn](https://github.com/leohhhn)
6+
7+
This Live Coding session creating a [`GRC20`](https://gno.land/p/demo/grc/grc20) token
8+
in Gno, while exploring Gno's language features, such as calling methods on
9+
exported top-level variables.
10+
11+
The code contains an example of a GRC20 token, example
12+
[`Run`](https://docs.gno.land/gno-tooling/cli/gnokey/state-changing-calls#run)
13+
scripts which enable interactions with it.
14+
15+
## Following up
16+
17+
We encourage anyone who wishes to build upon the example given in the coding
18+
session to do so. Please make a PR adding your code to the
19+
[`followup-work/`](./followup-work) folder, and ping the presenter.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Package run20 showcases a simple way to create a GRC20 token using the p/demo/grc/grc20 package.
2+
// This package also showcases how to use the MsgRun message type:
3+
// Exposing a variable of a type that contains exposed methods will expose those methods to the end-user as well.
4+
// In this example, it is the grc20.Token interface type.
5+
// Currently, the only way to interact with it is via MsgRun (https://docs.gno.land/gno-tooling/cli/gnokey/state-changing-calls#the-power-of-run)
6+
// The `example_interactions` folder contains Gno scripts that can be provided to the Run transactions to execute these methods.
7+
// This functionality is planned for MsgCall as well in the future.
8+
// For more token examples, check out wugnot, foo20, and bar20 in the examples/ folder in the Gno monorepo.
9+
package run20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
import (
4+
leon "gno.land/r/leon/token"
5+
)
6+
7+
// using the Approve method of the grc20.Token interface, which is the type of `leon.Token`
8+
// read more about Run in the official gno.land docs
9+
func main() {
10+
leon.Token.Approve("g10ahumypepd2qcrau7kahv8q78f7jcdns5tn54a", 10_000*1_000_000)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import (
4+
leon "gno.land/r/leon/token"
5+
)
6+
7+
// using the Transfer method of the grc20.Token interface, which is the type of `leon.Token`
8+
// read more about Run in the official gno.land docs
9+
func main() {
10+
leon.Token.Transfer("g10ahumypepd2qcrau7kahv8q78f7jcdns5tn54a", 10_000*1_000_000)
11+
leon.Token.Transfer("g13awn2575t8s2vf3svlprc4dg0e9z5wchejdxk8", 10_000*1_000_000)
12+
leon.Token.Transfer("g162jgpk4740r6a7g53cgz9ahxqtyuekgqchw6w9", 10_000*1_000_000)
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module gno.land/r/leon/run20
2+
3+
require (
4+
gno.land/p/demo/grc/grc20 v0.0.0-latest
5+
gno.land/r/leon/token/registry v0.0.0-latest
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package run20
2+
3+
import "gno.land/p/demo/grc/grc20"
4+
5+
var (
6+
// bank is a new instance of the grc20.Banker type which contains admin functionality, such as mint, burn, etc
7+
// should not be exported, unless you want to expose mint & burn functionality to all users
8+
bank = grc20.NewBanker("Gno Live Coding #3 Token", "LCS3", 6)
9+
// Token is an instance of the interface grc20.Token following the fungible token spec.
10+
// Token can be safely exposed, as contains only the subset of banker functionalities which are non-admin related.
11+
// This is why it is called a "safe object" - it's safe to expose to the public.
12+
Token = bank.Token()
13+
)
14+
15+
func init() {
16+
// minting initial balances
17+
_ = bank.Mint("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5", 10000000000000) // leon
18+
_ = bank.Mint("g10ahumypepd2qcrau7kahv8q78f7jcdns5tn54a", 10_000*1_000_000) // malek
19+
_ = bank.Mint("g13awn2575t8s2vf3svlprc4dg0e9z5wchejdxk8", 10_000*1_000_000) // stefan n
20+
_ = bank.Mint("g162jgpk4740r6a7g53cgz9ahxqtyuekgqchw6w9", 10_000*1_000_000) // varmeta
21+
}
22+
23+
func Render(_ string) string {
24+
return bank.RenderHome()
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Followup work
2+
3+
To add your code for this GnoLCS, create a directory named after your GitHub username
4+
under this folder.
5+
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Gno Live Coding Sessions
2+
3+
Hello! Welcome to the Gno Live Coding Sessions directory.
4+
5+
Gno Live Coding sessions (GnoLCS) are a educational initiative meant to provide
6+
new builders with practical examples of how to build applications with Gno & gno.land.
7+
8+
Each subfolder of this directory is meant to contain a few things:
9+
- A README file with a brief overview of that specific GnoLCS topic
10+
- Code created during the session
11+
- A `followup-work` folder, which anyone can use to add their added work or code
12+
improvements to the code built during the session.
13+
- Other useful information
14+
15+
Currently, the sessions are hosted on the [official gno.land Discord server](https://discord.gg/S8nKUqwkPn).
16+
Check out the active events on the server for the upcoming Gno Live Coding session.
17+

0 commit comments

Comments
 (0)
Please sign in to comment.