Search Apps Documentation Source Content File Folder Download Copy

Simple echo example with coins

This is a simple test realm contract that demonstrates how to use the banker.

See gno.land/r/demo/banktest/banktest.gno to see the original contract code.

This article will go through each line to explain how it works.

1package banktest

This package is locally named "banktest" (could be anything).

1import (
2	"std"
3)

The "std" package is defined by the gno code in stdlibs/std/. Self explanatory; and you'll see more usage from std later.

 1type activity struct {
 2	caller   std.Address
 3	sent     std.Coins
 4	returned std.Coins
 5	time     std.Time
 6}
 7
 8func (act *activity) String() string {
 9	return act.caller.String() + " " +
10		act.sent.String() + " sent, " +
11		act.returned.String() + " returned, at " +
12		std.FormatTimestamp(act.time, "2006-01-02 3:04pm MST")
13}
14
15var latest [10]*activity

This is just maintaining a list of recent activity to this contract. Notice that the "latest" variable is defined "globally" within the context of the realm with path "gno.land/r/demo/banktest".

This means that calls to functions defined within this package are encapsulated within this "data realm", where the data is mutated based on transactions that can potentially cross many realm and non-realm packge boundaries (in the call stack).

1// Deposit will take the coins (to the realm's pkgaddr) or return them to user.
2func Deposit(returnDenom string, returnAmount int64) string {
3	std.AssertOriginCall()
4	caller := std.GetOrigCaller()
5	send := std.Coins{{returnDenom, returnAmount}}

This is the beginning of the definition of the contract function named "Deposit". `std.AssertOriginCall() asserts that this function was called by a gno transactional Message. The caller is the user who signed off on this transactional message. Send is the amount of deposit sent along with this message.

 1	// record activity
 2	act := &activity{
 3		caller:   caller,
 4		sent:     std.GetOrigSend(),
 5		returned: send,
 6		time:     std.GetTimestamp(),
 7	}
 8	for i := len(latest) - 2; i >= 0; i-- {
 9		latest[i+1] = latest[i] // shift by +1.
10	}
11	latest[0] = act

Updating the "latest" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).

1	// return if any.
2	if returnAmount > 0 {

If the user requested the return of coins...

1		banker := std.GetBanker(std.BankerTypeOrigSend)

use a std.Banker instance to return any deposited coins to the original sender.

1		pkgaddr := std.GetOrigPkgAddr()
2		// TODO: use std.Coins constructors, this isn't generally safe.
3		banker.SendCoins(pkgaddr, caller, send)
4		return "returned!"

Notice that each realm package has an associated Cosmos address.

Finally, the results are rendered via an ABCI query call when you visit /r/demo/banktest:.

 1func Render(path string) string {
 2	// get realm coins.
 3	banker := std.GetBanker(std.BankerTypeReadonly)
 4	coins := banker.GetCoins(std.GetOrigPkgAddr())
 5
 6	// render
 7	res := ""
 8	res += "## recent activity\n"
 9	res += "\n"
10	for _, act := range latest {
11		if act == nil {
12			break
13		}
14		res += " * " + act.String() + "\n"
15	}
16	res += "\n"
17	res += "## total deposits\n"
18	res += coins.String()
19	return res
20}

You can call this contract yourself, by vistiing /r/demo/banktest and the quickstart guide.

- @administrator, 2024-12-21 12:51am (UTC) [reply] [repost] [x]