From 6f294a6241312e3b3f33598bd461ab9594c95eb6 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Tue, 10 Dec 2019 21:08:27 +0100 Subject: [PATCH] Add get balance history for ethereum type coins --- api/worker.go | 95 ++++++++++++++++++++++++++++------- bchain/coins/eth/erc20.go | 12 ++--- bchain/coins/eth/ethparser.go | 9 ++++ 3 files changed, 93 insertions(+), 23 deletions(-) diff --git a/api/worker.go b/api/worker.go index 86396f8c..f92a5eea 100644 --- a/api/worker.go +++ b/api/worker.go @@ -818,15 +818,34 @@ func (w *Worker) balanceHistoryHeightsFromTo(fromTime, toTime time.Time) (uint32 } func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid string, fromUnix, toUnix uint32) (*BalanceHistory, error) { - ta, err := w.db.GetTxAddresses(txid) - if err != nil { - return nil, err + var time uint32 + var err error + var ta *db.TxAddresses + var bchainTx *bchain.Tx + var height uint32 + if w.chainType == bchain.ChainBitcoinType { + ta, err = w.db.GetTxAddresses(txid) + if err != nil { + return nil, err + } + if ta == nil { + glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses") + return nil, nil + } + height = ta.Height + } else if w.chainType == bchain.ChainEthereumType { + var h int + bchainTx, h, err = w.txCache.GetTransaction(txid) + if err != nil { + return nil, err + } + if bchainTx == nil { + glog.Warning("Inconsistency: tx ", txid, ": not found in the blockchain") + return nil, nil + } + height = uint32(h) } - if ta == nil { - glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses") - return nil, nil - } - time := w.is.GetBlockTime(ta.Height) + time = w.is.GetBlockTime(height) if time < fromUnix || time >= toUnix { return nil, nil } @@ -837,16 +856,58 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s ReceivedSat: &Amount{}, Txid: txid, } - for i := range ta.Inputs { - tai := &ta.Inputs[i] - if bytes.Equal(addrDesc, tai.AddrDesc) { - (*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &tai.ValueSat) + if w.chainType == bchain.ChainBitcoinType { + for i := range ta.Inputs { + tai := &ta.Inputs[i] + if bytes.Equal(addrDesc, tai.AddrDesc) { + (*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &tai.ValueSat) + } } - } - for i := range ta.Outputs { - tao := &ta.Outputs[i] - if bytes.Equal(addrDesc, tao.AddrDesc) { - (*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &tao.ValueSat) + for i := range ta.Outputs { + tao := &ta.Outputs[i] + if bytes.Equal(addrDesc, tao.AddrDesc) { + (*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &tao.ValueSat) + } + } + } else if w.chainType == bchain.ChainEthereumType { + var value big.Int + ethTxData := eth.GetEthereumTxData(bchainTx) + // add received amount only for OK transactions + if ethTxData.Status == 1 { + if len(bchainTx.Vout) > 0 { + bchainVout := &bchainTx.Vout[0] + value = bchainVout.ValueSat + if len(bchainVout.ScriptPubKey.Addresses) > 0 { + txAddrDesc, err := w.chainParser.GetAddrDescFromAddress(bchainVout.ScriptPubKey.Addresses[0]) + if err != nil { + return nil, err + } + if bytes.Equal(addrDesc, txAddrDesc) { + (*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &value) + } + } + } + } + for i := range bchainTx.Vin { + bchainVin := &bchainTx.Vin[i] + if len(bchainVin.Addresses) > 0 { + txAddrDesc, err := w.chainParser.GetAddrDescFromAddress(bchainVin.Addresses[0]) + if err != nil { + return nil, err + } + if bytes.Equal(addrDesc, txAddrDesc) { + // add sent amount only for OK transactions, however fees always + if ethTxData.Status == 1 { + (*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &value) + } + var feesSat big.Int + // mempool txs do not have fees yet + if ethTxData.GasUsed != nil { + feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed) + } + (*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &feesSat) + } + } } } return &bh, nil diff --git a/bchain/coins/eth/erc20.go b/bchain/coins/eth/erc20.go index d001722d..6903d1e4 100644 --- a/bchain/coins/eth/erc20.go +++ b/bchain/coins/eth/erc20.go @@ -74,9 +74,9 @@ func erc20GetTransfersFromLog(logs []*rpcLog) ([]bchain.Erc20Transfer, error) { return nil, err } r = append(r, bchain.Erc20Transfer{ - Contract: strings.ToLower(l.Address), - From: strings.ToLower(from), - To: strings.ToLower(to), + Contract: EIP55AddressFromAddress(l.Address), + From: EIP55AddressFromAddress(from), + To: EIP55AddressFromAddress(to), Tokens: t, }) } @@ -97,9 +97,9 @@ func erc20GetTransfersFromTx(tx *rpcTransaction) ([]bchain.Erc20Transfer, error) return nil, errors.New("Data is not a number") } r = append(r, bchain.Erc20Transfer{ - Contract: strings.ToLower(tx.To), - From: strings.ToLower(tx.From), - To: strings.ToLower(to), + Contract: EIP55AddressFromAddress(tx.To), + From: EIP55AddressFromAddress(tx.From), + To: EIP55AddressFromAddress(to), Tokens: t, }) } diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go index f3790699..49cea1fa 100644 --- a/bchain/coins/eth/ethparser.go +++ b/bchain/coins/eth/ethparser.go @@ -202,6 +202,15 @@ func EIP55Address(addrDesc bchain.AddressDescriptor) string { return string(result) } +// EIP55AddressFromAddress returns an EIP55-compliant hex string representation of the address +func EIP55AddressFromAddress(address string) string { + b, err := hex.DecodeString(address) + if err != nil { + return address + } + return EIP55Address(b) +} + // GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable func (p *EthereumParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) { return []string{EIP55Address(addrDesc)}, true, nil