Filter address transactions by height from-to and contract
This commit is contained in:
parent
35a13e0647
commit
a04b2b67b5
35
api/types.go
35
api/types.go
@ -74,14 +74,14 @@ func (a *Amount) AsBigInt() big.Int {
|
||||
|
||||
// ScriptSig contains input script
|
||||
type ScriptSig struct {
|
||||
Hex string `json:"hex"`
|
||||
Hex string `json:"hex,omitempty"`
|
||||
Asm string `json:"asm,omitempty"`
|
||||
}
|
||||
|
||||
// Vin contains information about single transaction input
|
||||
type Vin struct {
|
||||
Txid string `json:"txid"`
|
||||
Vout uint32 `json:"vout"`
|
||||
Txid string `json:"txid,omitempty"`
|
||||
Vout uint32 `json:"vout,omitempty"`
|
||||
Sequence int64 `json:"sequence,omitempty"`
|
||||
N int `json:"n"`
|
||||
ScriptSig ScriptSig `json:"scriptSig"`
|
||||
@ -93,7 +93,7 @@ type Vin struct {
|
||||
|
||||
// ScriptPubKey contains output script and addresses derived from it
|
||||
type ScriptPubKey struct {
|
||||
Hex string `json:"hex"`
|
||||
Hex string `json:"hex,omitempty"`
|
||||
Asm string `json:"asm,omitempty"`
|
||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||
Addresses []string `json:"addresses"`
|
||||
@ -106,7 +106,7 @@ type Vout struct {
|
||||
ValueSat *Amount `json:"value,omitempty"`
|
||||
N int `json:"n"`
|
||||
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
|
||||
Spent bool `json:"spent"`
|
||||
Spent bool `json:"spent,omitempty"`
|
||||
SpentTxID string `json:"spentTxId,omitempty"`
|
||||
SpentIndex int `json:"spentIndex,omitempty"`
|
||||
SpentHeight int `json:"spentHeight,omitempty"`
|
||||
@ -115,7 +115,7 @@ type Vout struct {
|
||||
// Erc20Token contains info about ERC20 token held by an address
|
||||
type Erc20Token struct {
|
||||
Contract string `json:"contract"`
|
||||
Txs int `json:"txs"`
|
||||
Transfers int `json:"transfers"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
Decimals int `json:"decimals"`
|
||||
@ -155,8 +155,8 @@ type Tx struct {
|
||||
Confirmations uint32 `json:"confirmations"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
Blocktime int64 `json:"blocktime"`
|
||||
ValueOutSat *Amount `json:"valueOut,omitempty"`
|
||||
Size int `json:"size,omitempty"`
|
||||
ValueOutSat *Amount `json:"valueOut,omitempty"`
|
||||
ValueInSat *Amount `json:"valueIn,omitempty"`
|
||||
FeesSat *Amount `json:"fees,omitempty"`
|
||||
Hex string `json:"hex,omitempty"`
|
||||
@ -173,14 +173,21 @@ type Paging struct {
|
||||
ItemsOnPage int `json:"itemsOnPage,omitempty"`
|
||||
}
|
||||
|
||||
// AddressFilterNone disables filtering of transactions
|
||||
const AddressFilterNone = -1
|
||||
const (
|
||||
// AddressFilterVoutOff disables filtering of transactions by vout
|
||||
AddressFilterVoutOff = -1
|
||||
// AddressFilterVoutInputs specifies that only txs where the address is as input are returned
|
||||
AddressFilterVoutInputs = -2
|
||||
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
|
||||
AddressFilterVoutOutputs = -3
|
||||
)
|
||||
|
||||
// AddressFilterInputs specifies that only txs where the address is as input are returned
|
||||
const AddressFilterInputs = -2
|
||||
|
||||
// AddressFilterOutputs specifies that only txs where the address is as output are returned
|
||||
const AddressFilterOutputs = -3
|
||||
type AddressFilter struct {
|
||||
Vout int
|
||||
Contract string
|
||||
FromHeight uint32
|
||||
ToHeight uint32
|
||||
}
|
||||
|
||||
// Address holds information about address and its transactions
|
||||
type Address struct {
|
||||
|
||||
@ -128,6 +128,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
||||
}
|
||||
}
|
||||
var valInSat, valOutSat, feesSat big.Int
|
||||
var pValInSat *big.Int
|
||||
vins := make([]Vin, len(bchainTx.Vin))
|
||||
for i := range bchainTx.Vin {
|
||||
bchainVin := &bchainTx.Vin[i]
|
||||
@ -215,6 +216,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
||||
if feesSat.Sign() == -1 {
|
||||
feesSat.SetUint64(0)
|
||||
}
|
||||
pValInSat = &valInSat
|
||||
} else if w.chainType == bchain.ChainEthereumType {
|
||||
ets, err := eth.GetErc20FromTx(bchainTx)
|
||||
if err != nil {
|
||||
@ -251,9 +253,8 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
||||
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
|
||||
}
|
||||
if len(bchainTx.Vout) > 0 {
|
||||
valInSat = bchainTx.Vout[0].ValueSat
|
||||
valOutSat = bchainTx.Vout[0].ValueSat
|
||||
}
|
||||
valOutSat = valInSat
|
||||
ethSpecific = &EthereumSpecific{
|
||||
GasLimit: ethTxData.GasLimit,
|
||||
GasPrice: (*Amount)(ethTxData.GasPrice),
|
||||
@ -280,7 +281,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
||||
Locktime: bchainTx.LockTime,
|
||||
Time: bchainTx.Time,
|
||||
Txid: bchainTx.Txid,
|
||||
ValueInSat: (*Amount)(&valInSat),
|
||||
ValueInSat: (*Amount)(pValInSat),
|
||||
ValueOutSat: (*Amount)(&valOutSat),
|
||||
Version: bchainTx.Version,
|
||||
Hex: bchainTx.Hex,
|
||||
@ -294,14 +295,14 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, filter int) ([]string, error) {
|
||||
func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, filter *AddressFilter) ([]string, error) {
|
||||
var err error
|
||||
txids := make([]string, 0, 4)
|
||||
addFilteredTxid := func(txid string, vout int32, isOutput bool) error {
|
||||
if filter == AddressFilterNone ||
|
||||
(filter == AddressFilterInputs && !isOutput) ||
|
||||
(filter == AddressFilterOutputs && isOutput) ||
|
||||
(vout == int32(filter)) {
|
||||
if filter.Vout == AddressFilterVoutOff ||
|
||||
(filter.Vout == AddressFilterVoutInputs && !isOutput) ||
|
||||
(filter.Vout == AddressFilterVoutOutputs && isOutput) ||
|
||||
(vout == int32(filter.Vout)) {
|
||||
txids = append(txids, txid)
|
||||
}
|
||||
return nil
|
||||
@ -321,7 +322,11 @@ func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool
|
||||
addFilteredTxid(m.Txid, vout, isOutput)
|
||||
}
|
||||
} else {
|
||||
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), addFilteredTxid)
|
||||
to := filter.ToHeight
|
||||
if to == 0 {
|
||||
to = ^uint32(0)
|
||||
}
|
||||
err = w.db.GetAddrDescTransactions(addrDesc, filter.FromHeight, to, addFilteredTxid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -332,7 +337,7 @@ func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool
|
||||
func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
||||
var val big.Int
|
||||
for _, vout := range t.Vout {
|
||||
if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) {
|
||||
if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) && vout.ValueSat != nil {
|
||||
val.Add(&val, (*big.Int)(vout.ValueSat))
|
||||
}
|
||||
}
|
||||
@ -342,7 +347,7 @@ func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
||||
func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
||||
var val big.Int
|
||||
for _, vin := range t.Vin {
|
||||
if bytes.Equal(vin.AddrDesc, addrDesc) {
|
||||
if bytes.Equal(vin.AddrDesc, addrDesc) && vin.ValueSat != nil {
|
||||
val.Add(&val, (*big.Int)(vin.ValueSat))
|
||||
}
|
||||
}
|
||||
@ -435,7 +440,7 @@ func computePaging(count, page, itemsOnPage int) (Paging, int, int, int) {
|
||||
}, from, to, page
|
||||
}
|
||||
|
||||
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, option GetAddressOption) (*db.AddrBalance, []Erc20Token, *bchain.Erc20Contract, uint64, error) {
|
||||
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, option GetAddressOption, filter *AddressFilter) (*db.AddrBalance, []Erc20Token, *bchain.Erc20Contract, uint64, error) {
|
||||
var (
|
||||
ba *db.AddrBalance
|
||||
erc20t []Erc20Token
|
||||
@ -462,8 +467,23 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Annotatef(err, "EthereumTypeGetNonce %v", addrDesc)
|
||||
}
|
||||
var filterDesc bchain.AddressDescriptor
|
||||
if filter.Contract != "" {
|
||||
filterDesc, err = w.chainParser.GetAddrDescFromAddress(filter.Contract)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, NewAPIError(fmt.Sprintf("Invalid contract filter, %v", err), true)
|
||||
}
|
||||
}
|
||||
erc20t = make([]Erc20Token, len(ca.Contracts))
|
||||
var j int
|
||||
for i, c := range ca.Contracts {
|
||||
if len(filterDesc) > 0 {
|
||||
if !bytes.Equal(filterDesc, c.Contract) {
|
||||
continue
|
||||
}
|
||||
// filter only transactions by this contract
|
||||
filter.Vout = i + 1
|
||||
}
|
||||
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(c.Contract)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", c.Contract)
|
||||
@ -486,16 +506,18 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||
} else {
|
||||
b = nil
|
||||
}
|
||||
erc20t[i] = Erc20Token{
|
||||
erc20t[j] = Erc20Token{
|
||||
BalanceSat: (*Amount)(b),
|
||||
Contract: ci.Contract,
|
||||
Name: ci.Name,
|
||||
Symbol: ci.Symbol,
|
||||
Txs: int(c.Txs),
|
||||
Transfers: int(c.Txs),
|
||||
Decimals: ci.Decimals,
|
||||
ContractIndex: strconv.Itoa(i + 1),
|
||||
}
|
||||
j++
|
||||
}
|
||||
erc20t = erc20t[:j]
|
||||
ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
@ -505,7 +527,7 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||
}
|
||||
|
||||
// GetAddress computes address value and gets transactions for given address
|
||||
func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetAddressOption, filter int) (*Address, error) {
|
||||
func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetAddressOption, filter *AddressFilter) (*Address, error) {
|
||||
start := time.Now()
|
||||
page--
|
||||
if page < 0 {
|
||||
@ -529,7 +551,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
|
||||
)
|
||||
if w.chainType == bchain.ChainEthereumType {
|
||||
var n uint64
|
||||
ba, erc20t, erc20c, n, err = w.getEthereumTypeAddressBalances(addrDesc, option)
|
||||
ba, erc20t, erc20c, n, err = w.getEthereumTypeAddressBalances(addrDesc, option, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -598,9 +620,6 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(txc) != int(ba.Txs) && w.chainType == bchain.ChainBitcoinType && filter == AddressFilterNone {
|
||||
glog.Warning("DB inconsistency for address ", address, ": number of txs from column addresses ", len(txc), ", from addressBalance ", ba.Txs)
|
||||
}
|
||||
for i := from; i < to; i++ {
|
||||
txid := txc[i]
|
||||
if option == TxidHistory {
|
||||
@ -674,7 +693,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
|
||||
r := make([]AddressUtxo, 0, 8)
|
||||
if !onlyConfirmed {
|
||||
// get utxo from mempool
|
||||
txm, err := w.getAddressTxids(addrDesc, true, AddressFilterNone)
|
||||
txm, err := w.getAddressTxids(addrDesc, true, &AddressFilter{Vout: AddressFilterVoutOff})
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "getAddressTxids %v true", address)
|
||||
}
|
||||
|
||||
@ -498,7 +498,7 @@ func (s *PublicServer) explorerSpendingTx(w http.ResponseWriter, r *http.Request
|
||||
func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
|
||||
var address *api.Address
|
||||
var filter string
|
||||
var fn = api.AddressFilterNone
|
||||
var fn = api.AddressFilterVoutOff
|
||||
var err error
|
||||
s.metrics.ExplorerViews.With(common.Labels{"action": "address"}).Inc()
|
||||
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||
@ -509,18 +509,18 @@ func (s *PublicServer) explorerAddress(w http.ResponseWriter, r *http.Request) (
|
||||
filter = r.URL.Query().Get("filter")
|
||||
if len(filter) > 0 {
|
||||
if filter == "inputs" {
|
||||
fn = api.AddressFilterInputs
|
||||
fn = api.AddressFilterVoutInputs
|
||||
} else if filter == "outputs" {
|
||||
fn = api.AddressFilterOutputs
|
||||
fn = api.AddressFilterVoutOutputs
|
||||
} else {
|
||||
fn, ec = strconv.Atoi(filter)
|
||||
if ec != nil || fn < 0 {
|
||||
filter = ""
|
||||
fn = api.AddressFilterNone
|
||||
fn = api.AddressFilterVoutOff
|
||||
}
|
||||
}
|
||||
}
|
||||
address, err = s.api.GetAddress(r.URL.Path[i+1:], page, txsOnPage, api.TxHistory, fn)
|
||||
address, err = s.api.GetAddress(r.URL.Path[i+1:], page, txsOnPage, api.TxHistory, &api.AddressFilter{Vout: fn})
|
||||
if err != nil {
|
||||
return errorTpl, nil, err
|
||||
}
|
||||
@ -608,7 +608,7 @@ func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (t
|
||||
http.Redirect(w, r, joinURL("/tx/", tx.Txid), 302)
|
||||
return noTpl, nil, nil
|
||||
}
|
||||
address, err = s.api.GetAddress(q, 0, 1, api.Basic, api.AddressFilterNone)
|
||||
address, err = s.api.GetAddress(q, 0, 1, api.Basic, &api.AddressFilter{Vout: api.AddressFilterVoutOff})
|
||||
if err == nil {
|
||||
http.Redirect(w, r, joinURL("/address/", address.AddrStr), 302)
|
||||
return noTpl, nil, nil
|
||||
@ -766,7 +766,7 @@ func (s *PublicServer) apiAddress(r *http.Request, apiVersion int) (interface{},
|
||||
if ec != nil {
|
||||
page = 0
|
||||
}
|
||||
address, err = s.api.GetAddress(r.URL.Path[i+1:], page, txsInAPI, api.TxidHistory, api.AddressFilterNone)
|
||||
address, err = s.api.GetAddress(r.URL.Path[i+1:], page, txsInAPI, api.TxidHistory, &api.AddressFilter{Vout: api.AddressFilterVoutOff})
|
||||
if err == nil && apiVersion == apiV1 {
|
||||
return s.api.AddressToV1(address), nil
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"scriptSig":{"hex":""},"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"value":"0.00009876"}],"vout":[{"value":"0.00009","n":0,"scriptPubKey":{"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]},"spent":false}],"blockhash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockheight":225494,"confirmations":1,"time":22549400002,"blocktime":22549400002,"valueOut":"0.00009","valueIn":"0.00009876","fees":"0.00000876","hex":""}`,
|
||||
`{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"scriptSig":{},"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"value":"0.00009876"}],"vout":[{"value":"0.00009","n":0,"scriptPubKey":{"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]},"spent":false}],"blockhash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockheight":225494,"confirmations":1,"time":22549400002,"blocktime":22549400002,"valueOut":"0.00009","valueIn":"0.00009876","fees":"0.00000876","hex":""}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -397,7 +397,7 @@ func httpTests_BitcoinType(t *testing.T, ts *httptest.Server) {
|
||||
status: http.StatusOK,
|
||||
contentType: "application/json; charset=utf-8",
|
||||
body: []string{
|
||||
`{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"scriptSig":{"hex":""},"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"value":"9876"}],"vout":[{"value":"9000","n":0,"scriptPubKey":{"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]},"spent":false}],"blockhash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockheight":225494,"confirmations":1,"time":22549400002,"blocktime":22549400002,"valueOut":"9000","valueIn":"9876","fees":"876"}`,
|
||||
`{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"scriptSig":{},"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"value":"9876"}],"vout":[{"value":"9000","n":0,"scriptPubKey":{"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]}}],"blockhash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockheight":225494,"confirmations":1,"time":22549400002,"blocktime":22549400002,"valueOut":"9000","valueIn":"9876","fees":"876"}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -284,10 +284,13 @@ func (s *WebsocketServer) onRequest(c *websocketChannel, req *websocketReq) {
|
||||
}
|
||||
|
||||
type accountInfoReq struct {
|
||||
Descriptor string `json:"descriptor"`
|
||||
Details string `json:"details"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Page int `json:"page"`
|
||||
Descriptor string `json:"descriptor"`
|
||||
Details string `json:"details"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Page int `json:"page"`
|
||||
FromHeight int `json:"from"`
|
||||
ToHeight int `json:"to"`
|
||||
ContractFilter string `json:"contractFilter"`
|
||||
}
|
||||
|
||||
func unmarshalGetAccountInfoRequest(params []byte) (*accountInfoReq, error) {
|
||||
@ -312,7 +315,13 @@ func (s *WebsocketServer) getAccountInfo(req *accountInfoReq) (res *api.Address,
|
||||
default:
|
||||
opt = api.Basic
|
||||
}
|
||||
return s.api.GetAddress(req.Descriptor, req.Page, req.PageSize, opt, api.AddressFilterNone)
|
||||
|
||||
return s.api.GetAddress(req.Descriptor, req.Page, req.PageSize, opt, &api.AddressFilter{
|
||||
FromHeight: uint32(req.FromHeight),
|
||||
ToHeight: uint32(req.ToHeight),
|
||||
Contract: req.ContractFilter,
|
||||
Vout: api.AddressFilterVoutOff,
|
||||
})
|
||||
}
|
||||
return nil, errors.New("Not implemented")
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
<tr>
|
||||
<td class="data ellipsis"><a href="/address/{{$et.Contract}}">{{$et.Name}}</a></td>
|
||||
<td class="data">{{formatAmountWithDecimals $et.BalanceSat $et.Decimals}} {{$et.Symbol}}</td>
|
||||
<td class="data">{{$et.Txs}}</td>
|
||||
<td class="data">{{$et.Transfers}}</td>
|
||||
</tr>
|
||||
{{- end -}}
|
||||
</tbody>
|
||||
|
||||
@ -102,6 +102,9 @@
|
||||
const selectDetails = document.getElementById('getAccountInfoDetails');
|
||||
const details = selectDetails.options[selectDetails.selectedIndex].value;
|
||||
const page = parseInt(document.getElementById("getAccountInfoPage").value);
|
||||
const from = parseInt(document.getElementById("getAccountInfoFrom").value);
|
||||
const to = parseInt(document.getElementById("getAccountInfoTo").value);
|
||||
const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
|
||||
const pageSize = 10;
|
||||
const method = 'getAccountInfo';
|
||||
const params = {
|
||||
@ -109,6 +112,9 @@
|
||||
details,
|
||||
page,
|
||||
pageSize,
|
||||
from,
|
||||
to,
|
||||
contractFilter
|
||||
};
|
||||
send(method, params, function (result) {
|
||||
document.getElementById('getAccountInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
|
||||
@ -257,14 +263,19 @@
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="row" style="margin: 0;">
|
||||
<input type="text" style="width: 67.7%" class="form-control" id="getAccountInfoDescriptor" value="0x103262f243e6f67d12d6a4ea0d45302c1fa4bb0a">
|
||||
<input type="text" style="width: 79%" class="form-control" id="getAccountInfoDescriptor" value="0x65513ecd11fd3a5b1fefdcc6a500b025008405a2">
|
||||
<select id="getAccountInfoDetails" style="width: 20%; margin-left: 5px;">
|
||||
<option value="basic">Basic</option>
|
||||
<option value="balance">Balance</option>
|
||||
<option value="txids">Txids</option>
|
||||
<option value="txs">Transactions</option>
|
||||
</select>
|
||||
<input type="text" style="width: 10%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoPage" value="0">
|
||||
</div>
|
||||
<div class="row" style="margin: 0; margin-top: 5px;">
|
||||
<input type="text" placeholder="page" style="width: 10%; margin-right: 5px;" class="form-control" id="getAccountInfoPage">
|
||||
<input type="text" placeholder="from" style="width: 15%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getAccountInfoFrom">
|
||||
<input type="text" placeholder="to" style="width: 15%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoTo">
|
||||
<input type="text" placeholder="contract" style="width: 55%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoContract">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col form-inline"></div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user