cli: print zero balance of known token if token flag specified

Close #2313.
This commit is contained in:
AnnaShaleva 2021-12-27 16:29:35 +03:00 committed by Anna Shaleva
parent 501ca0dedb
commit cf3ec6d9ac
2 changed files with 78 additions and 8 deletions

View file

@ -49,6 +49,16 @@ func TestNEP17Balance(t *testing.T) {
b := e.Chain.GetUtilityTokenBalance(validatorHash) b := e.Chain.GetUtilityTokenBalance(validatorHash)
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$") e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
}) })
t.Run("zero balance of known token", func(t *testing.T) {
e.Run(t, append(cmdbase, []string{"--token", "NEO"}...)...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
require.NoError(t, err)
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr1))
e.checkNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
e.checkNextLine(t, "^\\s*Updated:")
e.checkNextLine(t, "^\\s*$")
})
t.Run("all accounts", func(t *testing.T) { t.Run("all accounts", func(t *testing.T) {
e.Run(t, cmdbase...) e.Run(t, cmdbase...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn") addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")

View file

@ -11,9 +11,11 @@ import (
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
"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/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"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"
@ -188,6 +190,7 @@ func getNEP17Balance(ctx *cli.Context) error {
} }
fmt.Fprintf(ctx.App.Writer, "Account %s\n", acc.Address) fmt.Fprintf(ctx.App.Writer, "Account %s\n", acc.Address)
var tokenFound bool
for i := range balances.Balances { for i := range balances.Balances {
var tokenName, tokenSymbol string var tokenName, tokenSymbol string
tokenDecimals := 0 tokenDecimals := 0
@ -203,27 +206,84 @@ func getNEP17Balance(ctx *cli.Context) error {
tokenName = token.Name tokenName = token.Name
tokenSymbol = token.Symbol tokenSymbol = token.Symbol
tokenDecimals = int(token.Decimals) tokenDecimals = int(token.Decimals)
tokenFound = true
} else { } else {
if name != "" { if name != "" {
continue continue
} }
tokenSymbol = "UNKNOWN" tokenSymbol = "UNKNOWN"
} }
fmt.Fprintf(ctx.App.Writer, "%s: %s (%s)\n", tokenSymbol, tokenName, asset.StringLE()) printAssetBalance(ctx, asset, tokenName, tokenSymbol, tokenDecimals, balances.Balances[i])
amount := balances.Balances[i].Amount }
if tokenDecimals != 0 { if name == "" || tokenFound {
b, ok := new(big.Int).SetString(amount, 10) continue
if ok { }
amount = fixedn.ToString(b, tokenDecimals) // Token was explicitly specified, but was not found among balances, thus either balance is 0
// or the token doesn't exist. Try to find token by its address/hash/name/symbol and print zero
// balance if found. Search into wallet first.
token, err := getMatchingToken(ctx, wall, name, manifest.NEP17StandardName)
if err != nil {
// The wallet doesn't contain specified token, so try to ask chain.
h, err := flags.ParseAddress(name)
if err != nil {
h, err = c.GetNativeContractHash(name)
if err != nil {
// Try to get native NEP17 with matching symbol.
var gasSymbol, neoSymbol string
gasSymbol, h, err = getNativeNEP17Symbol(c, nativenames.Gas)
if err != nil {
continue
}
if gasSymbol != name {
neoSymbol, h, err = getNativeNEP17Symbol(c, nativenames.Neo)
if err != nil {
continue
}
if neoSymbol != name {
continue
}
}
} }
} }
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", amount) token, err = c.NEP17TokenInfo(h)
fmt.Fprintf(ctx.App.Writer, "\tUpdated: %d\n", balances.Balances[i].LastUpdated) if err != nil {
continue
}
} }
printAssetBalance(ctx, token.Hash, token.Name, token.Symbol, int(token.Decimals), result.NEP17Balance{
Asset: token.Hash,
Amount: "0",
LastUpdated: 0,
})
} }
return nil return nil
} }
func printAssetBalance(ctx *cli.Context, asset util.Uint160, tokenName, tokenSymbol string, tokenDecimals int, balance result.NEP17Balance) {
fmt.Fprintf(ctx.App.Writer, "%s: %s (%s)\n", tokenSymbol, tokenName, asset.StringLE())
amount := balance.Amount
if tokenDecimals != 0 {
b, ok := new(big.Int).SetString(amount, 10)
if ok {
amount = fixedn.ToString(b, tokenDecimals)
}
}
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", amount)
fmt.Fprintf(ctx.App.Writer, "\tUpdated: %d\n", balance.LastUpdated)
}
func getNativeNEP17Symbol(c *client.Client, name string) (string, util.Uint160, error) {
h, err := c.GetNativeContractHash(name)
if err != nil {
return "", util.Uint160{}, fmt.Errorf("failed to get native %s hash: %w", name, err)
}
symbol, err := c.NEP17Symbol(h)
if err != nil {
return "", util.Uint160{}, fmt.Errorf("failed to get native %s symbol: %w", name, err)
}
return symbol, h, nil
}
func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string, standard string) (*wallet.Token, error) { func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string, standard string) (*wallet.Token, error) {
return getMatchingTokenAux(ctx, func(i int) *wallet.Token { return getMatchingTokenAux(ctx, func(i int) *wallet.Token {
return w.Extra.Tokens[i] return w.Extra.Tokens[i]