A journey into Gno.land
the evolution of smart contract -- Eth Seoul
3 June 2023
Manfred Touron
VP Eng., Gno.land
Manfred Touron
VP Eng., Gno.land
EVM
GnoVM, everything is Go
// realm package gno.land/r/manfred/demo var x int func Incr() { x += 1 }
// contract 0x503b6dd2fc5b285cdfef... // address, code, obfuscated. pragma solidity ^0.8.17; contract Primitives { uint x = 0; function incr() public { x += 1; } }
#[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result<Response, ContractError> { match msg { ExecuteMsg::Increment {} => increment(deps), } } pub fn increment(deps: DepsMut) -> Result<Response, ContractError> { STATE.update(deps.storage, |mut state| -> Result<_, ContractError> { state.count += 1; Ok(state) })?; Ok(Response::new().add_attribute("method", "increment")) }
func executeEnqueue(deps *std.Deps, _ types.Env, _ types.MessageInfo, enqueue *Enqueue) (*types.Response, error) { iter := deps.Storage.Range(nil, nil, std.Descending) nextKey := []byte{FirstKey} dbKey, _, err := iter.Next() if err == nil { nextKey[0] = dbKey[0] + 1 } value, err := (Item{Value: enqueue.Value}).MarshalJSON() if err != nil { return nil, err } deps.Storage.Set(nextKey, value) return &types.Response{}, nil }
// cli/cli.go, msg.go, handler.go, >keeper.go< // * keeper/handler pattern, "ctx", binary codec, determinism import ( "github.com/gnolang/gno/pkgs/sdk" ) type Keeper struct{ storeKey storetypes.StoreKey } // expected to be prefix store. func (k *Keeper) Incr(sdk.Context) { store := ctx.KVStore(k.storeKey) bz := store.Get("x") if bz == nil { panic("XXX") } x, err := strconv.Atoi(bz) if err != nil { panic("XXX") } x += 1 // all we wanted bz = strconv.Itoa(x) store.Set("x", bz) }
package counter import ( "io/ioutil" "strconv" ) func IncrementCounter() (int, error) { counterBytes, err := ioutil.ReadFile("counter.txt") if err != nil { return 0, err } counter, err := strconv.Atoi(string(counterBytes)) if err != nil { return 0, err } counter += 1 err = ioutil.WriteFile("counter.txt", []byte(strconv.Itoa(counter)), 0644) if err != nil { return 0, err } return counter, nil }
// user-defined data-structures // gno.land/p/demo/avl/node.gno type Node struct { key string value interface{} height int8 size int leftNode *Node rightNode *Node }
// gno.land/r/moul/basics/import/v1/contract.gno import ( "gno.land/p/demo/avl" "gno.land/p/demo/dom" ) func Render(path string) string { thread := dom.Plot{Name: "Hello!"} thread.AddPost("Foo", "foo foo foo") thread.AddPost("Bar", "bar bar bar") return thread.String() }
package grc721 type IGRC721 interface { BalanceOf(owner std.Address) (uint64, error) OwnerOf(tid TokenID) (std.Address, error) SafeTransferFrom(from, to std.Address, tid TokenID) error TransferFrom(from, to std.Address, tid TokenID) error Approve(approved std.Address, tid TokenID) error SetApprovalForAll(operator std.Address, approved bool) error GetApproved(tid TokenID) (std.Address, error) IsApprovedForAll(owner, operator std.Address) bool }
// from gno.land/r/demo/boards/post.gno // A Post is a "thread" or a "reply" depending on context. // A thread is a Post of a Board that holds other replies. type Post struct { board *Board id PostID creator std.Address title string // optional body string replies avl.Tree // Post.id -> *Post repliesAll avl.Tree // Post.id -> *Post (all replies, for top-level posts) reposts avl.Tree // Board.id -> Post.id threadID PostID // original Post.id parentID PostID // parent Post.id (if reply or repost) repostBoard BoardID // original Board.id (if repost) createdAt time.Time updatedAt time.Time }
r/united-builders/dex