cli: implement NEP5 balance querying

This commit is contained in:
Evgenii Stratonikov 2020-03-05 19:31:35 +03:00
parent 519b27fe0e
commit bcc03e2068

View file

@ -1,8 +1,10 @@
package wallet package wallet
import ( import (
"errors"
"fmt" "fmt"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpc/client" "github.com/nspcc-dev/neo-go/pkg/rpc/client"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
@ -11,6 +13,25 @@ import (
func newNEP5Commands() []cli.Command { func newNEP5Commands() []cli.Command {
return []cli.Command{ return []cli.Command{
{
Name: "balance",
Usage: "get address balance",
UsageText: "balance --path <path> --rpc <node> --addr <addr> [--token <hash-or-name>]",
Action: getNEP5Balance,
Flags: []cli.Flag{
walletPathFlag,
rpcFlag,
timeoutFlag,
cli.StringFlag{
Name: "addr",
Usage: "Address to use",
},
cli.StringFlag{
Name: "token",
Usage: "Token to use",
},
},
},
{ {
Name: "import", Name: "import",
Usage: "import NEP5 token to a wallet", Usage: "import NEP5 token to a wallet",
@ -28,6 +49,99 @@ func newNEP5Commands() []cli.Command {
} }
} }
func getNEP5Balance(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("path"))
if err != nil {
return cli.NewExitError(err, 1)
}
defer wall.Close()
addr := ctx.String("addr")
addrHash, err := address.StringToUint160(addr)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid address: %v", err), 1)
}
acc := wall.GetAccount(addrHash)
if acc == nil {
return cli.NewExitError(fmt.Errorf("can't find account for the address: %s", addr), 1)
}
gctx, cancel := getGoContext(ctx)
defer cancel()
c, err := client.New(gctx, ctx.String("rpc"), client.Options{})
if err != nil {
return cli.NewExitError(err, 1)
}
var token *wallet.Token
name := ctx.String("token")
if name != "" {
token, err = getMatchingToken(wall, name)
if err != nil {
token, err = getMatchingTokenRPC(c, addrHash, name)
if err != nil {
return cli.NewExitError(err, 1)
}
}
}
balances, err := c.GetNEP5Balances(addrHash)
if err != nil {
return cli.NewExitError(err, 1)
}
for i := range balances.Balances {
asset := balances.Balances[i].Asset
if name != "" && !token.Hash.Equals(asset) {
continue
}
fmt.Printf("TokenHash: %s\n", asset)
fmt.Printf("\tAmount : %s\n", balances.Balances[i].Amount)
fmt.Printf("\tUpdated: %d\n", balances.Balances[i].LastUpdated)
}
return nil
}
func getMatchingToken(w *wallet.Wallet, name string) (*wallet.Token, error) {
return getMatchingTokenAux(func(i int) *wallet.Token {
return w.Extra.Tokens[i]
}, len(w.Extra.Tokens), name)
}
func getMatchingTokenRPC(c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) {
bs, err := c.GetNEP5Balances(addr)
if err != nil {
return nil, err
}
get := func(i int) *wallet.Token {
t, _ := c.NEP5TokenInfo(bs.Balances[i].Asset)
return t
}
return getMatchingTokenAux(get, len(bs.Balances), name)
}
func getMatchingTokenAux(get func(i int) *wallet.Token, n int, name string) (*wallet.Token, error) {
var token *wallet.Token
var count int
for i := 0; i < n; i++ {
t := get(i)
if t != nil && (t.Name == name || t.Symbol == name || t.Address == name || t.Hash.StringLE() == name) {
if count == 1 {
printTokenInfo(token)
printTokenInfo(t)
return nil, errors.New("multiple matching tokens found")
}
count++
token = t
}
}
if count == 0 {
return nil, errors.New("token was not found")
}
return token, nil
}
func importNEP5Token(ctx *cli.Context) error { func importNEP5Token(ctx *cli.Context) error {
wall, err := openWallet(ctx.String("path")) wall, err := openWallet(ctx.String("path"))
if err != nil { if err != nil {