From 44f5bb09b30132c9e60fb01431b74a62d3b7cdf6 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:10:28 +0100 Subject: [PATCH 1/8] feat: buidl slides Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../2025-01-09--buidleu--manfred/Makefile | 5 + .../code/.gitignore | 1 + .../code/Makefile | 15 ++ .../code/async_closure.gno | 1 + .../code/atomicswap.gno | 84 +++++++++++ .../code/bar20.gno | 19 +++ .../code/blog_admin.gno | 19 +++ .../code/blog_post.gno | 21 +++ .../code/board_comment.gno | 18 +++ .../code/board_post.gno | 19 +++ .../code/carbon-now.json | 21 +++ .../code/composability.gno | 0 .../code/counter.gno | 11 ++ .../code/counter_2.gno | 22 +++ .../2025-01-09--buidleu--manfred/code/dao.gno | 16 +++ .../code/foo20.gno | 100 +++++++++++++ .../code/gno-doc-std.txt | 20 +++ .../code/grc20_type.gno | 18 +++ .../code/grc20factory.gno | 24 ++++ .../code/grc20registry.gno | 24 ++++ .../code/guest_book.gno | 21 +++ .../code/hello.go | 7 + .../code/hello_world.gno | 5 + .../code/interop.gno | 11 ++ .../code/interop2.gno | 8 ++ .../code/minidex.gno | 23 +++ .../code/minidex_2.gno | 21 +++ .../code/tamagotchi.gno | 20 +++ .../code/tamagotchi_render.gno | 20 +++ .../code/users.gno | 16 +++ .../code/users_invite.gno | 21 +++ .../code/wugnot.gno | 24 ++++ .../2025-01-09--buidleu--manfred/metadata.yml | 15 ++ .../presentation.slide | 133 ++++++++++++++++++ 34 files changed, 803 insertions(+) create mode 100644 presentations/2025-01-09--buidleu--manfred/Makefile create mode 100644 presentations/2025-01-09--buidleu--manfred/code/.gitignore create mode 100644 presentations/2025-01-09--buidleu--manfred/code/Makefile create mode 100644 presentations/2025-01-09--buidleu--manfred/code/async_closure.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/bar20.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/blog_post.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/board_comment.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/board_post.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/carbon-now.json create mode 100644 presentations/2025-01-09--buidleu--manfred/code/composability.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/counter.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/counter_2.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/foo20.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt create mode 100644 presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/guest_book.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/hello.go create mode 100644 presentations/2025-01-09--buidleu--manfred/code/hello_world.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/interop.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/interop2.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/minidex.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/users.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/users_invite.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/wugnot.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/metadata.yml create mode 100644 presentations/2025-01-09--buidleu--manfred/presentation.slide diff --git a/presentations/2025-01-09--buidleu--manfred/Makefile b/presentations/2025-01-09--buidleu--manfred/Makefile new file mode 100644 index 0000000..842599e --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/Makefile @@ -0,0 +1,5 @@ +run: + cd ..; go run golang.org/x/tools/cmd/present -http 0.0.0.0:3999 # -base ../.. + +runx: + cd ..; go run github.com/soypat/go-presentx -http 0.0.0.0:3999 diff --git a/presentations/2025-01-09--buidleu--manfred/code/.gitignore b/presentations/2025-01-09--buidleu--manfred/code/.gitignore new file mode 100644 index 0000000..e33609d --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/.gitignore @@ -0,0 +1 @@ +*.png diff --git a/presentations/2025-01-09--buidleu--manfred/code/Makefile b/presentations/2025-01-09--buidleu--manfred/code/Makefile new file mode 100644 index 0000000..d23649a --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/Makefile @@ -0,0 +1,15 @@ +SOURCES := $(shell find . -name '*.gno') +PNGS := $(SOURCES:.gno=.png) + +.PHONY: all +all: $(PNGS) + +.SECONDEXPANSION: +%.png: $$(wildcard %.gno) + carbon-now --config carbon-now.json --save-as $(basename $@) $< + +clean: + rm *.png + +install: + yarn global add carbon-now-cli diff --git a/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno b/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno new file mode 100644 index 0000000..f6df921 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno @@ -0,0 +1 @@ +package async_closure diff --git a/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno b/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno new file mode 100644 index 0000000..6338930 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno @@ -0,0 +1,84 @@ +package atomicswap + +// Swap represents an atomic swap contract. +type Swap struct { + sender std.Address + recipient std.Address + hashlock string + timelock time.Time + claimed bool + refunded bool + amountStr string + sendFn func(to std.Address) +} + +func newSwap( + sender std.Address, + recipient std.Address, + hashlock string, + timelock time.Time, + amountStr string, + sendFn func(std.Address), +) *Swap { + require(time.Now().Before(timelock), "timelock must be in the future") + require(hashlock != "", "hashlock must not be empty") + return &Swap{ + recipient: recipient, + sender: sender, + hashlock: hashlock, + timelock: timelock, + claimed: false, + refunded: false, + sendFn: sendFn, + amountStr: amountStr, + } +} + +// Claim allows the recipient to claim the funds if they provide the correct preimage. +func (s *Swap) Claim(preimage string) { + require(!s.claimed, "already claimed") + require(!s.refunded, "already refunded") + require(std.PrevRealm().Addr() == s.recipient, "unauthorized") + + hashlock := sha256.Sum256([]byte(preimage)) + hashlockHex := hex.EncodeToString(hashlock[:]) + require(hashlockHex == s.hashlock, "invalid preimage") + + s.claimed = true + s.sendFn(s.recipient) +} + +// Refund allows the sender to refund the funds after the timelock has expired. +func (s *Swap) Refund() { + require(!s.claimed, "already claimed") + require(!s.refunded, "already refunded") + require(std.PrevRealm().Addr() == s.sender, "unauthorized") + require(time.Now().After(s.timelock), "timelock not expired") + + s.refunded = true + s.sendFn(s.sender) +} + +func NewCustomCoinSwap(recipient std.Address, hashlock string, timelock time.Time) (int, *Swap) { + sender := std.PrevRealm().Addr() + sent := std.GetOrigSend() + require(len(sent) != 0, "at least one coin needs to be sent") + sendFn := func(to std.Address) { + banker := std.GetBanker(std.BankerTypeRealmSend) + banker.SendCoins(std.GetOrigPkgAddr(), to, sent) + } + amountStr := sent.String() + swap := newSwap(sender, recipient, hashlock, timelock, amountStr, sendFn) + counter++ + id := strconv.Itoa(counter) + swaps.Set(id, swap) + return counter, swap +} + +func Claim(id int, secret string) { + swaps.Get(id).Claim(secret) +} + +func Refund(id int) { + swaps.Get(id).Refund(secret) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/bar20.gno b/presentations/2025-01-09--buidleu--manfred/code/bar20.gno new file mode 100644 index 0000000..2f0b7be --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/bar20.gno @@ -0,0 +1,19 @@ +package bar20 + +import "gno.land/r/demo/grc20reg" + +var Bank, adm = grc20.NewBank("Bar", "BAR", 4) + +var UserBanker = grc20.PrevRealmBanker(Bank) + +func init() { + grc20reg.Register(Bank, "") +} + +func Faucet() string { + caller := std.GetOrignCaller() + if err := adm.Mint(caller, 1_000_000); err != nil { + return "error: " + err.Error() + } + return "OK" +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno b/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno new file mode 100644 index 0000000..3ca2d6c --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno @@ -0,0 +1,19 @@ +package blog + +type Post struct{} + +var ( + adminAuthor string = std.GetOrginCaller() // Set deployer as admin + postid int + posts []Post +) + +func Post(name, body string) Post { + // Assert caller is admin + caller := std.GetOrigCaller() + if caller != adminAuthor { + panic("unauthorized") + } + + // Add post ... +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno b/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno new file mode 100644 index 0000000..5eb28b3 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno @@ -0,0 +1,21 @@ +package blog + +import "time" + +type Post struct { + id int + Date time.Time + Name string + Comments []Post +} + +var postid int + +var posts []Post + +func Post(name, body string) Post { + post := Post{postid, time.Now(), name, body} + posts = append(posts, post) + postid++ + return post +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno b/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno new file mode 100644 index 0000000..48c493b --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno @@ -0,0 +1,18 @@ +package board + +type Post struct{} + +type Board struct{} + +func (b *Board) Post(name, body string) Post + +func (b *Board) Comment(id string, body string) { + if id < 0 || id >= len(b.posts) { + panic("invalid id") + } + caller := std.GetOrigCaller() + + post := &b.posts[id] + comment := Post{len(post.Comment), caller, "", body} + post.Comment = append(post.Comment, post) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/board_post.gno b/presentations/2025-01-09--buidleu--manfred/code/board_post.gno new file mode 100644 index 0000000..79764a0 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/board_post.gno @@ -0,0 +1,19 @@ +package board + +type Post struct { + id int + Author std.Address + Name string + Comments []Post +} + +type Board struct { + posts []Post +} + +func (b *Board) Post(name, body string) Post { + caller := std.GetOrigCaller() + post := Post{len(b.posts), caller, name, body} + b.posts = append(b.posts, post) + return post +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json b/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json new file mode 100644 index 0000000..9e7abd7 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json @@ -0,0 +1,21 @@ +{ + "latest-preset": { + "t": "blackboard", + "bg": "rgba(100,245,145,1)", + "wc": false, + "fm": "Hack", + "fs": "15px", + "ln": false, + "ds": false, + "dsyoff": "20px", + "dsblur": "68px", + "wa": true, + "lh": "133%", + "pv": "0px", + "ph": "0px", + "si": false, + "wm": false, + "es": "4x", + "type": "png" + } +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/composability.gno b/presentations/2025-01-09--buidleu--manfred/code/composability.gno new file mode 100644 index 0000000..e69de29 diff --git a/presentations/2025-01-09--buidleu--manfred/code/counter.gno b/presentations/2025-01-09--buidleu--manfred/code/counter.gno new file mode 100644 index 0000000..74b111e --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/counter.gno @@ -0,0 +1,11 @@ +package counter + +var Counter int + +func Inc() { + Counter += 1 +} + +func Render(path string) string { + return "My Super Counter: " + Counter +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno b/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno new file mode 100644 index 0000000..5c16346 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno @@ -0,0 +1,22 @@ +package counter + +import "std" + +var ( + Counter int + LastCaller std.Address +) + +func Inc() int { + return addToCounter(amount) +} + +func Add(amount int) int { + return addToCounter(amount) +} + +func addToCounter(amount int) int { + Counter += amount + LastCaller = std.GetOrigCaller() + return Counter +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao.gno b/presentations/2025-01-09--buidleu--manfred/code/dao.gno new file mode 100644 index 0000000..4a1cf93 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/dao.gno @@ -0,0 +1,16 @@ +package dao + +// Voter defines the needed methods for a voting system +type Voter interface { + // IsAccepted indicates if the voting process had been accepted + IsAccepted(voters []std.Address) bool + + // IsFinished indicates if the voting process is finished + IsFinished(voters []std.Address) bool + + // Vote adds a new vote to the voting system + Vote(voters []std.Address, caller std.Address, flag string) + + // Status returns a human friendly string describing how the voting process is going + Status(voters []std.Address) string +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/foo20.gno b/presentations/2025-01-09--buidleu--manfred/code/foo20.gno new file mode 100644 index 0000000..27f92b3 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/foo20.gno @@ -0,0 +1,100 @@ +// foo20 is a GRC20 token contract where all the GRC20 methods are proxified +// with top-level functions. see also gno.land/r/demo/bar20. +package foo20 + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ownable" + "gno.land/p/demo/ufmt" + pusers "gno.land/p/demo/users" + "gno.land/r/demo/grc20reg" + "gno.land/r/demo/users" +) + +var ( + Bank, adm = grc20.NewBank("Foo", "FOO", 4) + UserBanker = grc20.PrevRealmBanker(Bank) + owner = ownable.NewWithAddress("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") // @manfred +) + +func init() { + adm.Mint(owner.Owner(), 1_000_000*10_000) // @administrator (1M) + grc20reg.Register(Bank, "") +} + +func TotalSupply() uint64 { + return UserBanker.TotalSupply() +} + +func BalanceOf(owner pusers.AddressOrName) uint64 { + ownerAddr := users.Resolve(owner) + return UserBanker.BalanceOf(ownerAddr) +} + +func Allowance(owner, spender pusers.AddressOrName) uint64 { + ownerAddr := users.Resolve(owner) + spenderAddr := users.Resolve(spender) + return UserBanker.Allowance(ownerAddr, spenderAddr) +} + +func Transfer(to pusers.AddressOrName, amount uint64) { + toAddr := users.Resolve(to) + checkErr(UserBanker.Transfer(toAddr, amount)) +} + +func Approve(spender pusers.AddressOrName, amount uint64) { + spenderAddr := users.Resolve(spender) + checkErr(UserBanker.Approve(spenderAddr, amount)) +} + +func TransferFrom(from, to pusers.AddressOrName, amount uint64) { + fromAddr := users.Resolve(from) + toAddr := users.Resolve(to) + checkErr(UserBanker.TransferFrom(fromAddr, toAddr, amount)) +} + +// Faucet is distributing foo20 tokens without restriction (unsafe). +// For a real token faucet, you should take care of setting limits are asking payment. +func Faucet() { + caller := std.PrevRealm().Addr() + amount := uint64(1_000 * 10_000) // 1k + checkErr(adm.Mint(caller, amount)) +} + +func Mint(to pusers.AddressOrName, amount uint64) { + owner.AssertCallerIsOwner() + toAddr := users.Resolve(to) + checkErr(adm.Mint(toAddr, amount)) +} + +func Burn(from pusers.AddressOrName, amount uint64) { + owner.AssertCallerIsOwner() + fromAddr := users.Resolve(from) + checkErr(adm.Burn(fromAddr, amount)) +} + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return Bank.RenderHome() + case c == 2 && parts[0] == "balance": + owner := pusers.AddressOrName(parts[1]) + ownerAddr := users.Resolve(owner) + balance := UserBanker.BalanceOf(ownerAddr) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} + +func checkErr(err error) { + if err != nil { + panic(err) + } +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt b/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt new file mode 100644 index 0000000..95d0250 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt @@ -0,0 +1,20 @@ +package std // import "std" + +func AssertOriginCall() +func Emit(typ string, attrs ...string) +func GetChainID() string +func GetHeight() int64 +func IsOriginCall() bool +type Address string + func DerivePkgAddr(pkgPath string) Address + func GetOrigCaller() Address +type Banker interface{ ... } + func GetBanker(bt BankerType) Banker +type Coin struct{ ... } + func NewCoin(denom string, amount int64) Coin +type Coins []Coin + func GetOrigSend() Coins + func NewCoins(coins ...Coin) Coins +type Realm struct{ ... } + func CurrentRealm() Realm + func PrevRealm() Realm diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno new file mode 100644 index 0000000..36184f9 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno @@ -0,0 +1,18 @@ +// gno.land/p/demo/grc/grc20 +package grc20 + +import ( + "std" + + "gno.land/p/demo/grc/exts" +) + +type GRC20 interface { + exts.TokenMetadata + TotalSupply() uint64 + BalanceOf(account std.Address) uint64 + Transfer(to std.Address, amount uint64) error + Allowance(owner, spender std.Address) uint64 + Approve(spender std.Address, amount uint64) error + TransferFrom(from, to std.Address, amount uint64) error +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno new file mode 100644 index 0000000..90dde71 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno @@ -0,0 +1,24 @@ +package foo20 + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/r/demo/grc20reg" +) + +var instances avl.Tree // symbol -> instance + +func New(name, symbol string, decimals uint, initialMint, faucet uint64) { + admin := std.PrevRealm().Addr() + bank := grc20.NewBank(name, symbol, decimals) + bank.Mint(admin, initialMint) + inst := instance{bank: bank, admin: ownable.NewWithAddress(admin), faucet: faucet} + instances.Set(symbol, &inst) + grc20reg.Register(bank, symbol) +} + +func Bank(symbol string) *grc20.Bank { + return mustGetInstance(symbol).bank +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno new file mode 100644 index 0000000..0547664 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno @@ -0,0 +1,24 @@ +package grc20reg + +import ( + "std" + + "gno.land/p/demo/grc/grc20" +) + +var registry = avl.NewTree() // rlmPath[.slug] -> *grc20.Bank + +func Register(bank *grc20.Bank, slug string) { + rlmPath := std.PrevRealm().PkgPath() + key := fqname.Construct(rlmPath, slug) + registry.Set(key, bank) + std.Emit(registerEvent, "pkgpath", rlmPath, "slug", slug) +} + +func Get(key string) *grc20.Bank { + bank, ok := registry.Get(key) + if !ok { + return nil + } + return bank.(*grc20.Bank) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/guest_book.gno b/presentations/2025-01-09--buidleu--manfred/code/guest_book.gno new file mode 100644 index 0000000..dde4e93 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/guest_book.gno @@ -0,0 +1,21 @@ +package guest + +import "std" + +var messages avl.Tree // std.Address -> string (message) + +func AddMessage(message string) { + caller := std.GetOrigCaller() + if _, ok := messages.Get(caller); ok { + panic("this user already post a message") + } + messages.Set(caller, message) // add message to our messages list +} + +func Render(path string) string { + var view string + for _, message := range messages { + view = view + "\n" + message // add message to the render + } + return view +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/hello.go b/presentations/2025-01-09--buidleu--manfred/code/hello.go new file mode 100644 index 0000000..21ab42a --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/hello.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, Nebular! It's Manfred.") +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/hello_world.gno b/presentations/2025-01-09--buidleu--manfred/code/hello_world.gno new file mode 100644 index 0000000..044709e --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/hello_world.gno @@ -0,0 +1,5 @@ +package hello + +func Hello() string { + return "hello world" +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/interop.gno b/presentations/2025-01-09--buidleu--manfred/code/interop.gno new file mode 100644 index 0000000..34d4512 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/interop.gno @@ -0,0 +1,11 @@ +package alice + +var x int + +func GetX() int { + return x +} + +func SetX(n int) { + x = n +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/interop2.gno b/presentations/2025-01-09--buidleu--manfred/code/interop2.gno new file mode 100644 index 0000000..861dd97 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/interop2.gno @@ -0,0 +1,8 @@ +package bob + +import "alice" + +func IncrAlice() { + x := alice.GetX() + alice.SetX(x + 1) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/minidex.gno b/presentations/2025-01-09--buidleu--manfred/code/minidex.gno new file mode 100644 index 0000000..0d683e8 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/minidex.gno @@ -0,0 +1,23 @@ +package dex + +func (dex *DEX) PlaceOrder(tokenFrom, tokenTo *grc20.Bank, amount uint64, isBuy bool) int { + trader, contract := std.PrevRealm().Addr(), std.CurrentRealm().Addr() + userBanker := grc20.AccountBanker(tokenFrom, "") + + allowance := userBanker.Allowance(trader, contract) + require(allowance >= amount, "insufficient allowance") + err := userBanker.TransferFrom(trader, contract, amount) + checkErr(err, "cannot retrieve tokens from allowance") + + order := &Order{trader: trader, tokenFrom: tokenFrom, tokenTo: tokenTo, amount: amount, isBuy: isBuy} + dex.Append(order) + std.Emit( + "order_placed", + "trader", trader.String(), + "tokenFrom", tokenFrom.GetName(), + "tokenTo", tokenTo.GetName(), + "amount", ufmt.Sprintf("%d", amount), + ) + + return dex.matchPairOrders(tokenFrom, tokenTo) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno b/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno new file mode 100644 index 0000000..ce3209b --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno @@ -0,0 +1,21 @@ +package dex + +func (dex *DEX) matchPairOrders(tokenFrom, tokenTo *grc20.Bank) int { + matched := 0 + orders.Iterate("", "", func(key1 string, value interface{}) bool { + orders.Iterate("", "", func(key2 string, value2 interface{}) bool { + if order1.isBuy != order2.isBuy && order1.tokenFrom == order2.tokenTo && order1.tokenTo == order2.tokenFrom { + amount := min(order1.amount, order2.amount) + order1.amount -= amount + order2.amount -= amount + banker1 := grc20.AccountBanker(order1.tokenFrom, "") + banker2 := grc20.AccountBanker(order2.tokenFrom, "") + banker1.Transfer(order2.trader, amount) + banker2.Transfer(order1.trader, amount) + matched++ + std.Emit("trade_executed" /*...*/) + } + }) + }) + return matched +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno new file mode 100644 index 0000000..28b03b6 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno @@ -0,0 +1,20 @@ +package tamagochi + +// Tamagotchi structure +type Tamagotchi struct { + hunger int + happiness int + health int +} + +func (t *Tamagotchi) Feed() { + t.updateStats() + if t.dead() { + return + } + t.hunger = bound(t.hunger-10, 0, 100) +} + +func (t *Tamagotchi) Heal() { /* ... */ } + +func (t *Tamagotchi) Play() { /* ... */ } diff --git a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno new file mode 100644 index 0000000..ceeeb66 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno @@ -0,0 +1,20 @@ +package tamagochi + +var tam Tamagochi + +// Interaction function ... + +func Render(path string) string { + switch { + case tam.Health() == 0: + return "😵" // dead face + case tam.Health() < 30: + return "😷" // sick face + case tam.Happiness() < 30: + return "😢" // sad face + case tam.Hunger() > 70: + return "😫" // hungry face + default: + return "😃" // happy face + } +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/users.gno b/presentations/2025-01-09--buidleu--manfred/code/users.gno new file mode 100644 index 0000000..f982fbd --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/users.gno @@ -0,0 +1,16 @@ +package users + +var ( + addressToUsers avl.Tree // address -> user + usersToAddress avl.Tree // user -> address +) + +func Register(name string) { + caller := std.GetOrigCaller() + if usersToAddress.Has(name) || addressToUsers.Has(caller) { + panic("address/name already registered") + } + + usersToAddress.Set(name, std.GetOrignCaller()) + addressToUsers.Set(std.GetOrignCaller(), name) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno b/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno new file mode 100644 index 0000000..43cd7d5 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno @@ -0,0 +1,21 @@ +package users + +var admin = "g1xxxxx..." + +var invites avl.Tree // std.Address -> true + +func AdminSendInvite(address std.Address) { + if caller := std.GetOrigCaller(); caller != admin { + panic("unauthorized") + } + invites.Set(address, true) +} + +func Register() { + caller := std.GetOrigCaller() + if !invites.Has(caller) { + panic("caller hasn't been invited") + } + // ... register caller + invites.Remove(address) +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno b/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno new file mode 100644 index 0000000..a913af8 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno @@ -0,0 +1,24 @@ +package wugnot + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" + pusers "gno.land/p/demo/users" + "gno.land/r/demo/grc20reg" + "gno.land/r/demo/users" +) + +var Bank, adm = grc20.NewBank("wrapped GNOT", "wugnot", 0) + +func Deposit() { + caller := std.PrevRealm().Addr() + sent := std.GetOrigSend() + amount := sent.AmountOf("ugnot") + require(uint64(amount) >= ugnotMinDeposit, ufmt.Sprintf("Deposit below minimum: %d/%d ugnot.", amount, ugnotMinDeposit)) + checkErr(adm.Mint(caller, uint64(amount))) +} + +// Withdraw... diff --git a/presentations/2025-01-09--buidleu--manfred/metadata.yml b/presentations/2025-01-09--buidleu--manfred/metadata.yml new file mode 100644 index 0000000..df9bf4d --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/metadata.yml @@ -0,0 +1,15 @@ +# Date of the workshop +date: "2025-01-09" +# Title of the workshop +title: "Designing Seamless Interconnected dApps with Gno" +# GitHub usernames of the speakers +speakers: + - "moul" +# Location of the workshop +location: "Lisbon, Portugal" +# At which event the workshop took place, if any +event: "BUIDL Europe 2025" +# Workshop slides link. If the link is local, only put the file name, without any other path parts. +slides: "https://gnolang.github.io/workshops/presentations/2025-01-09--buidleu--manfred/presentation.slide.html#1" +# Workshop recording +#recording: "" \ No newline at end of file diff --git a/presentations/2025-01-09--buidleu--manfred/presentation.slide b/presentations/2025-01-09--buidleu--manfred/presentation.slide new file mode 100644 index 0000000..060fd97 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/presentation.slide @@ -0,0 +1,133 @@ +# Designing Seamless Interconnected dApps with Gno +BUIDL Eu, 9 Jan 2025, Lisbon +Tags: golang, gnolang +Summary: TODO + +Manfred Touron +VP Eng., Gno.land +https://gno.land/ +https://github.com/gnolang +@moul + +## Introduction + +- Decentralized applications are the future of Web3. +- **Challenges:** Lack of modularity, limited interoperability, and siloed ecosystems. +- **Goal:** Showcase Gno’s unique capabilities for building next-gen interconnected dApps. + +## What is Gno? + +- **Gno**: Deterministic, transactional, auto-persistent Go interpreter. +- **Gno.land**: Blockchain designed for modular, interoperable dApps. +- **Key Features**: + - Composable DAOs + - Safe Objects and Pausable Closures + - Hub for Gno ecosystem + +## Key Features Overview + +- **Safe Objects**: + - Gno objects act like mini-dApps with secure boundaries. + - Factory contracts can create independent objects accessible to other contracts. + +## Full Type Safety + +- Highlights how Gno avoids Solidity’s pitfalls (e.g., unsafe casting, complicated Yul interactions). +- Contracts are imported directly, exposing clean interfaces like GRC20. +- Eliminates casting addresses to contracts for safer development. + +## Following Go Design Principles + +- Gno tooling simplifies development with built-in optimizations (-cover, -profile, -metrics). +- All-in-one development using gnodev, avoiding reliance on third-party frameworks like Hardhat or Foundry. +- Debugger support, with plans to debug transaction execution. + +## Unique Exploration with gnoweb + +- Blockchain provides discovery features (e.g., Hall of Fame) instead of company-specific marketing. +- Package paths offer a new way to explore the ecosystem. + +## Writing Go (Gno) Only + +- No need to learn JS/TS for frontend development. +- Streamlined dApp development fully in Gno. + +## Built-in Coins vs. GRC20 + +- Offers built-in coin mechanisms as an alternative to token standards. +- Simplifies use cases requiring native token functionalities. + +## gno hello world + +.code ./code/hello_world.gno + +## Pausable Closures + +- Transactions can pause and resume seamlessly. +- Preserve state and ownership for asynchronous execution. + +## counter.gno - persistency and Render() + +.code ./code/counter.gno + +## counter.gno - private helpers + +.code ./code/counter_2.gno + +## Advanced Use Cases + +- **Composable DAOs**: + - Flexible, collaborative governance systems. + - Example: Multi-layered decision-making via interconnected smart contracts. + - DAO pointers for automatic proposal execution. +- **Connected Applications**: + - Enable cross-dApp interactions with shared functionality. + +## alice.gno, bob.gno + +.code ./code/interop.gno + +.code ./code/interop2.gno + +## Gas Fee Rewards for Developers + +- Usage of packages can allocate part of gas fees to deployers. +- Incentivizes creation and maintenance of reusable components. + +## Technical Design + +- Gno emphasizes modularity, allowing reusable contract components. +- Interoperability supports seamless interactions between dApps. + +## Why Gno? + +The **GnoVM** enables: +**Seamless interoperability** of +**untrusted** user programs +written in a secure language. + +## grc20/types.gno + +Implement a GRC20 token standard, similar to ERC20 in Solidity. + +.code ./code/grc20_type.gno + +## Road Ahead + +- Launching soon as an experimental chain. +- Opportunities for developers to contribute and innovate. + +## Conclusion + +- Gno is designed for the next generation of modular, interoperable dApps. +- Join the community and start building today! + +## Resources + +- Documentation: https://docs.gno.land +- GitHub: https://github.com/gnolang +- Discord: [Invite Link] + +## Questions? + +Thank you! \ No newline at end of file From 5e763189675e07a753efadc09081b130d33e4a3e Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:12:56 +0000 Subject: [PATCH 2/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .gitignore | 3 + .../code/bar20.gno | 19 -- .../code/buidl20.gno | 20 ++ .../code/counter_2.gno | 2 +- .../code/dao_aggregated.gno | 23 +++ .../code/dao_composition.gno | 10 + .../code/dao_impl.gno | 13 ++ .../code/dao_type.gno | 14 ++ .../code/executable_proposal.gno | 23 +++ .../code/grc20_type.gno | 25 ++- .../code/grc20factory.gno | 35 ++-- .../code/grc20reg.gno | 14 ++ .../code/hello.go | 4 +- .../code/minidex.gno | 2 +- .../code/solidity_721.sol | 15 ++ .../presentation.slide | 185 ++++++++++-------- 16 files changed, 275 insertions(+), 132 deletions(-) delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/bar20.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/buidl20.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao_aggregated.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao_composition.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao_impl.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao_type.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/executable_proposal.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/grc20reg.gno create mode 100644 presentations/2025-01-09--buidleu--manfred/code/solidity_721.sol diff --git a/.gitignore b/.gitignore index a23836a..3adb90a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ # generated files from reveal tool slides.html + +presentations/static/ +presentations/templates \ No newline at end of file diff --git a/presentations/2025-01-09--buidleu--manfred/code/bar20.gno b/presentations/2025-01-09--buidleu--manfred/code/bar20.gno deleted file mode 100644 index 2f0b7be..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/bar20.gno +++ /dev/null @@ -1,19 +0,0 @@ -package bar20 - -import "gno.land/r/demo/grc20reg" - -var Bank, adm = grc20.NewBank("Bar", "BAR", 4) - -var UserBanker = grc20.PrevRealmBanker(Bank) - -func init() { - grc20reg.Register(Bank, "") -} - -func Faucet() string { - caller := std.GetOrignCaller() - if err := adm.Mint(caller, 1_000_000); err != nil { - return "error: " + err.Error() - } - return "OK" -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno b/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno new file mode 100644 index 0000000..367f4a6 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno @@ -0,0 +1,20 @@ +package buidl20 + +import ( + "std" + "gno.land/p/demo/grc/grc20" +) + +// Token: public safe object for composability +// adm: privileged object for minting +var Token, adm = grc20.NewToken("Buidl", "BDL", 4) + +// grc20 API for the caller +var UserTeller = Token.CallerTeller() + +func init() { + adm.Mint(1_000_000, std.GetOrigCaller()) // mint 1M to the contract deployer. +} + +// optional helpers +// [...] diff --git a/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno b/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno index 5c16346..2154c7d 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno +++ b/presentations/2025-01-09--buidleu--manfred/code/counter_2.gno @@ -8,7 +8,7 @@ var ( ) func Inc() int { - return addToCounter(amount) + return addToCounter(1) } func Add(amount int) int { diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao_aggregated.gno b/presentations/2025-01-09--buidleu--manfred/code/dao_aggregated.gno new file mode 100644 index 0000000..83588c5 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/dao_aggregated.gno @@ -0,0 +1,23 @@ +package aggregateddao + +import "gno.land/p/dao" + +type AggregatedDAO struct { dao1, dao2 dao.DAO } + +func (a *AggregatedDAO) Propose(def dao.PropDefinition) (dao.Proposal, error) { + prop1, _ := a.dao1.Propose(def) + prop2, _ := a.dao2.Propose(def) + // [...] +} + +func (a *AggregatedDAO) Len() int { return a.dao1.Len() + a.dao2.Len() } + +func (a *AggregatedDAO) ActiveProposals() dao.PropList { + return append(a.dao1.ActiveProposals(), a.dao2.ActiveProposals()...) +} + +func (a *AggregatedDAO) ArchivedProposals() dao.PropList { + return append(a.dao1.ArchivedProposals(), a.dao2.ArchivedProposals()...) +} + +// [...] diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao_composition.gno b/presentations/2025-01-09--buidleu--manfred/code/dao_composition.gno new file mode 100644 index 0000000..5434e44 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/dao_composition.gno @@ -0,0 +1,10 @@ +// gno.land/r/foobardao +package foobardao + +import ( + "gno.land/r/foodao" + "gno.land/r/bardao" + "gno.land/p/aggregateddao" +) + +var FooBarDAO = aggregateddao.New(foodao.DAO, bardao.DAO) diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao_impl.gno b/presentations/2025-01-09--buidleu--manfred/code/dao_impl.gno new file mode 100644 index 0000000..9e694aa --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/dao_impl.gno @@ -0,0 +1,13 @@ +package foodao + +import "gno.land/p/dao" // interface + +// FooDAO implements the dao.DAO interface. +type FooDAO struct { proposals []dao.Proposal, voters []std.Address } + +func (d *FooDAO) Propose(def PropDefinition) (Proposal, error) { /* [...] */ } +func (d *FooDAO) GetProposal(proposalID uint64) (Proposal, error) { /* [...] */ } +func (d *FooDAO) Execute(proposalID uint64) error { /* [...] */ } +func (d *FooDAO) ActiveProposals() PropList { /* [...] */ } +func (d *FooDAO) ArchivedProposals() PropList { /* [...] */ } +func (d *FooDAO) Len() int { /* [...] */ } diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao_type.gno b/presentations/2025-01-09--buidleu--manfred/code/dao_type.gno new file mode 100644 index 0000000..4cc16a9 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/dao_type.gno @@ -0,0 +1,14 @@ +// gno.land/p/dao +package dao + +type DAO interface { + // Core proposal operations + Propose(def PropDefinition) (Proposal, error) + GetProposal(proposalID uint64) (Proposal, error) + Execute(proposalID uint64) error + + // List operations + ActiveProposals() PropList + ArchivedProposals() PropList + Len() int +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/executable_proposal.gno b/presentations/2025-01-09--buidleu--manfred/code/executable_proposal.gno new file mode 100644 index 0000000..8cd9b29 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/executable_proposal.gno @@ -0,0 +1,23 @@ +// prop1.gno + +import "gno.land/r/gov/dao" +import "gno.land/r/buidl/buidl20" + +func init() { + closure := func() error { + // this closure will preserve the execution context at the time of + // creation, even if the proposal is executed by someone else. + return executor() + } + prop := dao.ProposalRequest{ + Title: "", + Description: "lorem ipsum dolor sit amet", + Executor: closure, + } + dao.Propose(prop) +} + +func executor() error { + buidl20.TransferTo("g12345678", 1_000_000) // transfer 1M $BUIDL + return nil +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno index 36184f9..a98ad71 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20_type.gno @@ -1,14 +1,6 @@ -// gno.land/p/demo/grc/grc20 -package grc20 +package grc20 // gno.land/p/demo/grc/grc20 -import ( - "std" - - "gno.land/p/demo/grc/exts" -) - -type GRC20 interface { - exts.TokenMetadata +type Teller interface { TotalSupply() uint64 BalanceOf(account std.Address) uint64 Transfer(to std.Address, amount uint64) error @@ -16,3 +8,16 @@ type GRC20 interface { Approve(spender std.Address, amount uint64) error TransferFrom(from, to std.Address, amount uint64) error } + +type Token struct { + name, symbol string + decimals uint + ledger *PrivateLedger +} + +type PrivateLedger struct { + totalSupply uint64 + balances, allowances avl.Tree +} + +func NewToken(name, symbol string, decs uint) (*Token, *PrivateLedger) { /*...*/ } diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno index 90dde71..f3a36b1 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20factory.gno @@ -1,24 +1,23 @@ -package foo20 - -import ( - "std" - "strings" - - "gno.land/p/demo/grc/grc20" - "gno.land/r/demo/grc20reg" -) +// gno.land/r/demo/grc20factory +package grc20factory var instances avl.Tree // symbol -> instance -func New(name, symbol string, decimals uint, initialMint, faucet uint64) { - admin := std.PrevRealm().Addr() - bank := grc20.NewBank(name, symbol, decimals) - bank.Mint(admin, initialMint) - inst := instance{bank: bank, admin: ownable.NewWithAddress(admin), faucet: faucet} - instances.Set(symbol, &inst) - grc20reg.Register(bank, symbol) +type instance struct { + token *grc20.Token + ledger *grc20.PrivateLedger + admin *ownable.Ownable + faucet uint64 // per-request amount. disabled if 0. } -func Bank(symbol string) *grc20.Bank { - return mustGetInstance(symbol).bank +func New(name, symbol string, decimals uint, initialMint, faucet uint64) { + caller := std.PrevRealm().Addr() + token, ledger := grc20.NewToken(name, symbol, decimals) + if initialMint > 0 { + ledger.Mint(admin, initialMint) + } + owner := ownable.NewWithAddress(admin) + inst := instance{token: token, ledger: ledger, admin: owner, faucet: faucet} + instances.Set(symbol, &inst) + grc20reg.Register(token.Getter(), symbol) } diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20reg.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20reg.gno new file mode 100644 index 0000000..0ba44e1 --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/grc20reg.gno @@ -0,0 +1,14 @@ +// gno.land/r/demo/grc20reg +package grc20reg + +var registry = avl.NewTree() // rlmPath -> TokenGetter + +func Register(tokenGetter grc20.TokenGetter) { + rlmPath := std.PrevRealm().PkgPath() + registry.Set(rlmPath, tokenGetter) +} + +func Get(key string) grc20.TokenGetter { + tokenGetter, _ := registry.Get(key) + return tokenGetter +} diff --git a/presentations/2025-01-09--buidleu--manfred/code/hello.go b/presentations/2025-01-09--buidleu--manfred/code/hello.go index 21ab42a..6ebbec9 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/hello.go +++ b/presentations/2025-01-09--buidleu--manfred/code/hello.go @@ -1,7 +1,5 @@ package main -import "fmt" - func main() { - fmt.Println("Hello, Nebular! It's Manfred.") + println("Hello, BUIDL! It's Manfred.") } diff --git a/presentations/2025-01-09--buidleu--manfred/code/minidex.gno b/presentations/2025-01-09--buidleu--manfred/code/minidex.gno index 0d683e8..3675d03 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/minidex.gno +++ b/presentations/2025-01-09--buidleu--manfred/code/minidex.gno @@ -1,6 +1,6 @@ package dex -func (dex *DEX) PlaceOrder(tokenFrom, tokenTo *grc20.Bank, amount uint64, isBuy bool) int { +func (dex *DEX) PlaceOrder(tokenFrom, tokenTo grc20.Token, amount uint64, isBuy bool) int { trader, contract := std.PrevRealm().Addr(), std.CurrentRealm().Addr() userBanker := grc20.AccountBanker(tokenFrom, "") diff --git a/presentations/2025-01-09--buidleu--manfred/code/solidity_721.sol b/presentations/2025-01-09--buidleu--manfred/code/solidity_721.sol new file mode 100644 index 0000000..a556e5d --- /dev/null +++ b/presentations/2025-01-09--buidleu--manfred/code/solidity_721.sol @@ -0,0 +1,15 @@ +// Solidity example for ERC721Receiver check +interface IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} + +// Solidity relies on checking bytes4 signature +require( + contract.onERC721Received.selector == bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")), + "Invalid ERC721 receiver" +); diff --git a/presentations/2025-01-09--buidleu--manfred/presentation.slide b/presentations/2025-01-09--buidleu--manfred/presentation.slide index 060fd97..e42d379 100644 --- a/presentations/2025-01-09--buidleu--manfred/presentation.slide +++ b/presentations/2025-01-09--buidleu--manfred/presentation.slide @@ -1,133 +1,158 @@ -# Designing Seamless Interconnected dApps with Gno -BUIDL Eu, 9 Jan 2025, Lisbon +# designing seamless interconnected dApps with gno +BUIDL Europe, 9 Jan 2025, Lisbon Tags: golang, gnolang Summary: TODO Manfred Touron -VP Eng., Gno.land +VP Eng., gno.land https://gno.land/ https://github.com/gnolang @moul -## Introduction +## bonjour, BUIDL! -- Decentralized applications are the future of Web3. -- **Challenges:** Lack of modularity, limited interoperability, and siloed ecosystems. -- **Goal:** Showcase Gno’s unique capabilities for building next-gen interconnected dApps. +.code ./code/hello.go -## What is Gno? +- Manfred Touron +- started with code, stuck with Go +- built Scaleway, Berty, and now gno.land -- **Gno**: Deterministic, transactional, auto-persistent Go interpreter. -- **Gno.land**: Blockchain designed for modular, interoperable dApps. -- **Key Features**: - - Composable DAOs - - Safe Objects and Pausable Closures - - Hub for Gno ecosystem +## introduction -## Key Features Overview +- dApps are the future of Web3 +- **challenges:** lack of modularity and composability, limited interoperability, and siloed ecosystems +- **goal:** showcase Gno’s unique capabilities for building next-gen interconnected dApps -- **Safe Objects**: - - Gno objects act like mini-dApps with secure boundaries. - - Factory contracts can create independent objects accessible to other contracts. +## what is gno? -## Full Type Safety +- **gno**: transactional VM + - determinism: guaranteed + - state persistence: built-in + - sandboxed execution: Safe and secure + - more info: https://docs.gno.land/reference/go-gno-compatibility +- **gno.land**: blockchain designed for modular, transparent, and interoperable dApps + - "proof of ...": new consensus mechanism + - tendermint2, IBCx, ICSx + - hub of the gno ecosystem -- Highlights how Gno avoids Solidity’s pitfalls (e.g., unsafe casting, complicated Yul interactions). -- Contracts are imported directly, exposing clean interfaces like GRC20. -- Eliminates casting addresses to contracts for safer development. +## gno hello world -## Following Go Design Principles +.code ./code/hello_world.gno -- Gno tooling simplifies development with built-in optimizations (-cover, -profile, -metrics). -- All-in-one development using gnodev, avoiding reliance on third-party frameworks like Hardhat or Foundry. -- Debugger support, with plans to debug transaction execution. +## counter.gno - persistency and Render() -## Unique Exploration with gnoweb +.code ./code/counter.gno -- Blockchain provides discovery features (e.g., Hall of Fame) instead of company-specific marketing. -- Package paths offer a new way to explore the ecosystem. +## counter.gno - private helpers -## Writing Go (Gno) Only +.code ./code/counter_2.gno -- No need to learn JS/TS for frontend development. -- Streamlined dApp development fully in Gno. +## guestbook.gno -## Built-in Coins vs. GRC20 +.code ./code/guest_book.gno -- Offers built-in coin mechanisms as an alternative to token standards. -- Simplifies use cases requiring native token functionalities. +## why gno? -## gno hello world +the **gnoVM** enables: +**seamless interoperability** of +**untrusted** user programs +written in a good language. -.code ./code/hello_world.gno +## alice.gno, bob.gno -## Pausable Closures +.code ./code/interop.gno -- Transactions can pause and resume seamlessly. -- Preserve state and ownership for asynchronous execution. +.code ./code/interop2.gno -## counter.gno - persistency and Render() +## packages and realms -.code ./code/counter.gno +- **packages** + - reusable code modules + - pure: stateless, cannot import realms +- **realms** + - end-user "smart contracts" with persistent state via global variables + - exported functions accessible through RPC + - supports contract-to-contract interactions -## counter.gno - private helpers +## gno grc20 package -.code ./code/counter_2.gno +.code ./code/grc20_type.gno -## Advanced Use Cases +## gno buidl20 realm -- **Composable DAOs**: - - Flexible, collaborative governance systems. - - Example: Multi-layered decision-making via interconnected smart contracts. - - DAO pointers for automatic proposal execution. -- **Connected Applications**: - - Enable cross-dApp interactions with shared functionality. +.code ./code/buidl20.gno -## alice.gno, bob.gno +## gno safe objects -.code ./code/interop.gno +- gno objects can act like mini-dApps with secure boundaries +- factory contracts can create independent objects accessible to other contracts. -.code ./code/interop2.gno +## gno grc20reg realm -## Gas Fee Rewards for Developers +.code ./code/grc20reg.gno -- Usage of packages can allocate part of gas fees to deployers. -- Incentivizes creation and maintenance of reusable components. +## gno grc20factory realm -## Technical Design +.code ./code/grc20factory.gno -- Gno emphasizes modularity, allowing reusable contract components. -- Interoperability supports seamless interactions between dApps. +## gno full type safety -## Why Gno? +- how gno avoids Solidity’s pitfalls (e.g., unsafe casting, complicated Yul interactions). +- contracts are imported directly, exposing clean interfaces like GRC20. +- eliminates casting addresses to contracts for safer development. -The **GnoVM** enables: -**Seamless interoperability** of -**untrusted** user programs -written in a secure language. +.code ./code/solidity_721.sol -## grc20/types.gno +## gno minidex -Implement a GRC20 token standard, similar to ERC20 in Solidity. +.code ./code/minidex.gno -.code ./code/grc20_type.gno +## gno pausable closures + +- closures instanciated during transactions can pause and resume seamlessly +- preserve state and ownership for asynchronous execution +- allows arbitrary code execution for governance proposals + +## gno govdao proposal + +.code ./code/executable_proposal.gno + +## gno composition + +- similar to Go composition +- can compose package logic, or realms with state + +## a gno DAO interface + +.code ./code/dao_type.gno + +## a gno DAO implementation + +.code ./code/dao_impl.gno + +## a gno DAO aggregator -## Road Ahead +.code ./code/dao_aggregated.gno -- Launching soon as an experimental chain. -- Opportunities for developers to contribute and innovate. +## a gno DAO composition -## Conclusion +.code ./code/dao_composition.gno -- Gno is designed for the next generation of modular, interoperable dApps. -- Join the community and start building today! +## advanced use cases -## Resources +- **composable DAOs**: + - flexible, collaborative governance systems + - example: multi-layered decision-making via interconnected smart contracts + - DAO pointers for automatic proposal execution +- **connected dApps**: + - enable cross-dApp interactions with shared functionality -- Documentation: https://docs.gno.land -- GitHub: https://github.com/gnolang -- Discord: [Invite Link] +## road ahead -## Questions? +- gno is designed for the next generation of modular, interoperable dApps +- launching soon as an experimental chain +- opportunities for developers to contribute and innovate +- join the community and start building today! +- -> https://gno.land -Thank you! \ No newline at end of file +Thank you \ No newline at end of file From 1ea496e55c9242d2178ed7d3c474a9498abcf88f Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:19:45 +0000 Subject: [PATCH 3/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../presentation.slide | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/presentations/2025-01-09--buidleu--manfred/presentation.slide b/presentations/2025-01-09--buidleu--manfred/presentation.slide index e42d379..96ab059 100644 --- a/presentations/2025-01-09--buidleu--manfred/presentation.slide +++ b/presentations/2025-01-09--buidleu--manfred/presentation.slide @@ -138,14 +138,19 @@ written in a good language. .code ./code/dao_composition.gno -## advanced use cases - -- **composable DAOs**: - - flexible, collaborative governance systems - - example: multi-layered decision-making via interconnected smart contracts - - DAO pointers for automatic proposal execution -- **connected dApps**: - - enable cross-dApp interactions with shared functionality +## DAO compositions ideas + +- **sum**: combine DAOs by aggregating proposals and votes +- **weighted**: assign different voting weights to DAOs +- **delayed**: wrap DAOs to enforce delays before actions +- **fallback**: use a secondary DAO if the primary lacks data +- **sharded**: partition proposals into different DAOs +- **proxy**: forward actions to another DAO without exposure +- **crosschain**: aggregate DAOs across different blockchains +- **dynamic**: switch DAOs based on external conditions +- **routing**: pass only specific proposals to certain DAOs +- **hybrid**: mix centralized and decentralized governance +- ... ## road ahead @@ -155,4 +160,4 @@ written in a good language. - join the community and start building today! - -> https://gno.land -Thank you \ No newline at end of file +thank you! \ No newline at end of file From 307246a20e78d2b228271d547bada82889066917 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:26:37 +0000 Subject: [PATCH 4/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../presentation.slide | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/presentations/2025-01-09--buidleu--manfred/presentation.slide b/presentations/2025-01-09--buidleu--manfred/presentation.slide index 96ab059..4fc163c 100644 --- a/presentations/2025-01-09--buidleu--manfred/presentation.slide +++ b/presentations/2025-01-09--buidleu--manfred/presentation.slide @@ -19,20 +19,20 @@ https://github.com/gnolang ## introduction -- dApps are the future of Web3 -- **challenges:** lack of modularity and composability, limited interoperability, and siloed ecosystems -- **goal:** showcase Gno’s unique capabilities for building next-gen interconnected dApps +- dapps are the future of web3 +- challenges: lack of modularity and composability, limited interoperability, siloed ecosystems +- goal: showcase gno's unique capabilities for building next-gen interconnected dapps ## what is gno? -- **gno**: transactional VM +- gno: transactional vm - determinism: guaranteed - state persistence: built-in - - sandboxed execution: Safe and secure + - sandboxed execution: safe and secure - more info: https://docs.gno.land/reference/go-gno-compatibility -- **gno.land**: blockchain designed for modular, transparent, and interoperable dApps - - "proof of ...": new consensus mechanism - - tendermint2, IBCx, ICSx +- gno.land: blockchain designed for modular, transparent, interoperable dapps + - proof of ...: new consensus mechanism + - tendermint2, ibcx, icsx - hub of the gno ecosystem ## gno hello world @@ -53,10 +53,13 @@ https://github.com/gnolang ## why gno? -the **gnoVM** enables: -**seamless interoperability** of -**untrusted** user programs -written in a good language. +the gnovm enables: + +seamless interoperability of + +untrusted user programs + +written in a good language ## alice.gno, bob.gno @@ -66,12 +69,12 @@ written in a good language. ## packages and realms -- **packages** +- packages - reusable code modules - pure: stateless, cannot import realms -- **realms** - - end-user "smart contracts" with persistent state via global variables - - exported functions accessible through RPC +- realms + - end-user smart contracts with persistent state via global variables + - exported functions accessible through rpc - supports contract-to-contract interactions ## gno grc20 package @@ -85,7 +88,7 @@ written in a good language. ## gno safe objects - gno objects can act like mini-dApps with secure boundaries -- factory contracts can create independent objects accessible to other contracts. +- factory contracts can create independent objects accessible to other contracts ## gno grc20reg realm @@ -97,9 +100,9 @@ written in a good language. ## gno full type safety -- how gno avoids Solidity’s pitfalls (e.g., unsafe casting, complicated Yul interactions). -- contracts are imported directly, exposing clean interfaces like GRC20. -- eliminates casting addresses to contracts for safer development. +- how gno avoids Solidity's pitfalls (e.g., unsafe casting, complicated Yul interactions) +- contracts are imported directly, exposing clean interfaces like GRC20 +- eliminates casting addresses to contracts for safer development .code ./code/solidity_721.sol @@ -140,24 +143,24 @@ written in a good language. ## DAO compositions ideas -- **sum**: combine DAOs by aggregating proposals and votes -- **weighted**: assign different voting weights to DAOs -- **delayed**: wrap DAOs to enforce delays before actions -- **fallback**: use a secondary DAO if the primary lacks data -- **sharded**: partition proposals into different DAOs -- **proxy**: forward actions to another DAO without exposure -- **crosschain**: aggregate DAOs across different blockchains -- **dynamic**: switch DAOs based on external conditions -- **routing**: pass only specific proposals to certain DAOs -- **hybrid**: mix centralized and decentralized governance +- sum: combine daos by aggregating proposals and votes +- weighted: assign different voting weights to daos +- delayed: wrap daos to enforce delays before actions +- fallback: use secondary dao if primary lacks data +- sharded: partition proposals into different daos +- proxy: forward actions to another dao without exposure +- crosschain: aggregate daos across different blockchains +- dynamic: switch daos based on external conditions +- routing: pass specific proposals to certain daos +- hybrid: mix centralized and decentralized governance - ... ## road ahead -- gno is designed for the next generation of modular, interoperable dApps -- launching soon as an experimental chain +- gno is designed for next-gen modular, interoperable dapps +- launching soon as experimental chain - opportunities for developers to contribute and innovate -- join the community and start building today! +- join the community and start building today - -> https://gno.land thank you! \ No newline at end of file From 954d54f5779443030a110dee3ae53fde94b591ed Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:31:09 +0000 Subject: [PATCH 5/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- presentations/2025-01-09--buidleu--manfred/code/buidl20.gno | 1 + 1 file changed, 1 insertion(+) diff --git a/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno b/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno index 367f4a6..b032b85 100644 --- a/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno +++ b/presentations/2025-01-09--buidleu--manfred/code/buidl20.gno @@ -1,3 +1,4 @@ +// https://gno.land/r/moul/x/buidl20$source package buidl20 import ( From 97b22eb975005554992c6319db130f3ee4728969 Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:49:14 +0000 Subject: [PATCH 6/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../code/Makefile | 15 --- .../code/async_closure.gno | 1 - .../code/atomicswap.gno | 84 --------------- .../code/blog_admin.gno | 19 ---- .../code/blog_post.gno | 21 ---- .../code/board_comment.gno | 18 ---- .../code/board_post.gno | 19 ---- .../code/carbon-now.json | 21 ---- .../code/composability.gno | 0 .../2025-01-09--buidleu--manfred/code/dao.gno | 16 --- .../code/foo20.gno | 100 ------------------ .../code/gno-doc-std.txt | 20 ---- .../code/grc20registry.gno | 24 ----- .../code/minidex_2.gno | 21 ---- .../code/tamagotchi.gno | 20 ---- .../code/tamagotchi_render.gno | 20 ---- .../code/users.gno | 16 --- .../code/users_invite.gno | 21 ---- .../code/wugnot.gno | 24 ----- 19 files changed, 480 deletions(-) delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/Makefile delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/async_closure.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/blog_post.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/board_comment.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/board_post.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/carbon-now.json delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/composability.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/dao.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/foo20.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/users.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/users_invite.gno delete mode 100644 presentations/2025-01-09--buidleu--manfred/code/wugnot.gno diff --git a/presentations/2025-01-09--buidleu--manfred/code/Makefile b/presentations/2025-01-09--buidleu--manfred/code/Makefile deleted file mode 100644 index d23649a..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -SOURCES := $(shell find . -name '*.gno') -PNGS := $(SOURCES:.gno=.png) - -.PHONY: all -all: $(PNGS) - -.SECONDEXPANSION: -%.png: $$(wildcard %.gno) - carbon-now --config carbon-now.json --save-as $(basename $@) $< - -clean: - rm *.png - -install: - yarn global add carbon-now-cli diff --git a/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno b/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno deleted file mode 100644 index f6df921..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/async_closure.gno +++ /dev/null @@ -1 +0,0 @@ -package async_closure diff --git a/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno b/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno deleted file mode 100644 index 6338930..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/atomicswap.gno +++ /dev/null @@ -1,84 +0,0 @@ -package atomicswap - -// Swap represents an atomic swap contract. -type Swap struct { - sender std.Address - recipient std.Address - hashlock string - timelock time.Time - claimed bool - refunded bool - amountStr string - sendFn func(to std.Address) -} - -func newSwap( - sender std.Address, - recipient std.Address, - hashlock string, - timelock time.Time, - amountStr string, - sendFn func(std.Address), -) *Swap { - require(time.Now().Before(timelock), "timelock must be in the future") - require(hashlock != "", "hashlock must not be empty") - return &Swap{ - recipient: recipient, - sender: sender, - hashlock: hashlock, - timelock: timelock, - claimed: false, - refunded: false, - sendFn: sendFn, - amountStr: amountStr, - } -} - -// Claim allows the recipient to claim the funds if they provide the correct preimage. -func (s *Swap) Claim(preimage string) { - require(!s.claimed, "already claimed") - require(!s.refunded, "already refunded") - require(std.PrevRealm().Addr() == s.recipient, "unauthorized") - - hashlock := sha256.Sum256([]byte(preimage)) - hashlockHex := hex.EncodeToString(hashlock[:]) - require(hashlockHex == s.hashlock, "invalid preimage") - - s.claimed = true - s.sendFn(s.recipient) -} - -// Refund allows the sender to refund the funds after the timelock has expired. -func (s *Swap) Refund() { - require(!s.claimed, "already claimed") - require(!s.refunded, "already refunded") - require(std.PrevRealm().Addr() == s.sender, "unauthorized") - require(time.Now().After(s.timelock), "timelock not expired") - - s.refunded = true - s.sendFn(s.sender) -} - -func NewCustomCoinSwap(recipient std.Address, hashlock string, timelock time.Time) (int, *Swap) { - sender := std.PrevRealm().Addr() - sent := std.GetOrigSend() - require(len(sent) != 0, "at least one coin needs to be sent") - sendFn := func(to std.Address) { - banker := std.GetBanker(std.BankerTypeRealmSend) - banker.SendCoins(std.GetOrigPkgAddr(), to, sent) - } - amountStr := sent.String() - swap := newSwap(sender, recipient, hashlock, timelock, amountStr, sendFn) - counter++ - id := strconv.Itoa(counter) - swaps.Set(id, swap) - return counter, swap -} - -func Claim(id int, secret string) { - swaps.Get(id).Claim(secret) -} - -func Refund(id int) { - swaps.Get(id).Refund(secret) -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno b/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno deleted file mode 100644 index 3ca2d6c..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/blog_admin.gno +++ /dev/null @@ -1,19 +0,0 @@ -package blog - -type Post struct{} - -var ( - adminAuthor string = std.GetOrginCaller() // Set deployer as admin - postid int - posts []Post -) - -func Post(name, body string) Post { - // Assert caller is admin - caller := std.GetOrigCaller() - if caller != adminAuthor { - panic("unauthorized") - } - - // Add post ... -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno b/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno deleted file mode 100644 index 5eb28b3..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/blog_post.gno +++ /dev/null @@ -1,21 +0,0 @@ -package blog - -import "time" - -type Post struct { - id int - Date time.Time - Name string - Comments []Post -} - -var postid int - -var posts []Post - -func Post(name, body string) Post { - post := Post{postid, time.Now(), name, body} - posts = append(posts, post) - postid++ - return post -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno b/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno deleted file mode 100644 index 48c493b..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/board_comment.gno +++ /dev/null @@ -1,18 +0,0 @@ -package board - -type Post struct{} - -type Board struct{} - -func (b *Board) Post(name, body string) Post - -func (b *Board) Comment(id string, body string) { - if id < 0 || id >= len(b.posts) { - panic("invalid id") - } - caller := std.GetOrigCaller() - - post := &b.posts[id] - comment := Post{len(post.Comment), caller, "", body} - post.Comment = append(post.Comment, post) -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/board_post.gno b/presentations/2025-01-09--buidleu--manfred/code/board_post.gno deleted file mode 100644 index 79764a0..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/board_post.gno +++ /dev/null @@ -1,19 +0,0 @@ -package board - -type Post struct { - id int - Author std.Address - Name string - Comments []Post -} - -type Board struct { - posts []Post -} - -func (b *Board) Post(name, body string) Post { - caller := std.GetOrigCaller() - post := Post{len(b.posts), caller, name, body} - b.posts = append(b.posts, post) - return post -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json b/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json deleted file mode 100644 index 9e7abd7..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/carbon-now.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "latest-preset": { - "t": "blackboard", - "bg": "rgba(100,245,145,1)", - "wc": false, - "fm": "Hack", - "fs": "15px", - "ln": false, - "ds": false, - "dsyoff": "20px", - "dsblur": "68px", - "wa": true, - "lh": "133%", - "pv": "0px", - "ph": "0px", - "si": false, - "wm": false, - "es": "4x", - "type": "png" - } -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/composability.gno b/presentations/2025-01-09--buidleu--manfred/code/composability.gno deleted file mode 100644 index e69de29..0000000 diff --git a/presentations/2025-01-09--buidleu--manfred/code/dao.gno b/presentations/2025-01-09--buidleu--manfred/code/dao.gno deleted file mode 100644 index 4a1cf93..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/dao.gno +++ /dev/null @@ -1,16 +0,0 @@ -package dao - -// Voter defines the needed methods for a voting system -type Voter interface { - // IsAccepted indicates if the voting process had been accepted - IsAccepted(voters []std.Address) bool - - // IsFinished indicates if the voting process is finished - IsFinished(voters []std.Address) bool - - // Vote adds a new vote to the voting system - Vote(voters []std.Address, caller std.Address, flag string) - - // Status returns a human friendly string describing how the voting process is going - Status(voters []std.Address) string -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/foo20.gno b/presentations/2025-01-09--buidleu--manfred/code/foo20.gno deleted file mode 100644 index 27f92b3..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/foo20.gno +++ /dev/null @@ -1,100 +0,0 @@ -// foo20 is a GRC20 token contract where all the GRC20 methods are proxified -// with top-level functions. see also gno.land/r/demo/bar20. -package foo20 - -import ( - "std" - "strings" - - "gno.land/p/demo/grc/grc20" - "gno.land/p/demo/ownable" - "gno.land/p/demo/ufmt" - pusers "gno.land/p/demo/users" - "gno.land/r/demo/grc20reg" - "gno.land/r/demo/users" -) - -var ( - Bank, adm = grc20.NewBank("Foo", "FOO", 4) - UserBanker = grc20.PrevRealmBanker(Bank) - owner = ownable.NewWithAddress("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") // @manfred -) - -func init() { - adm.Mint(owner.Owner(), 1_000_000*10_000) // @administrator (1M) - grc20reg.Register(Bank, "") -} - -func TotalSupply() uint64 { - return UserBanker.TotalSupply() -} - -func BalanceOf(owner pusers.AddressOrName) uint64 { - ownerAddr := users.Resolve(owner) - return UserBanker.BalanceOf(ownerAddr) -} - -func Allowance(owner, spender pusers.AddressOrName) uint64 { - ownerAddr := users.Resolve(owner) - spenderAddr := users.Resolve(spender) - return UserBanker.Allowance(ownerAddr, spenderAddr) -} - -func Transfer(to pusers.AddressOrName, amount uint64) { - toAddr := users.Resolve(to) - checkErr(UserBanker.Transfer(toAddr, amount)) -} - -func Approve(spender pusers.AddressOrName, amount uint64) { - spenderAddr := users.Resolve(spender) - checkErr(UserBanker.Approve(spenderAddr, amount)) -} - -func TransferFrom(from, to pusers.AddressOrName, amount uint64) { - fromAddr := users.Resolve(from) - toAddr := users.Resolve(to) - checkErr(UserBanker.TransferFrom(fromAddr, toAddr, amount)) -} - -// Faucet is distributing foo20 tokens without restriction (unsafe). -// For a real token faucet, you should take care of setting limits are asking payment. -func Faucet() { - caller := std.PrevRealm().Addr() - amount := uint64(1_000 * 10_000) // 1k - checkErr(adm.Mint(caller, amount)) -} - -func Mint(to pusers.AddressOrName, amount uint64) { - owner.AssertCallerIsOwner() - toAddr := users.Resolve(to) - checkErr(adm.Mint(toAddr, amount)) -} - -func Burn(from pusers.AddressOrName, amount uint64) { - owner.AssertCallerIsOwner() - fromAddr := users.Resolve(from) - checkErr(adm.Burn(fromAddr, amount)) -} - -func Render(path string) string { - parts := strings.Split(path, "/") - c := len(parts) - - switch { - case path == "": - return Bank.RenderHome() - case c == 2 && parts[0] == "balance": - owner := pusers.AddressOrName(parts[1]) - ownerAddr := users.Resolve(owner) - balance := UserBanker.BalanceOf(ownerAddr) - return ufmt.Sprintf("%d\n", balance) - default: - return "404\n" - } -} - -func checkErr(err error) { - if err != nil { - panic(err) - } -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt b/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt deleted file mode 100644 index 95d0250..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/gno-doc-std.txt +++ /dev/null @@ -1,20 +0,0 @@ -package std // import "std" - -func AssertOriginCall() -func Emit(typ string, attrs ...string) -func GetChainID() string -func GetHeight() int64 -func IsOriginCall() bool -type Address string - func DerivePkgAddr(pkgPath string) Address - func GetOrigCaller() Address -type Banker interface{ ... } - func GetBanker(bt BankerType) Banker -type Coin struct{ ... } - func NewCoin(denom string, amount int64) Coin -type Coins []Coin - func GetOrigSend() Coins - func NewCoins(coins ...Coin) Coins -type Realm struct{ ... } - func CurrentRealm() Realm - func PrevRealm() Realm diff --git a/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno b/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno deleted file mode 100644 index 0547664..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/grc20registry.gno +++ /dev/null @@ -1,24 +0,0 @@ -package grc20reg - -import ( - "std" - - "gno.land/p/demo/grc/grc20" -) - -var registry = avl.NewTree() // rlmPath[.slug] -> *grc20.Bank - -func Register(bank *grc20.Bank, slug string) { - rlmPath := std.PrevRealm().PkgPath() - key := fqname.Construct(rlmPath, slug) - registry.Set(key, bank) - std.Emit(registerEvent, "pkgpath", rlmPath, "slug", slug) -} - -func Get(key string) *grc20.Bank { - bank, ok := registry.Get(key) - if !ok { - return nil - } - return bank.(*grc20.Bank) -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno b/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno deleted file mode 100644 index ce3209b..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/minidex_2.gno +++ /dev/null @@ -1,21 +0,0 @@ -package dex - -func (dex *DEX) matchPairOrders(tokenFrom, tokenTo *grc20.Bank) int { - matched := 0 - orders.Iterate("", "", func(key1 string, value interface{}) bool { - orders.Iterate("", "", func(key2 string, value2 interface{}) bool { - if order1.isBuy != order2.isBuy && order1.tokenFrom == order2.tokenTo && order1.tokenTo == order2.tokenFrom { - amount := min(order1.amount, order2.amount) - order1.amount -= amount - order2.amount -= amount - banker1 := grc20.AccountBanker(order1.tokenFrom, "") - banker2 := grc20.AccountBanker(order2.tokenFrom, "") - banker1.Transfer(order2.trader, amount) - banker2.Transfer(order1.trader, amount) - matched++ - std.Emit("trade_executed" /*...*/) - } - }) - }) - return matched -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno deleted file mode 100644 index 28b03b6..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi.gno +++ /dev/null @@ -1,20 +0,0 @@ -package tamagochi - -// Tamagotchi structure -type Tamagotchi struct { - hunger int - happiness int - health int -} - -func (t *Tamagotchi) Feed() { - t.updateStats() - if t.dead() { - return - } - t.hunger = bound(t.hunger-10, 0, 100) -} - -func (t *Tamagotchi) Heal() { /* ... */ } - -func (t *Tamagotchi) Play() { /* ... */ } diff --git a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno b/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno deleted file mode 100644 index ceeeb66..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/tamagotchi_render.gno +++ /dev/null @@ -1,20 +0,0 @@ -package tamagochi - -var tam Tamagochi - -// Interaction function ... - -func Render(path string) string { - switch { - case tam.Health() == 0: - return "😵" // dead face - case tam.Health() < 30: - return "😷" // sick face - case tam.Happiness() < 30: - return "😢" // sad face - case tam.Hunger() > 70: - return "😫" // hungry face - default: - return "😃" // happy face - } -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/users.gno b/presentations/2025-01-09--buidleu--manfred/code/users.gno deleted file mode 100644 index f982fbd..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/users.gno +++ /dev/null @@ -1,16 +0,0 @@ -package users - -var ( - addressToUsers avl.Tree // address -> user - usersToAddress avl.Tree // user -> address -) - -func Register(name string) { - caller := std.GetOrigCaller() - if usersToAddress.Has(name) || addressToUsers.Has(caller) { - panic("address/name already registered") - } - - usersToAddress.Set(name, std.GetOrignCaller()) - addressToUsers.Set(std.GetOrignCaller(), name) -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno b/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno deleted file mode 100644 index 43cd7d5..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/users_invite.gno +++ /dev/null @@ -1,21 +0,0 @@ -package users - -var admin = "g1xxxxx..." - -var invites avl.Tree // std.Address -> true - -func AdminSendInvite(address std.Address) { - if caller := std.GetOrigCaller(); caller != admin { - panic("unauthorized") - } - invites.Set(address, true) -} - -func Register() { - caller := std.GetOrigCaller() - if !invites.Has(caller) { - panic("caller hasn't been invited") - } - // ... register caller - invites.Remove(address) -} diff --git a/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno b/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno deleted file mode 100644 index a913af8..0000000 --- a/presentations/2025-01-09--buidleu--manfred/code/wugnot.gno +++ /dev/null @@ -1,24 +0,0 @@ -package wugnot - -import ( - "std" - "strings" - - "gno.land/p/demo/grc/grc20" - "gno.land/p/demo/ufmt" - pusers "gno.land/p/demo/users" - "gno.land/r/demo/grc20reg" - "gno.land/r/demo/users" -) - -var Bank, adm = grc20.NewBank("wrapped GNOT", "wugnot", 0) - -func Deposit() { - caller := std.PrevRealm().Addr() - sent := std.GetOrigSend() - amount := sent.AmountOf("ugnot") - require(uint64(amount) >= ugnotMinDeposit, ufmt.Sprintf("Deposit below minimum: %d/%d ugnot.", amount, ugnotMinDeposit)) - checkErr(adm.Mint(caller, uint64(amount))) -} - -// Withdraw... From a45842c9b4f37ae51e7927cf79cdf62438f9164b Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:08:23 +0000 Subject: [PATCH 7/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index c904e7d..9b53a59 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,9 @@ toolchain go1.22.3 require ( github.com/campoy/embedmd v1.0.0 - github.com/gnolang/gno v0.2.0 + github.com/gnolang/gno v0.0.0-20250109171001-b60f86478da2 github.com/soypat/go-presentx v1.1.0 - golang.org/x/tools v0.23.0 + golang.org/x/tools v0.24.0 gopkg.in/yaml.v3 v3.0.1 moul.io/mdtable v1.0.0 ) @@ -17,10 +17,10 @@ require ( github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/soypat/rebed v0.2.2 // indirect - github.com/yuin/goldmark v1.4.13 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect + github.com/yuin/goldmark v1.7.2 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect moul.io/banner v1.0.1 // indirect moul.io/climan v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index 604f6a8..6a5341b 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gnolang/gno v0.2.0 h1:s33kyRByweDxxHMZMQKJtCDQpueTCYCFBqlLHwr6P+Y= -github.com/gnolang/gno v0.2.0/go.mod h1:dBaL1Au2MNLol+3FXdCv+IKLJnMKtTmIt778zsKjVu0= +github.com/gnolang/gno v0.0.0-20250109171001-b60f86478da2 h1:NSdDGlVJtDDrocvtIQ9/1CN1NpeTfcqTTTd3lvB429s= +github.com/gnolang/gno v0.0.0-20250109171001-b60f86478da2/go.mod h1:60XncI6LLLwujdl/jAX5APhSf5t3pn+PTVdK2vmbYJE= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -34,8 +34,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= +github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= @@ -51,8 +51,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -60,10 +60,10 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -71,8 +71,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20201109182053-3db8fd265862/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From b827f2e38d30d0b4fc962bb0c7b2ff3febdb60ad Mon Sep 17 00:00:00 2001 From: moul <94029+moul@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:21:33 +0000 Subject: [PATCH 8/8] chore: fixup Signed-off-by: moul <94029+moul@users.noreply.github.com> --- README.md | 7 ++++++- scripts/lint.go | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 99a3c4f..7fe484c 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,12 @@ presentations. |Date |Title |Speakers |Presentation |Recording | |---- |----- |-------- |------------ |--------- | +|2025.01.09 |Designing Seamless Interconnected dApps with Gno |[@moul](https://github.com/moul) |[Slides](https://gnolang.github.io/workshops/presentations/2025-01-09--buidleu--manfred/presentation.slide.html#1) |--- | |2024.09.23 |Distributed Communities - How to build timeless and decentralized apps, with Go |[@thehowl](https://github.com/thehowl) |[Slides](https://gnolang.github.io/workshops/presentations/2024-09-23--distributed-communities--morgan/slides.html) |[Video](https://www.youtube.com/watch?v=b3zRbVcJxyE) | |2024.08.20 |A gentle intro to gno.land |[@leohhhn](https://github.com/leohhhn) |[Slides](presentations/2024-08-20--gentle-intro-to-gnoland--leon/presentation.pdf) |[Video](https://www.youtube.com/watch?v=hTGeG0z09NU) | |2024.08.05 |Intro to gno.land |[@leohhhn](https://github.com/leohhhn) |[Slides](https://docs.google.com/presentation/d/1tnplCWxhg-RFatDS3w1iJnO0vSfBAuw2ZA0ommNJQOU/edit?usp=sharing) |--- | -|2024.07.13 |Building with Gno.land: A Practical Workshop on Smart Contracts |[@gfanton](https://github.com/gfanton) |[Slides](presentations/2024-07-13--nebular--gfanton/README.md) |[Video](https://www.youtube.com/watch?v=oBQ-t_E0QpI) | |2024.07.13 |Gno: Examples and Comparisons |[@moul](https://github.com/moul) |[Slides](https://gnolang.github.io/workshops/presentations/2024-07-13--nebular--manfred/presentation.slide.html#1) |[Video](https://www.youtube.com/watch?v=Zsl3xu_Edcc) | +|2024.07.13 |Building with Gno.land: A Practical Workshop on Smart Contracts |[@gfanton](https://github.com/gfanton) |[Slides](presentations/2024-07-13--nebular--gfanton/README.md) |[Video](https://www.youtube.com/watch?v=oBQ-t_E0QpI) | |2024.07.09 |Building a Deterministic Interpreter in Go: Readability vs Performance |[@jaekwon](https://github.com/jaekwon) |[Slides](presentations/2024-07-09--gophercon-us--jae) |[Video](https://www.youtube.com/watch?v=betUkghf_jo) | |2024.07.08 |Building a Decentralized App on gno.land |[@deelawn](https://github.com/deelawn) |[Slides](presentations/2024-07-08--gophercon-us--dylan) |[Video](https://www.youtube.com/watch?v=lwL2VyjaV-A) | |2024.06.17 |Envisioning a Go-Powered Ecosystem: The Ultimate Go Computer |[@moul](https://github.com/moul) |[Slides](presentations/2024-06-17--gophercon-berlin--manfred) |[Video](https://youtu.be/dLE2-8QPK64?si=IidxNLGrwwS6jbYL) | @@ -42,6 +43,10 @@ presentations. |2022.09.29 |Intro to Gno |[@moul](https://github.com/moul), [@pwnh4](https://github.com/pwnh4) |[Slides](https://github.com/xplrz/gnoland-workshop) |--- | |2022.09.13 |Intro to the Gno Smart Contract Platform and Blockchain |[@moul](https://github.com/moul) |[Slides](presentations/2022-09-13--berlin--manfred/slides.pdf) |[Video](https://www.youtube.com/watch?v=S36kA5RqLvs) | + + + + _This table is autogenerated based on the [./presentations](./presentations) folder._ ## Resources diff --git a/scripts/lint.go b/scripts/lint.go index 353eff4..24a80fa 100644 --- a/scripts/lint.go +++ b/scripts/lint.go @@ -32,6 +32,11 @@ func execLint(cfg *cfg) error { var dates []string for _, dir := range dirs { + // Skip special dirs + switch dir.Name() { + case "static", "templates": + continue + } // Skip non-dirs if !dir.IsDir() { continue @@ -51,8 +56,9 @@ func execLint(cfg *cfg) error { cts := string(rawContents) for _, date := range dates { + date = strings.ReplaceAll(date, "-", ".") if !strings.Contains(cts, date) { - panic("could not find some items in README table - did you run `make build`?") + panic("could not find some items in README table - did you run `make build`? (" + date + ")") } }