Skip to content

Commit

Permalink
account api: /api/v1/account/{address} (#194)
Browse files Browse the repository at this point in the history
* api: added an account api satisfying the swagger spec

* account api: using balances api balances output, no more coins

closes #174
closes #194
  • Loading branch information
notatestuser authored and forcodedancing committed May 19, 2022
1 parent d56415b commit 1682789
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 57 deletions.
4 changes: 4 additions & 0 deletions plugins/api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ func (s *server) handleNodeVersionReq() http.HandlerFunc {
return hnd.NodeVersionReqHandler(s.ctx)
}

func (s *server) handleAccountReq(cdc *wire.Codec, ctx context.CoreContext, tokens tkstore.Mapper, accStoreName string) http.HandlerFunc {
return hnd.AccountReqHandler(cdc, ctx, tokens, accStoreName)
}

func (s *server) handleSimulateReq(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
h := hnd.SimulateReqHandler(cdc, ctx)
return s.withTextPlainForm(s.limitReqSize(h))
Expand Down
83 changes: 83 additions & 0 deletions plugins/api/handlers/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package handlers

import (
"encoding/json"
"fmt"
"net/http"

"github.com/gorilla/mux"

"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"

"github.com/BiJie/BinanceChain/common/types"
tkclient "github.com/BiJie/BinanceChain/plugins/tokens/client/rest"
tkstore "github.com/BiJie/BinanceChain/plugins/tokens/store"
"github.com/BiJie/BinanceChain/wire"
)

// AccountReqHandler queries for an account and returns its information.
func AccountReqHandler(
cdc *wire.Codec, ctx context.CoreContext, tokens tkstore.Mapper, accStoreName string,
) http.HandlerFunc {
type response struct {
auth.BaseAccount
Balances []tkclient.TokenBalance `json:"balances"`
Coins *struct{} `json:"coins,omitempty"` // omit `coins`
}

responseType := "application/json"

accDecoder := authcmd.GetAccountDecoder(cdc)

throw := func(w http.ResponseWriter, status int, message string) {
w.WriteHeader(status)
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(message))
return
}

return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
bech32addr := vars["address"]

addr, err := sdk.AccAddressFromBech32(bech32addr)
if err != nil {
throw(w, http.StatusBadRequest, err.Error())
return
}

res, err := ctx.QueryStore(auth.AddressStoreKey(addr), accStoreName)
if err != nil {
errMsg := fmt.Sprintf("couldn't query account. Error: %s", err.Error())
throw(w, http.StatusInternalServerError, errMsg)
return
}

// the query will return empty if there is no data for this account
if len(res) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}

// decode the value
account, err := accDecoder(res)
if err != nil {
errMsg := fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error())
throw(w, http.StatusInternalServerError, errMsg)
return
}

bals, err := tkclient.GetBalances(cdc, ctx, tokens, account.GetAddress())
resp := response{
BaseAccount: account.(*types.AppAccount).BaseAccount,
Balances: bals,
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
json.NewEncoder(w).Encode(resp)
}
}
1 change: 1 addition & 0 deletions plugins/api/handlers/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func SimulateReqHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFu
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ func (s *server) bindRoutes() *server {
r.HandleFunc("/node_version", s.handleNodeVersionReq()).
Methods("GET")

// auth routes
r.HandleFunc(prefix+"/account/{address}", s.handleAccountReq(s.cdc, s.ctx, s.tokens, s.accStoreName)).
Methods("GET")

// tx routes
r.HandleFunc(prefix+"/simulate", s.handleSimulateReq(s.cdc, s.ctx)).
Methods("POST")
Expand Down
1 change: 1 addition & 0 deletions plugins/dex/client/rest/getdepth.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func DepthReqHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)

err = rutils.StreamDepthResponse(w, ob, limit)
Expand Down
1 change: 1 addition & 0 deletions plugins/dex/client/rest/getpairs.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func GetPairsReqHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFu
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
1 change: 1 addition & 0 deletions plugins/dex/client/rest/putorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ func PutOrderReqHandler(cdc *wire.Codec, ctx context.CoreContext, accStoreName s
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
4 changes: 2 additions & 2 deletions plugins/tokens/client/rest/getbalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func BalanceReqHandler(cdc *wire.Codec, ctx context.CoreContext, tokens tokens.M
}
type response struct {
Address string `json:"address"`
Balance tokenBalance `json:"balance"`
Balance TokenBalance `json:"balance"`
}
throw := func(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)
Expand Down Expand Up @@ -78,7 +78,7 @@ func BalanceReqHandler(cdc *wire.Codec, ctx context.CoreContext, tokens tokens.M

resp := response{
Address: vars["address"],
Balance: tokenBalance{
Balance: TokenBalance{
Symbol: params.symbol,
Free: utils.Fixed8(coins.AmountOf(params.symbol).Int64()),
Locked: utils.Fixed8(locked.Int64()),
Expand Down
58 changes: 4 additions & 54 deletions plugins/tokens/client/rest/getbalances.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package rest

import (
"fmt"
"net/http"

"github.com/gorilla/mux"

"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/BiJie/BinanceChain/common/utils"
"github.com/BiJie/BinanceChain/plugins/tokens"
"github.com/BiJie/BinanceChain/wire"
)
Expand All @@ -18,13 +16,9 @@ import (
func BalancesReqHandler(
cdc *wire.Codec, ctx context.CoreContext, tokens tokens.Mapper,
) http.HandlerFunc {
type params struct {
address sdk.AccAddress
}

type response struct {
Address string `json:"address"`
Balances []tokenBalance `json:"balances"`
Balances []TokenBalance `json:"balances"`
}
responseType := "application/json"

Expand All @@ -46,57 +40,12 @@ func BalancesReqHandler(
return
}

params := params{
address: addr,
}

coins, err := getCoinsCC(cdc, ctx, params.address)
bals, err := GetBalances(cdc, ctx, tokens, addr)
if err != nil {
throw(w, http.StatusNotFound, err)
throw(w, http.StatusInternalServerError, err)
return
}

// must do it this way because GetTokenList relies on store.Iterator
// which we can't use from a CoreContext
var denoms map[string]bool
denoms = map[string]bool{}
for _, coin := range coins {
denom := coin.Denom
exists := tokens.ExistsCC(ctx, denom)
// TODO: we probably actually want to show zero balances.
// if exists && !sdk.Int.IsZero(coins.AmountOf(denom)) {
if exists {
denoms[denom] = true
}
}

symbs := make([]string, 0, len(denoms))
bals := make([]tokenBalance, 0, len(denoms))
for symb := range denoms {
symbs = append(symbs, symb)
// count locked and frozen coins
locked := sdk.NewInt(0)
frozen := sdk.NewInt(0)
lockedc, err := getLockedCC(cdc, ctx, params.address)
if err != nil {
fmt.Println("getLockedCC error ignored, will use `0`")
} else {
locked = lockedc.AmountOf(symb)
}
frozenc, err := getFrozenCC(cdc, ctx, params.address)
if err != nil {
fmt.Println("getFrozenCC error ignored, will use `0`")
} else {
frozen = frozenc.AmountOf(symb)
}
bals = append(bals, tokenBalance{
Symbol: symb,
Free: utils.Fixed8(coins.AmountOf(symb).Int64()),
Locked: utils.Fixed8(locked.Int64()),
Frozen: utils.Fixed8(frozen.Int64()),
})
}

resp := response{
Address: vars["address"],
Balances: bals,
Expand All @@ -108,6 +57,7 @@ func BalancesReqHandler(
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
1 change: 1 addition & 0 deletions plugins/tokens/client/rest/gettoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func GetTokenReqHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFu
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
1 change: 1 addition & 0 deletions plugins/tokens/client/rest/gettokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func GetTokensReqHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerF
return
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", responseType)
w.Write(output)
}
Expand Down
57 changes: 56 additions & 1 deletion plugins/tokens/client/rest/helpers.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,78 @@
package rest

import (
"fmt"

"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"

"github.com/BiJie/BinanceChain/common"
"github.com/BiJie/BinanceChain/common/types"
"github.com/BiJie/BinanceChain/common/utils"
"github.com/BiJie/BinanceChain/plugins/tokens"
"github.com/BiJie/BinanceChain/wire"
)

type tokenBalance struct {
type TokenBalance struct {
Symbol string `json:"symbol"`
Free utils.Fixed8 `json:"free"`
Locked utils.Fixed8 `json:"locked"`
Frozen utils.Fixed8 `json:"frozen"`
}

func GetBalances(
cdc *wire.Codec, ctx context.CoreContext, tokens tokens.Mapper, addr sdk.AccAddress,
) ([]TokenBalance, error) {
coins, err := getCoinsCC(cdc, ctx, addr)
if err != nil {
return nil, err
}

// must do it this way because GetTokenList relies on store.Iterator
// which we can't use from a CoreContext
var denoms map[string]bool
denoms = map[string]bool{}
for _, coin := range coins {
denom := coin.Denom
exists := tokens.ExistsCC(ctx, denom)
// TODO: we probably actually want to show zero balances.
// if exists && !sdk.Int.IsZero(coins.AmountOf(denom)) {
if exists {
denoms[denom] = true
}
}

symbs := make([]string, 0, len(denoms))
bals := make([]TokenBalance, 0, len(denoms))
for symb := range denoms {
symbs = append(symbs, symb)
// count locked and frozen coins
locked := sdk.NewInt(0)
frozen := sdk.NewInt(0)
lockedc, err := getLockedCC(cdc, ctx, addr)
if err != nil {
fmt.Println("getLockedCC error ignored, will use `0`")
} else {
locked = lockedc.AmountOf(symb)
}
frozenc, err := getFrozenCC(cdc, ctx, addr)
if err != nil {
fmt.Println("getFrozenCC error ignored, will use `0`")
} else {
frozen = frozenc.AmountOf(symb)
}
bals = append(bals, TokenBalance{
Symbol: symb,
Free: utils.Fixed8(coins.AmountOf(symb).Int64()),
Locked: utils.Fixed8(locked.Int64()),
Frozen: utils.Fixed8(frozen.Int64()),
})
}

return bals, nil
}

func decodeAccount(cdc *wire.Codec, bz *[]byte) (acc auth.Account, err error) {
err = cdc.UnmarshalBinaryBare(*bz, &acc)
if err != nil {
Expand Down

0 comments on commit 1682789

Please sign in to comment.