Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple tokens (GRC20 + Banker) #14

Open
wants to merge 12 commits into
base: multiple_tokens_payment
Choose a base branch
from
1 change: 1 addition & 0 deletions examples/gno.land/p/demo/teritori/token_registry/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/demo/teritori/token_registry
173 changes: 173 additions & 0 deletions examples/gno.land/p/demo/teritori/token_registry/registry.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package token_registry

import (
"std"

"gno.land/r/demo/users"
)

type Registry struct {
registered []TokenInfo
manager string
}

func New(manager string) *Registry {
r := Registry{
registered: []TokenInfo{},
manager: manager,
}
return &r
}

type GRC20Interface interface {
Transfer() func(to users.AddressOrName, amount uint64)
TransferFrom() func(from, to users.AddressOrName, amount uint64)
BalanceOf() func(owner users.AddressOrName) uint64
}

type TokenInfo struct {
isBank bool
token string // pkgPath (GRC20) | denom (Bank)
igrc20 GRC20Interface // only valid when isBank is false
}

func (r Registry) findToken(token string) (int, bool) {
for i, pair := range r.registered {
if pair.token == token {
return i, true
}
}

return -1, false
}

func (r *Registry) appendGRC20Interface(pkgPath string, igrc20 GRC20Interface) {
r.registered = append(r.registered, TokenInfo{isBank: false, token: pkgPath, igrc20: igrc20})
}

func (r *Registry) appendBankToken(denom string) {
r.registered = append(r.registered, TokenInfo{isBank: true, token: denom})
}

func (r *Registry) removeToken(token string) {
i, found := r.findToken(token)
if !found {
return
}

r.registered = append(r.registered[:i], r.registered[i+1:]...)
}

func (r *Registry) RegisterGRC20Interface(token string, igrc20 GRC20Interface) {
_, found := r.findToken(token)
if found {
panic("GRC20 already registered")
}

r.appendGRC20Interface(token, igrc20)
}

func (r *Registry) UnregisterToken(token string) {
// do not allow realm to unregister
std.AssertOriginCall()
caller := std.GetOrigCaller()

if caller != r.manager {
panic("unauthorized")
}

_, found := r.findToken(token)
if found {
r.removeToken(token)
}
}

func (r *Registry) RegisterBankToken(denom string) {
_, found := r.findToken(denom)
if found {
panic("Token already registered")
}

r.appendBankToken(denom)
}

func (r Registry) TransferByInterfaceName(token string, to std.Address, amount uint64) bool {
i, found := r.findToken(token)
if !found {
return false
}

if r.registered[i].isBank {
banker := std.GetBanker(std.BankerTypeRealmSend)

coin := std.Coins{{token, int64(amount)}}
realmAddr := std.GetOrigPkgAddr()

// Send coin from realm
banker.SendCoins(realmAddr, to, coin)
return true
}
r.registered[i].igrc20.Transfer()(users.AddressOrName(to), amount)

return true
}

func (r Registry) TransferFromByInterfaceName(token string, from, to std.Address, amount uint64) bool {
i, found := r.findToken(token)
if !found {
return false
}

if r.registered[i].isBank {
coinSent := std.GetOrigSend() // get Coins sent with call
caller := std.GetOrigCaller() // get tx sender

if len(coinSent) != 1 {
panic("only one coin can be sent")
}

if int64(amount) != coinSent.AmountOf(r.registered[i].token) {
panic("invalid amount sent")
}

if caller.String() != from {
panic("only caller should be configured for banker TransferFrom")
}

realmAddr := std.GetOrigPkgAddr()
if to.String() != realmAddr.String() {
// Send coin from realm to target
banker := std.GetBanker(std.BankerTypeOrigSend)
coin := std.Coins{{token, int64(amount)}}
banker.SendCoins(realmAddr, to, coin)
}
return true
}
r.registered[i].igrc20.TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount)

return true
}

func (r Registry) BalanceOfByInterfaceName(token string, owner std.Address) uint64 {
i, found := r.findToken(token)
if !found {
return 0
}

if r.registered[i].isBank {
banker := std.GetBanker(std.BankerTypeReadonly)
coins := banker.GetCoins(owner)
for _, coin := range coins {
if coin.Denom == token {
return uint64(coin.Amount)
}
}
return 0
}
balance := r.registered[i].igrc20.BalanceOf()(users.AddressOrName(owner))
return balance
}

func (r Registry) RegisteredTokens() []TokenInfo {
return r.registered
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/bin/sh

gnokey add gopher
- addr: g1x2xyqca98auaw9lnat2h9ycd4lx3w0jer9vjmt

gnokey add gopher2
- addr: g1c5y8jpe585uezcvlmgdjmk5jt2glfw88wxa3xq

TERITORI=g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5
GOPHER=g1x2xyqca98auaw9lnat2h9ycd4lx3w0jer9vjmt

# check balance
gnokey query bank/balances/$TERITORI -remote="51.15.236.215:26657"

gnokey maketx addpkg \
-deposit="1ugnot" \
-gas-fee="1ugnot" \
-gas-wanted="5000000" \
-broadcast="true" \
-remote="51.15.236.215:26657" \
-chainid="teritori-1" \
-pkgdir="./examples/gno.land/p/demo/teritori/token_registry" \
-pkgpath="gno.land/p/demo/teritori/token_registry_3" \
teritori

# # Register Bank token
# gnokey maketx call \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/registry_02" \
# -func="RegisterBankToken" \
# -args="ugnot" \
# teritori

# # Register GRC20 token while deploying
# gnokey maketx addpkg \
# -deposit="1ugnot" \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgdir="./examples/gno.land/r/x/grc20_dynamic_call/bar" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/bar" \
# teritori

# gnokey maketx addpkg \
# -deposit="1ugnot" \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgdir="./examples/gno.land/r/x/grc20_dynamic_call/foo" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/foo" \
# teritori

# # Get Faucet
# gnokey maketx call \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/foo" \
# -func="Faucet" \
# teritori

# # Transfer to realm
# gnokey maketx call \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/foo" \
# -func="Transfer" \
# -args="g19ffr0zd3ad8n4tr7rxff6dte8dxxss2sleajc5" \
# -args="5000000" \
# teritori

# # Deploy baz
# gnokey maketx addpkg \
# -deposit="1ugnot" \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgdir="./examples/gno.land/r/x/grc20_dynamic_call/baz" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/baz" \
# teritori

# # Deploy wrapper & register to registry
# gnokey maketx addpkg \
# -deposit="1ugnot" \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgdir="./examples/gno.land/r/x/grc20_dynamic_call/wrapper" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/wrapper" \
# teritori

# # Transfer ugnot (0.1GNOT to TERITORI)
# gnokey maketx call \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/registry_02" \
# -func="TransferByInterfaceName" \
# -args="ugnot" \
# -args="$TERITORI" \
# -args="100000" \
# teritori

# # Transfer foo (0.1FOO to TERITORI)
# gnokey maketx call \
# -gas-fee="1ugnot" \
# -gas-wanted="5000000" \
# -broadcast="true" \
# -remote="51.15.236.215:26657" \
# -chainid="teritori-1" \
# -pkgpath="gno.land/r/x/grc20_dynamic_call/registry_02" \
# -func="TransferByInterfaceName" \
# -args="foo" \
# -args="$TERITORI" \
# -args="100000" \
# teritori

# # Query RealmAddr
# gnokey query "vm/qeval" -data="gno.land/r/x/grc20_dynamic_call/registry_02
# RealmAddr()" -remote="51.15.236.215:26657"

# gnokey query "vm/qeval" -data="gno.land/r/x/grc20_dynamic_call/registry_02
# BalanceOfByInterfaceName(\"ugnot\",\"g19ffr0zd3ad8n4tr7rxff6dte8dxxss2sleajc5\")" -remote="51.15.236.215:26657"

# gnokey query "vm/qeval" -data="gno.land/r/x/grc20_dynamic_call/registry_02
# BalanceOfByInterfaceName(\"foo\",\"g19ffr0zd3ad8n4tr7rxff6dte8dxxss2sleajc5\")" -remote="51.15.236.215:26657"
Loading
Loading