Add tokens to return level choice to websocket interface
This commit is contained in:
parent
e54998dccc
commit
1c35c632cb
26
api/types.go
26
api/types.go
@ -204,8 +204,8 @@ type Paging struct {
|
|||||||
ItemsOnPage int `json:"itemsOnPage,omitempty"`
|
ItemsOnPage int `json:"itemsOnPage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenDetailLevel specifies detail level of tokens returned by GetAddress and GetXpubAddress
|
// TokensToReturn specifies what tokens are returned by GetAddress and GetXpubAddress
|
||||||
type TokenDetailLevel int
|
type TokensToReturn int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// AddressFilterVoutOff disables filtering of transactions by vout
|
// AddressFilterVoutOff disables filtering of transactions by vout
|
||||||
@ -215,21 +215,21 @@ const (
|
|||||||
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
|
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
|
||||||
AddressFilterVoutOutputs = -3
|
AddressFilterVoutOutputs = -3
|
||||||
|
|
||||||
// TokenDetailNonzeroBalance - use to return only tokens with nonzero balance
|
// TokensToReturnNonzeroBalance - return only tokens with nonzero balance
|
||||||
TokenDetailNonzeroBalance TokenDetailLevel = 0
|
TokensToReturnNonzeroBalance TokensToReturn = 0
|
||||||
// TokenDetailUsed - use to return tokens with some transfers (even if they have zero balance now)
|
// TokensToReturnUsed - return tokens with some transfers (even if they have zero balance now)
|
||||||
TokenDetailUsed TokenDetailLevel = 1
|
TokensToReturnUsed TokensToReturn = 1
|
||||||
// TokenDetailDiscovered - use to return all discovered tokens
|
// TokensToReturnDerived - return all derived tokens
|
||||||
TokenDetailDiscovered TokenDetailLevel = 2
|
TokensToReturnDerived TokensToReturn = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddressFilter is used to filter data returned from GetAddress api method
|
// AddressFilter is used to filter data returned from GetAddress api method
|
||||||
type AddressFilter struct {
|
type AddressFilter struct {
|
||||||
Vout int
|
Vout int
|
||||||
Contract string
|
Contract string
|
||||||
FromHeight uint32
|
FromHeight uint32
|
||||||
ToHeight uint32
|
ToHeight uint32
|
||||||
TokenLevel TokenDetailLevel
|
TokensToReturn TokensToReturn
|
||||||
// OnlyConfirmed set to true will ignore mempool transactions; mempool is also ignored if FromHeight/ToHeight filter is specified
|
// OnlyConfirmed set to true will ignore mempool transactions; mempool is also ignored if FromHeight/ToHeight filter is specified
|
||||||
OnlyConfirmed bool
|
OnlyConfirmed bool
|
||||||
}
|
}
|
||||||
|
|||||||
@ -906,6 +906,9 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) (Utxos, erro
|
|||||||
return nil, NewAPIError(fmt.Sprintf("Invalid address '%v', %v", address, err), true)
|
return nil, NewAPIError(fmt.Sprintf("Invalid address '%v', %v", address, err), true)
|
||||||
}
|
}
|
||||||
r, err := w.getAddrDescUtxo(addrDesc, nil, onlyConfirmed, false)
|
r, err := w.getAddrDescUtxo(addrDesc, nil, onlyConfirmed, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
glog.Info("GetAddressUtxo ", address, ", ", len(r), " utxos, finished in ", time.Since(start))
|
glog.Info("GetAddressUtxo ", address, ", ", len(r), " utxos, finished in ", time.Since(start))
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -502,9 +502,9 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
|
|||||||
}
|
}
|
||||||
if option > AccountDetailsBasic {
|
if option > AccountDetailsBasic {
|
||||||
token := w.tokenFromXpubAddress(data, ad, ci, i, option)
|
token := w.tokenFromXpubAddress(data, ad, ci, i, option)
|
||||||
if filter.TokenLevel == TokenDetailDiscovered ||
|
if filter.TokensToReturn == TokensToReturnDerived ||
|
||||||
filter.TokenLevel == TokenDetailUsed && ad.balance != nil ||
|
filter.TokensToReturn == TokensToReturnUsed && ad.balance != nil ||
|
||||||
filter.TokenLevel == TokenDetailNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
|
filter.TokensToReturn == TokensToReturnNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
|
||||||
tokens = append(tokens, token)
|
tokens = append(tokens, token)
|
||||||
}
|
}
|
||||||
xpubAddresses[token.Name] = struct{}{}
|
xpubAddresses[token.Name] = struct{}{}
|
||||||
|
|||||||
@ -607,7 +607,7 @@ func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (
|
|||||||
return addressTpl, data, nil
|
return addressTpl, data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int, option api.AccountDetails) (*api.Address, api.TokenDetailLevel, error) {
|
func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int, option api.AccountDetails) (*api.Address, api.TokensToReturn, error) {
|
||||||
var fn = api.AddressFilterVoutOff
|
var fn = api.AddressFilterVoutOff
|
||||||
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
|
page, ec := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
if ec != nil {
|
if ec != nil {
|
||||||
@ -622,7 +622,6 @@ func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int
|
|||||||
} else {
|
} else {
|
||||||
fn, ec = strconv.Atoi(filter)
|
fn, ec = strconv.Atoi(filter)
|
||||||
if ec != nil || fn < 0 {
|
if ec != nil || fn < 0 {
|
||||||
filter = ""
|
|
||||||
fn = api.AddressFilterVoutOff
|
fn = api.AddressFilterVoutOff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,26 +630,26 @@ func (s *PublicServer) getXpubAddress(r *http.Request, xpub string, pageSize int
|
|||||||
if ec != nil {
|
if ec != nil {
|
||||||
gap = 0
|
gap = 0
|
||||||
}
|
}
|
||||||
tokenLevel := api.TokenDetailNonzeroBalance
|
tokensToReturn := api.TokensToReturnNonzeroBalance
|
||||||
switch r.URL.Query().Get("tokenlevel") {
|
switch r.URL.Query().Get("tokens") {
|
||||||
case "discovered":
|
case "derived":
|
||||||
tokenLevel = api.TokenDetailDiscovered
|
tokensToReturn = api.TokensToReturnDerived
|
||||||
case "used":
|
case "used":
|
||||||
tokenLevel = api.TokenDetailUsed
|
tokensToReturn = api.TokensToReturnUsed
|
||||||
case "nonzero":
|
case "nonzero":
|
||||||
tokenLevel = api.TokenDetailNonzeroBalance
|
tokensToReturn = api.TokensToReturnNonzeroBalance
|
||||||
}
|
}
|
||||||
a, err := s.api.GetXpubAddress(xpub, page, pageSize, option, &api.AddressFilter{Vout: fn, TokenLevel: tokenLevel}, gap)
|
a, err := s.api.GetXpubAddress(xpub, page, pageSize, option, &api.AddressFilter{Vout: fn, TokensToReturn: tokensToReturn}, gap)
|
||||||
return a, tokenLevel, err
|
return a, tokensToReturn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
||||||
var address *api.Address
|
var address *api.Address
|
||||||
var tokenLevel api.TokenDetailLevel
|
var tokensToReturn api.TokensToReturn
|
||||||
var err error
|
var err error
|
||||||
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
|
s.metrics.ExplorerViews.With(common.Labels{"action": "xpub"}).Inc()
|
||||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
address, tokenLevel, err = s.getXpubAddress(r, r.URL.Path[i+1:], txsOnPage, api.AccountDetailsTxHistoryLight)
|
address, tokensToReturn, err = s.getXpubAddress(r, r.URL.Path[i+1:], txsOnPage, api.AccountDetailsTxHistoryLight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorTpl, nil, err
|
return errorTpl, nil, err
|
||||||
}
|
}
|
||||||
@ -665,7 +664,7 @@ func (s *PublicServer) explorerXpub(w http.ResponseWriter, r *http.Request) (tpl
|
|||||||
data.PageParams = template.URL("&filter=" + filter)
|
data.PageParams = template.URL("&filter=" + filter)
|
||||||
data.Address.Filter = filter
|
data.Address.Filter = filter
|
||||||
}
|
}
|
||||||
data.NonZeroBalanceTokens = tokenLevel == api.TokenDetailNonzeroBalance
|
data.NonZeroBalanceTokens = tokensToReturn == api.TokensToReturnNonzeroBalance
|
||||||
return xpubTpl, data, nil
|
return xpubTpl, data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -461,7 +461,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "apiXpub v2 tokenlevel=nonzero",
|
name: "apiXpub v2 tokens=nonzero",
|
||||||
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub),
|
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub),
|
||||||
status: http.StatusOK,
|
status: http.StatusOK,
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
@ -470,8 +470,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "apiXpub v2 tokenlevel=used",
|
name: "apiXpub v2 tokens=used",
|
||||||
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokenlevel=used"),
|
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=used"),
|
||||||
status: http.StatusOK,
|
status: http.StatusOK,
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
body: []string{
|
body: []string{
|
||||||
@ -479,8 +479,8 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "apiXpub v2 tokenlevel=discovered",
|
name: "apiXpub v2 tokens=derived",
|
||||||
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokenlevel=discovered"),
|
r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=derived"),
|
||||||
status: http.StatusOK,
|
status: http.StatusOK,
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
body: []string{
|
body: []string{
|
||||||
|
|||||||
@ -330,6 +330,7 @@ func (s *WebsocketServer) onRequest(c *websocketChannel, req *websocketReq) {
|
|||||||
type accountInfoReq struct {
|
type accountInfoReq struct {
|
||||||
Descriptor string `json:"descriptor"`
|
Descriptor string `json:"descriptor"`
|
||||||
Details string `json:"details"`
|
Details string `json:"details"`
|
||||||
|
Tokens string `json:"tokens"`
|
||||||
PageSize int `json:"pageSize"`
|
PageSize int `json:"pageSize"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page"`
|
||||||
FromHeight int `json:"from"`
|
FromHeight int `json:"from"`
|
||||||
@ -360,12 +361,21 @@ func (s *WebsocketServer) getAccountInfo(req *accountInfoReq) (res *api.Address,
|
|||||||
default:
|
default:
|
||||||
opt = api.AccountDetailsBasic
|
opt = api.AccountDetailsBasic
|
||||||
}
|
}
|
||||||
|
var tokensToReturn api.TokensToReturn
|
||||||
|
switch req.Tokens {
|
||||||
|
case "used":
|
||||||
|
tokensToReturn = api.TokensToReturnUsed
|
||||||
|
case "nonzero":
|
||||||
|
tokensToReturn = api.TokensToReturnNonzeroBalance
|
||||||
|
default:
|
||||||
|
tokensToReturn = api.TokensToReturnDerived
|
||||||
|
}
|
||||||
filter := api.AddressFilter{
|
filter := api.AddressFilter{
|
||||||
FromHeight: uint32(req.FromHeight),
|
FromHeight: uint32(req.FromHeight),
|
||||||
ToHeight: uint32(req.ToHeight),
|
ToHeight: uint32(req.ToHeight),
|
||||||
Contract: req.ContractFilter,
|
Contract: req.ContractFilter,
|
||||||
Vout: api.AddressFilterVoutOff,
|
Vout: api.AddressFilterVoutOff,
|
||||||
TokenLevel: api.TokenDetailDiscovered,
|
TokensToReturn: tokensToReturn,
|
||||||
}
|
}
|
||||||
a, err := s.api.GetXpubAddress(req.Descriptor, req.Page, req.PageSize, opt, &filter, 0)
|
a, err := s.api.GetXpubAddress(req.Descriptor, req.Page, req.PageSize, opt, &filter, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $data.NonZeroBalanceTokens -}}
|
{{- if $data.NonZeroBalanceTokens -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4"><a href="?tokenlevel=used">Show all XPUB addresses</a></td>
|
<td colspan="4"><a href="?tokens=used">Show all XPUB addresses</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@ -125,9 +125,11 @@
|
|||||||
const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
|
const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const method = 'getAccountInfo';
|
const method = 'getAccountInfo';
|
||||||
|
const tokens = "derived"; // could be "nonzero", "used", default is "derived" i.e. all
|
||||||
const params = {
|
const params = {
|
||||||
descriptor,
|
descriptor,
|
||||||
details,
|
details,
|
||||||
|
tokens,
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
from,
|
from,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user