diff --git a/api/types.go b/api/types.go
index f801d9f4..c8241e36 100644
--- a/api/types.go
+++ b/api/types.go
@@ -135,58 +135,40 @@ type Vout struct {
Type string `json:"type,omitempty"`
}
-// TokenType specifies type of token
-type TokenType string
-
-// Token types
-const (
- // Ethereum token types
- ERC20TokenType TokenType = "ERC20"
- ERC771TokenType TokenType = "ERC721"
- ERC1155TokenType TokenType = "ERC1155"
-
- // XPUBAddressTokenType is address derived from xpub
- XPUBAddressTokenType TokenType = "XPUBAddress"
-)
-
-// TokenTypeMap maps bchain.TokenTransferType to TokenType
-// the map must match all bchain.TokenTransferTypes to avoid index out of range panic
-var TokenTypeMap []TokenType = []TokenType{ERC20TokenType, ERC771TokenType, ERC1155TokenType}
-
-// TokenTransferValues contains values for ERC1155 contract
-type TokenTransferValues struct {
+// MultiTokenValue contains values for contract with id and value (like ERC1155)
+type MultiTokenValue struct {
Id *Amount `json:"id,omitempty"`
Value *Amount `json:"value,omitempty"`
}
// Token contains info about tokens held by an address
type Token struct {
- Type TokenType `json:"type"`
- Name string `json:"name"`
- Path string `json:"path,omitempty"`
- Contract string `json:"contract,omitempty"`
- Transfers int `json:"transfers"`
- Symbol string `json:"symbol,omitempty"`
- Decimals int `json:"decimals,omitempty"`
- BalanceSat *Amount `json:"balance,omitempty"`
- Ids []Amount `json:"ids,omitempty"` // multiple ERC721 tokens
- IdValues []TokenTransferValues `json:"idValues,omitempty"` // multiple ERC1155 tokens
- TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
- TotalSentSat *Amount `json:"totalSent,omitempty"`
- ContractIndex string `json:"-"`
+ Type bchain.TokenTypeName `json:"type"`
+ Name string `json:"name"`
+ Path string `json:"path,omitempty"`
+ Contract string `json:"contract,omitempty"`
+ Transfers int `json:"transfers"`
+ Symbol string `json:"symbol,omitempty"`
+ Decimals int `json:"decimals,omitempty"`
+ BalanceSat *Amount `json:"balance,omitempty"`
+ Ids []Amount `json:"ids,omitempty"` // multiple ERC721 tokens
+ MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"` // multiple ERC1155 tokens
+ TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
+ TotalSentSat *Amount `json:"totalSent,omitempty"`
+ ContractIndex string `json:"-"`
}
// TokenTransfer contains info about a token transfer done in a transaction
type TokenTransfer struct {
- Type TokenType `json:"type"`
- From string `json:"from"`
- To string `json:"to"`
- Token string `json:"token"`
- Name string `json:"name"`
- Symbol string `json:"symbol"`
- Decimals int `json:"decimals"`
- Value *Amount `json:"value,omitempty"`
- Values []TokenTransferValues `json:"values,omitempty"`
+ Type bchain.TokenTypeName `json:"type"`
+ From string `json:"from"`
+ To string `json:"to"`
+ Token string `json:"token"`
+ Name string `json:"name"`
+ Symbol string `json:"symbol"`
+ Decimals int `json:"decimals"`
+ Value *Amount `json:"value,omitempty"`
+ MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"`
}
type EthereumInternalTransfer struct {
@@ -290,22 +272,22 @@ type AddressFilter struct {
// Address holds information about address and its transactions
type Address struct {
Paging
- AddrStr string `json:"address"`
- BalanceSat *Amount `json:"balance"`
- TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
- TotalSentSat *Amount `json:"totalSent,omitempty"`
- UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
- UnconfirmedTxs int `json:"unconfirmedTxs"`
- Txs int `json:"txs"`
- NonTokenTxs int `json:"nonTokenTxs,omitempty"`
- InternalTxs int `json:"internalTxs,omitempty"`
- Transactions []*Tx `json:"transactions,omitempty"`
- Txids []string `json:"txids,omitempty"`
- Nonce string `json:"nonce,omitempty"`
- UsedTokens int `json:"usedTokens,omitempty"`
- Tokens []Token `json:"tokens,omitempty"`
- Erc20Contract *bchain.Erc20Contract `json:"erc20Contract,omitempty"`
- AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
+ AddrStr string `json:"address"`
+ BalanceSat *Amount `json:"balance"`
+ TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
+ TotalSentSat *Amount `json:"totalSent,omitempty"`
+ UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
+ UnconfirmedTxs int `json:"unconfirmedTxs"`
+ Txs int `json:"txs"`
+ NonTokenTxs int `json:"nonTokenTxs,omitempty"`
+ InternalTxs int `json:"internalTxs,omitempty"`
+ Transactions []*Tx `json:"transactions,omitempty"`
+ Txids []string `json:"txids,omitempty"`
+ Nonce string `json:"nonce,omitempty"`
+ UsedTokens int `json:"usedTokens,omitempty"`
+ Tokens []Token `json:"tokens,omitempty"`
+ ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
+ AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
// helpers for explorer
Filter string `json:"-"`
XPubAddresses map[string]struct{} `json:"-"`
diff --git a/api/worker.go b/api/worker.go
index 4445d12c..0fad5f2b 100644
--- a/api/worker.go
+++ b/api/worker.go
@@ -151,7 +151,10 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
}
for a := range addresses {
if w.chainType == bchain.ChainEthereumType {
- // TODO get contract name
+ ci, err := w.db.GetContractInfoForAddress(a)
+ if err == nil && ci != nil && ci.Name != "" {
+ aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
+ }
}
n := w.db.GetAddressAlias(a)
if len(n) > 0 {
@@ -535,20 +538,28 @@ func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, add
glog.Errorf("GetAddrDescFromAddress error %v, contract %v", err, t.Contract)
continue
}
- erc20c, err := w.chain.EthereumTypeGetErc20ContractInfo(cd)
+ typeName := bchain.EthereumTokenTypeMap[t.Type]
+ contractInfo, err := w.db.GetContractInfo(cd, typeName)
if err != nil {
- glog.Errorf("GetErc20ContractInfo error %v, contract %v", err, t.Contract)
+ glog.Errorf("GetContractInfo error %v, contract %v", err, t.Contract)
}
- if erc20c == nil {
- erc20c = &bchain.Erc20Contract{Name: t.Contract}
+ if contractInfo == nil {
+ glog.Warningf("Contract %v %v not found in DB", t.Contract, typeName)
+ contractInfo, err = w.chain.GetContractInfo(cd)
+ if err != nil {
+ glog.Errorf("GetContractInfo from chain error %v, contract %v", err, t.Contract)
+ }
+ if contractInfo == nil {
+ contractInfo = &bchain.ContractInfo{Name: t.Contract, Type: bchain.UnknownTokenType}
+ }
}
var value *Amount
- var values []TokenTransferValues
- if t.Type == bchain.ERC1155 {
- values = make([]TokenTransferValues, len(t.IdValues))
+ var values []MultiTokenValue
+ if t.Type == bchain.MultiToken {
+ values = make([]MultiTokenValue, len(t.MultiTokenValues))
for j := range values {
- values[j].Id = (*Amount)(&t.IdValues[j].Id)
- values[j].Value = (*Amount)(&t.IdValues[j].Value)
+ values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id)
+ values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value)
}
} else {
value = (*Amount)(&t.Value)
@@ -556,15 +567,15 @@ func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, add
aggregateAddress(addresses, t.From)
aggregateAddress(addresses, t.To)
tokens[i] = TokenTransfer{
- Type: TokenTypeMap[t.Type],
- Token: t.Contract,
- From: t.From,
- To: t.To,
- Value: value,
- Values: values,
- Decimals: erc20c.Decimals,
- Name: erc20c.Name,
- Symbol: erc20c.Symbol,
+ Type: typeName,
+ Token: t.Contract,
+ From: t.From,
+ To: t.To,
+ Value: value,
+ MultiTokenValues: values,
+ Decimals: contractInfo.Decimals,
+ Name: contractInfo.Name,
+ Symbol: contractInfo.Symbol,
}
}
return tokens
@@ -751,35 +762,41 @@ func computePaging(count, page, itemsOnPage int) (Paging, int, int, int) {
}
func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, index int, c *db.AddrContract, details AccountDetails) (*Token, error) {
- // TODO use db.contracts
validContract := true
-
- ci, err := w.chain.EthereumTypeGetErc20ContractInfo(c.Contract)
+ typeName := bchain.EthereumTokenTypeMap[c.Type]
+ ci, err := w.db.GetContractInfo(c.Contract, typeName)
if err != nil {
- return nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", c.Contract)
+ return nil, errors.Annotatef(err, "GetContractInfo %v", c.Contract)
}
if ci == nil {
- ci = &bchain.Erc20Contract{}
- addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(c.Contract)
- if len(addresses) > 0 {
- ci.Contract = addresses[0]
- ci.Name = addresses[0]
+ glog.Warningf("Contract %v %v not found in DB", c.Contract, typeName)
+ ci, err = w.chain.GetContractInfo(c.Contract)
+ if err != nil {
+ glog.Errorf("GetContractInfo from chain error %v, contract %v", err, c.Contract)
+ }
+ if ci == nil {
+ ci = &bchain.ContractInfo{Type: bchain.UnknownTokenType}
+ addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(c.Contract)
+ if len(addresses) > 0 {
+ ci.Contract = addresses[0]
+ ci.Name = addresses[0]
+ }
+ validContract = false
}
- validContract = false
}
t := Token{
Contract: ci.Contract,
Name: ci.Name,
Symbol: ci.Symbol,
+ Type: typeName,
Transfers: int(c.Txs),
Decimals: ci.Decimals,
ContractIndex: strconv.Itoa(index),
}
// return contract balances/values only at or above AccountDetailsTokenBalances
if details >= AccountDetailsTokenBalances && validContract {
- if c.Type == bchain.ERC20 {
- t.Type = ERC20TokenType
+ if c.Type == bchain.FungibleToken {
// get Erc20 Contract Balance from blockchain, balance obtained from adding and subtracting transfers is not correct
b, err := w.chain.EthereumTypeGetErc20ContractBalance(addrDesc, c.Contract)
if err != nil {
@@ -789,11 +806,6 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
t.BalanceSat = (*Amount)(b)
}
} else {
- if c.Type == bchain.ERC721 {
- t.Type = ERC771TokenType
- } else {
- t.Type = ERC1155TokenType
- }
if len(c.Ids) > 0 {
ids := make([]Amount, len(c.Ids))
for j := range ids {
@@ -801,13 +813,13 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
}
t.Ids = ids
}
- if len(c.IdValues) > 0 {
- idValues := make([]TokenTransferValues, len(c.IdValues))
+ if len(c.MultiTokenValues) > 0 {
+ idValues := make([]MultiTokenValue, len(c.MultiTokenValues))
for j := range idValues {
- idValues[j].Id = (*Amount)(&c.IdValues[j].Id)
- idValues[j].Value = (*Amount)(&c.IdValues[j].Value)
+ idValues[j].Id = (*Amount)(&c.MultiTokenValues[j].Id)
+ idValues[j].Value = (*Amount)(&c.MultiTokenValues[j].Value)
}
- t.IdValues = idValues
+ t.MultiTokenValues = idValues
}
}
}
@@ -819,18 +831,25 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bchain.AddressDescriptor, details AccountDetails) (*Token, error) {
var b *big.Int
validContract := true
- ci, err := w.chain.EthereumTypeGetErc20ContractInfo(contract)
+ ci, err := w.db.GetContractInfo(contract, "")
if err != nil {
- return nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", contract)
+ return nil, errors.Annotatef(err, "GetContractInfo %v", contract)
}
if ci == nil {
- ci = &bchain.Erc20Contract{}
- addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(contract)
- if len(addresses) > 0 {
- ci.Contract = addresses[0]
- ci.Name = addresses[0]
+ glog.Warningf("Contract %v not found in DB", contract)
+ ci, err = w.chain.GetContractInfo(contract)
+ if err != nil {
+ glog.Errorf("GetContractInfo from chain error %v, contract %v", err, contract)
+ }
+ if ci == nil {
+ ci = &bchain.ContractInfo{Type: bchain.UnknownTokenType}
+ addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(contract)
+ if len(addresses) > 0 {
+ ci.Contract = addresses[0]
+ ci.Name = addresses[0]
+ }
+ validContract = false
}
- validContract = false
}
// do not read contract balances etc in case of Basic option
if details >= AccountDetailsTokenBalances && validContract {
@@ -843,7 +862,7 @@ func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bch
b = nil
}
return &Token{
- Type: ERC20TokenType,
+ Type: ci.Type,
BalanceSat: (*Amount)(b),
Contract: ci.Contract,
Name: ci.Name,
@@ -854,11 +873,11 @@ func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bch
}, nil
}
-func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.Erc20Contract, uint64, int, int, int, error) {
+func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.ContractInfo, uint64, int, int, int, error) {
var (
ba *db.AddrBalance
tokens []Token
- ci *bchain.Erc20Contract
+ ci *bchain.ContractInfo
n uint64
nonContractTxs int
internalTxs int
@@ -912,7 +931,7 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
}
tokens = tokens[:j]
}
- ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
+ ci, err = w.db.GetContractInfo(addrDesc, "")
if err != nil {
return nil, nil, nil, 0, 0, 0, 0, err
}
@@ -1043,7 +1062,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
var (
ba *db.AddrBalance
tokens []Token
- erc20c *bchain.Erc20Contract
+ contractInfo *bchain.ContractInfo
txm []string
txs []*Tx
txids []string
@@ -1062,7 +1081,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
}
if w.chainType == bchain.ChainEthereumType {
var n uint64
- ba, tokens, erc20c, n, nonTokenTxs, internalTxs, totalResults, err = w.getEthereumTypeAddressBalances(addrDesc, option, filter)
+ ba, tokens, contractInfo, n, nonTokenTxs, internalTxs, totalResults, err = w.getEthereumTypeAddressBalances(addrDesc, option, filter)
if err != nil {
return nil, err
}
@@ -1173,7 +1192,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
Transactions: txs,
Txids: txids,
Tokens: tokens,
- Erc20Contract: erc20c,
+ ContractInfo: contractInfo,
Nonce: nonce,
AddressAliases: w.getAddressAliases(addresses),
}
diff --git a/api/xpub.go b/api/xpub.go
index 8737373b..b555e379 100644
--- a/api/xpub.go
+++ b/api/xpub.go
@@ -266,7 +266,7 @@ func (w *Worker) tokenFromXpubAddress(data *xpubData, ad *xpubAddress, changeInd
}
}
return Token{
- Type: XPUBAddressTokenType,
+ Type: bchain.XPUBAddressTokenType,
Name: address,
Decimals: w.chainParser.AmountDecimals(),
BalanceSat: (*Amount)(balance),
diff --git a/bchain/basechain.go b/bchain/basechain.go
index 26ea6a5e..ee5d30e0 100644
--- a/bchain/basechain.go
+++ b/bchain/basechain.go
@@ -54,8 +54,8 @@ func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint
return 0, errors.New("Not supported")
}
-// EthereumTypeGetErc20ContractInfo is not supported
-func (b *BaseChain) EthereumTypeGetErc20ContractInfo(contractDesc AddressDescriptor) (*Erc20Contract, error) {
+// GetContractInfo is not supported
+func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
return nil, errors.New("Not supported")
}
diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go
index c4008e8f..33b996e9 100644
--- a/bchain/coins/blockchain.go
+++ b/bchain/coins/blockchain.go
@@ -321,13 +321,13 @@ func (c *blockChainWithMetrics) EthereumTypeEstimateGas(params map[string]interf
return c.b.EthereumTypeEstimateGas(params)
}
-func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (v *bchain.Erc20Contract, err error) {
- defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
- return c.b.EthereumTypeGetErc20ContractInfo(contractDesc)
+func (c *blockChainWithMetrics) GetContractInfo(contractDesc bchain.AddressDescriptor) (v *bchain.ContractInfo, err error) {
+ defer func(s time.Time) { c.observeRPCLatency("GetContractInfo", s, err) }(time.Now())
+ return c.b.GetContractInfo(contractDesc)
}
func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (v *big.Int, err error) {
- defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
+ defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractBalance", s, err) }(time.Now())
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
}
diff --git a/bchain/coins/eth/contract.go b/bchain/coins/eth/contract.go
index ddc99294..76a84fb1 100644
--- a/bchain/coins/eth/contract.go
+++ b/bchain/coins/eth/contract.go
@@ -4,10 +4,8 @@ import (
"context"
"math/big"
"strings"
- "sync"
ethcommon "github.com/ethereum/go-ethereum/common"
- "github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
)
@@ -28,9 +26,6 @@ const contractSymbolSignature = "0x95d89b41"
const contractDecimalsSignature = "0x313ce567"
const contractBalanceOf = "0x70a08231"
-var cachedContracts = make(map[string]*bchain.Erc20Contract)
-var cachedContractsMux sync.Mutex
-
func addressFromPaddedHex(s string) (string, error) {
var t big.Int
var ok bool
@@ -48,16 +43,16 @@ func addressFromPaddedHex(s string) (string, error) {
func processTransferEvent(l *bchain.RpcLog) (*bchain.TokenTransfer, error) {
tl := len(l.Topics)
- var ttt bchain.TokenTransferType
+ var ttt bchain.TokenType
var value big.Int
if tl == 3 {
- ttt = bchain.ERC20
+ ttt = bchain.FungibleToken
_, ok := value.SetString(l.Data, 0)
if !ok {
return nil, errors.New("ERC20 log Data is not a number")
}
} else if tl == 4 {
- ttt = bchain.ERC721
+ ttt = bchain.NonFungibleToken
_, ok := value.SetString(l.Topics[3], 0)
if !ok {
return nil, errors.New("ERC721 log Topics[3] is not a number")
@@ -105,11 +100,11 @@ func processERC1155TransferSingleEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
return nil, errors.New("ERC1155 log Data value is not a number")
}
return &bchain.TokenTransfer{
- Type: bchain.ERC1155,
- Contract: EIP55AddressFromAddress(l.Address),
- From: EIP55AddressFromAddress(from),
- To: EIP55AddressFromAddress(to),
- IdValues: []bchain.TokenTransferIdValue{{Id: id, Value: value}},
+ Type: bchain.MultiToken,
+ Contract: EIP55AddressFromAddress(l.Address),
+ From: EIP55AddressFromAddress(from),
+ To: EIP55AddressFromAddress(to),
+ MultiTokenValues: []bchain.MultiTokenValue{{Id: id, Value: value}},
}, nil
}
@@ -150,7 +145,7 @@ func processERC1155TransferBatchEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
if countIds != countValues {
return nil, errors.New("ERC1155 TransferBatch, count values and ids does not match")
}
- idValues := make([]bchain.TokenTransferIdValue, countValues)
+ idValues := make([]bchain.MultiTokenValue, countValues)
for i := 0; i < countValues; i++ {
var id, value big.Int
o := offsetIds + 64 + 64*i
@@ -163,14 +158,14 @@ func processERC1155TransferBatchEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
if !ok {
return nil, errors.New("ERC1155 log Data value is not a number")
}
- idValues[i] = bchain.TokenTransferIdValue{Id: id, Value: value}
+ idValues[i] = bchain.MultiTokenValue{Id: id, Value: value}
}
return &bchain.TokenTransfer{
- Type: bchain.ERC1155,
- Contract: EIP55AddressFromAddress(l.Address),
- From: EIP55AddressFromAddress(from),
- To: EIP55AddressFromAddress(to),
- IdValues: idValues,
+ Type: bchain.MultiToken,
+ Contract: EIP55AddressFromAddress(l.Address),
+ From: EIP55AddressFromAddress(from),
+ To: EIP55AddressFromAddress(to),
+ MultiTokenValues: idValues,
}, nil
}
func contractGetTransfersFromLog(logs []*bchain.RpcLog) (bchain.TokenTransfers, error) {
@@ -214,7 +209,7 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
return nil, errors.New("Data is not a number")
}
r = append(r, &bchain.TokenTransfer{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: EIP55AddressFromAddress(tx.To),
From: EIP55AddressFromAddress(tx.From),
To: EIP55AddressFromAddress(to),
@@ -238,7 +233,7 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
return nil, errors.New("Data is not a number")
}
r = append(r, &bchain.TokenTransfer{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: EIP55AddressFromAddress(tx.To),
From: EIP55AddressFromAddress(from),
To: EIP55AddressFromAddress(to),
@@ -262,56 +257,52 @@ func (b *EthereumRPC) ethCall(data, to string) (string, error) {
return r, nil
}
-// EthereumTypeGetErc20ContractInfo returns information about ERC20 contract
-func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) {
- cds := string(contractDesc)
- cachedContractsMux.Lock()
- contract, found := cachedContracts[cds]
- cachedContractsMux.Unlock()
- if !found {
- address := EIP55Address(contractDesc)
- data, err := b.ethCall(contractNameSignature, address)
- if err != nil {
- // ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
- // and returning error "execution reverted" for some non contract addresses
- // https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672
- glog.Warning(errors.Annotatef(err, "erc20NameSignature %v", address))
- return nil, nil
- // return nil, errors.Annotatef(err, "erc20NameSignature %v", address)
- }
- name := parseSimpleStringProperty(data)
- if name != "" {
- data, err = b.ethCall(contractSymbolSignature, address)
- if err != nil {
- glog.Warning(errors.Annotatef(err, "erc20SymbolSignature %v", address))
- return nil, nil
- // return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
- }
- symbol := parseSimpleStringProperty(data)
- data, err = b.ethCall(contractDecimalsSignature, address)
- if err != nil {
- glog.Warning(errors.Annotatef(err, "erc20DecimalsSignature %v", address))
- // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
- }
- contract = &bchain.Erc20Contract{
- Contract: address,
- Name: name,
- Symbol: symbol,
- }
- d := parseSimpleNumericProperty(data)
- if d != nil {
- contract.Decimals = int(uint8(d.Uint64()))
- } else {
- contract.Decimals = EtherAmountDecimalPoint
- }
- } else {
- contract = nil
- }
- cachedContractsMux.Lock()
- cachedContracts[cds] = contract
- cachedContractsMux.Unlock()
+func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
+ var contract bchain.ContractInfo
+ data, err := b.ethCall(contractNameSignature, address)
+ if err != nil {
+ // ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
+ // and returning error "execution reverted" for some non contract addresses
+ // https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672
+ // glog.Warning(errors.Annotatef(err, "Contract NameSignature %v", address))
+ return nil, nil
+ // return nil, errors.Annotatef(err, "erc20NameSignature %v", address)
}
- return contract, nil
+ name := parseSimpleStringProperty(data)
+ if name != "" {
+ data, err = b.ethCall(contractSymbolSignature, address)
+ if err != nil {
+ // glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
+ return nil, nil
+ // return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
+ }
+ symbol := parseSimpleStringProperty(data)
+ data, _ = b.ethCall(contractDecimalsSignature, address)
+ // if err != nil {
+ // glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
+ // // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
+ // }
+ contract = bchain.ContractInfo{
+ Contract: address,
+ Name: name,
+ Symbol: symbol,
+ }
+ d := parseSimpleNumericProperty(data)
+ if d != nil {
+ contract.Decimals = int(uint8(d.Uint64()))
+ } else {
+ contract.Decimals = EtherAmountDecimalPoint
+ }
+ } else {
+ return nil, nil
+ }
+ return &contract, nil
+}
+
+// GetContractInfo returns information about a contract
+func (b *EthereumRPC) GetContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.ContractInfo, error) {
+ address := EIP55Address(contractDesc)
+ return b.fetchContractInfo(address)
}
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
diff --git a/bchain/coins/eth/contract_test.go b/bchain/coins/eth/contract_test.go
index 7d609a0a..587d98a7 100644
--- a/bchain/coins/eth/contract_test.go
+++ b/bchain/coins/eth/contract_test.go
@@ -133,7 +133,7 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
},
want: bchain.TokenTransfers{
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: "0x5689b918D34C038901870105A6C7fc24744D31eB",
From: "0x0a206d4d5ff79cb5069def7fe3598421cff09391",
To: "0x6a016d7eec560549ffa0fbdb7f15c2b27302087f",
@@ -171,11 +171,11 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
},
want: bchain.TokenTransfers{
{
- Type: bchain.ERC1155,
- Contract: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
- From: "0xa3950b823cb063dd9afc0d27f35008b805b3ed53",
- To: "0x4392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
- IdValues: []bchain.TokenTransferIdValue{{Id: *big.NewInt(150), Value: *big.NewInt(0x11)}},
+ Type: bchain.MultiToken,
+ Contract: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
+ From: "0xa3950b823cb063dd9afc0d27f35008b805b3ed53",
+ To: "0x4392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
+ MultiTokenValues: []bchain.MultiTokenValue{{Id: *big.NewInt(150), Value: *big.NewInt(0x11)}},
},
},
},
@@ -195,11 +195,11 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
},
want: bchain.TokenTransfers{
{
- Type: bchain.ERC1155,
+ Type: bchain.MultiToken,
Contract: "0x6c42c26a081c2f509f8bb68fb7ac3062311ccfb7",
From: "0x0000000000000000000000000000000000000000",
To: "0x5dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
- IdValues: []bchain.TokenTransferIdValue{
+ MultiTokenValues: []bchain.MultiTokenValue{
{Id: *big.NewInt(1776), Value: *big.NewInt(1)},
{Id: *big.NewInt(1898), Value: *big.NewInt(10)},
},
@@ -247,7 +247,7 @@ func Test_contractGetTransfersFromTx(t *testing.T) {
args: (b1.Txs[1].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
want: bchain.TokenTransfers{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
From: "0x20cd153de35d469ba46127a0c8f18626b59a256a",
To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
@@ -260,7 +260,7 @@ func Test_contractGetTransfersFromTx(t *testing.T) {
args: (b2.Txs[2].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
want: bchain.TokenTransfers{
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: "0xcda9fc258358ecaa88845f19af595e908bb7efe9",
From: "0x837e3f699d85a4b0b99894567e9233dfb1dcb081",
To: "0x7b62eb7fe80350dc7ec945c0b73242cb9877fb1b",
diff --git a/bchain/coins/eth/dataparser.go b/bchain/coins/eth/dataparser.go
index a67c947e..060fcfca 100644
--- a/bchain/coins/eth/dataparser.go
+++ b/bchain/coins/eth/dataparser.go
@@ -39,8 +39,8 @@ func parseSimpleStringProperty(data string) string {
if len(data) > 128 {
n := parseSimpleNumericProperty(data[64:128])
if n != nil {
- l := n.Uint64()
- if l > 0 && 2*int(l) <= len(data)-128 {
+ l := n.Int64()
+ if l > 0 && int(l) <= ((len(data)-128)>>1) {
b, err := hex.DecodeString(data[128 : 128+2*l])
if err == nil {
return string(b)
diff --git a/bchain/coins/eth/dataparser_test.go b/bchain/coins/eth/dataparser_test.go
index 5aca77ec..745e6b62 100644
--- a/bchain/coins/eth/dataparser_test.go
+++ b/bchain/coins/eth/dataparser_test.go
@@ -45,6 +45,11 @@ func Test_parseSimpleStringProperty(t *testing.T) {
args: "0x2234880850896048596206002535425366538144616734015984380565810000",
want: "",
},
+ {
+ name: "garbage",
+ args: "6080604052600436106100225760003560e01c80630cbcae701461003957610031565b366100315761002f610077565b005b61002f610077565b34801561004557600080fd5b5061004e61014e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000061011c565b60043560601b60601c6bca11c0de15dead10cced00006000195460a01c036100e9577f696d706c6f63000000000000000000000000000000000000000000000000000060005260206000fd5b8060001955005b60405136810160405236600082376000803683600019545af43d6000833e80610117573d82fd5b503d81f35b80330361014357602436036101435763ca11c0de60003560e01c036101435761014361009d565b61014b6100f0565b50565b600073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff541660005260206000f3fea2646970667358221220f27ad3f3b75609baa5d26d65ec1001c4a59f38e89088d6b47517c1cd1faf22ab64736f6c634300080d0033",
+ want: "",
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/bchain/coins/eth/ethrpc.go b/bchain/coins/eth/ethrpc.go
index 092c835b..1e48bc54 100644
--- a/bchain/coins/eth/ethrpc.go
+++ b/bchain/coins/eth/ethrpc.go
@@ -537,23 +537,37 @@ type rpcTraceResult struct {
Result rpcCallTrace `json:"result"`
}
-func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData) {
+func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo {
+ ci, err := b.fetchContractInfo(contract)
+ if ci == nil || err != nil {
+ ci = &bchain.ContractInfo{
+ Contract: contract,
+ }
+ }
+ ci.Type = bchain.UnknownTokenType
+ ci.CreatedInBlock = height
+ return ci
+}
+
+func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo {
value, err := hexutil.DecodeBig(call.Value)
if call.Type == "CREATE" {
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
Type: bchain.CREATE,
Value: *value,
From: call.From,
- To: call.To,
+ To: call.To, // new contract address
})
+ contracts = append(contracts, *b.getCreationContractInfo(call.To, blockHeight))
} else if call.Type == "SELFDESTRUCT" {
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
Type: bchain.SELFDESTRUCT,
Value: *value,
- From: call.From,
+ From: call.From, // destroyed contract address
To: call.To,
})
+ contracts = append(contracts, bchain.ContractInfo{Contract: call.From, DestructedInBlock: blockHeight})
} else if err == nil && (value.BitLen() > 0 || b.ChainConfig.ProcessZeroInternalTransactions) {
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
Value: *value,
@@ -565,13 +579,15 @@ func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInt
d.Error = call.Error
}
for i := range call.Calls {
- b.processCallTrace(&call.Calls[i], d)
+ contracts = b.processCallTrace(&call.Calls[i], d, contracts, blockHeight)
}
+ return contracts
}
// getInternalDataForBlock fetches debug trace using callTracer, extracts internal transfers and creations and destructions of contracts
-func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, error) {
+func (b *EthereumRPC) getInternalDataForBlock(blockHash string, blockHeight uint32, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, []bchain.ContractInfo, error) {
data := make([]bchain.EthereumInternalData, len(transactions))
+ contracts := make([]bchain.ContractInfo, 0)
if ProcessInternalTransactions {
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
@@ -579,11 +595,11 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
err := b.rpc.CallContext(ctx, &trace, "debug_traceBlockByHash", blockHash, map[string]interface{}{"tracer": "callTracer"})
if err != nil {
glog.Error("debug_traceBlockByHash block ", blockHash, ", error ", err)
- return data, err
+ return data, contracts, err
}
if len(trace) != len(data) {
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: trace length does not match block length ", len(trace), "!=", len(data))
- return data, err
+ return data, contracts, err
}
for i, result := range trace {
r := &result.Result
@@ -591,11 +607,12 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
if r.Type == "CREATE" {
d.Type = bchain.CREATE
d.Contract = r.To
+ contracts = append(contracts, *b.getCreationContractInfo(d.Contract, blockHeight))
} else if r.Type == "SELFDESTRUCT" {
d.Type = bchain.SELFDESTRUCT
}
for j := range r.Calls {
- b.processCallTrace(&r.Calls[j], d)
+ contracts = b.processCallTrace(&r.Calls[j], d, contracts, blockHeight)
}
if r.Error != "" {
baseError := PackInternalTransactionError(r.Error)
@@ -620,7 +637,7 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
}
}
}
- return data, nil
+ return data, contracts, nil
}
// GetBlock returns block with given hash or height, hash has precedence if both passed
@@ -642,15 +659,16 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
}
// get block events
+ // TODO - could be possibly done in parallel to getInternalDataForBlock
logs, ens, err := b.processEventsForBlock(head.Number)
if err != nil {
return nil, err
}
// error fetching internal data does not stop the block processing
var blockSpecificData *bchain.EthereumBlockSpecificData
- internalData, err := b.getInternalDataForBlock(head.Hash, body.Transactions)
+ internalData, contracts, err := b.getInternalDataForBlock(head.Hash, bbh.Height, body.Transactions)
// pass internalData error and ENS records in blockSpecificData to be stored
- if err != nil || len(ens) > 0 {
+ if err != nil || len(ens) > 0 || len(contracts) > 0 {
blockSpecificData = &bchain.EthereumBlockSpecificData{}
if err != nil {
blockSpecificData.InternalDataError = err.Error()
@@ -658,7 +676,11 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
}
if len(ens) > 0 {
blockSpecificData.AddressAliasRecords = ens
- glog.Info("ENS", ens)
+ // glog.Info("ENS", ens)
+ }
+ if len(contracts) > 0 {
+ blockSpecificData.Contracts = contracts
+ // glog.Info("Contracts", contracts)
}
}
diff --git a/bchain/types.go b/bchain/types.go
index 2f40dfe4..4d9af1f9 100644
--- a/bchain/types.go
+++ b/bchain/types.go
@@ -113,6 +113,27 @@ type MempoolTx struct {
CoinSpecificData interface{} `json:"-"`
}
+// TokenType - type of token
+type TokenType int
+
+// TokenType enumeration
+const (
+ FungibleToken = TokenType(iota) // ERC20
+ NonFungibleToken // ERC721
+ MultiToken // ERC1155
+)
+
+// TokenTypeName specifies type of token
+type TokenTypeName string
+
+// Token types
+const (
+ UnknownTokenType TokenTypeName = ""
+
+ // XPUBAddressTokenType is address derived from xpub
+ XPUBAddressTokenType TokenTypeName = "XPUBAddress"
+)
+
// TokenTransfers is array of TokenTransfer
type TokenTransfers []*TokenTransfer
@@ -286,13 +307,13 @@ type BlockChain interface {
EstimateFee(blocks int) (big.Int, error)
SendRawTransaction(tx string) (string, error)
GetMempoolEntry(txid string) (*MempoolEntry, error)
+ GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error)
// parser
GetChainParser() BlockChainParser
// EthereumType specific
EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error)
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
- EthereumTypeGetErc20ContractInfo(contractDesc AddressDescriptor) (*Erc20Contract, error)
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
}
diff --git a/bchain/types_ethereum_type.go b/bchain/types_ethereum_type.go
index 357f1667..a04a0810 100644
--- a/bchain/types_ethereum_type.go
+++ b/bchain/types_ethereum_type.go
@@ -47,16 +47,6 @@ const (
SELFDESTRUCT
)
-// TokenTransferType - type of token transfer
-type TokenTransferType int
-
-// TokenTransferType enumeration
-const (
- ERC20 = TokenTransferType(iota)
- ERC721
- ERC1155
-)
-
// EthereumInternalTransaction contains internal transfers
type EthereumInternalData struct {
Type EthereumInternalTransactionType `json:"type"`
@@ -65,27 +55,41 @@ type EthereumInternalData struct {
Error string
}
-// Erc20Contract contains info about ERC20 contract
-type Erc20Contract struct {
- Contract string `json:"contract"`
- Name string `json:"name"`
- Symbol string `json:"symbol"`
- Decimals int `json:"decimals"`
+// ContractInfo contains info about ERC20 contract
+type ContractInfo struct {
+ Type TokenTypeName `json:"type"`
+ Contract string `json:"contract"`
+ Name string `json:"name"`
+ Symbol string `json:"symbol"`
+ Decimals int `json:"decimals"`
+ CreatedInBlock uint32 `json:"createdInBlock,omitempty"`
+ DestructedInBlock uint32 `json:"destructedInBlock,omitempty"`
}
-type TokenTransferIdValue struct {
+// Ethereum token type names
+const (
+ ERC20TokenType TokenTypeName = "ERC20"
+ ERC771TokenType TokenTypeName = "ERC721"
+ ERC1155TokenType TokenTypeName = "ERC1155"
+)
+
+// EthereumTokenTypeMap maps bchain.TokenType to TokenTypeName
+// the map must match all bchain.TokenType to avoid index out of range panic
+var EthereumTokenTypeMap []TokenTypeName = []TokenTypeName{ERC20TokenType, ERC771TokenType, ERC1155TokenType}
+
+type MultiTokenValue struct {
Id big.Int
Value big.Int
}
-// TokenTransfer contains a single ERC20/ERC721/ERC1155 token transfer
+// TokenTransfer contains a single token transfer
type TokenTransfer struct {
- Type TokenTransferType
- Contract string
- From string
- To string
- Value big.Int
- IdValues []TokenTransferIdValue
+ Type TokenType
+ Contract string
+ From string
+ To string
+ Value big.Int
+ MultiTokenValues []MultiTokenValue
}
// RpcTransaction is returned by eth_getTransactionByHash
@@ -138,4 +142,5 @@ type AddressAliasRecord struct {
type EthereumBlockSpecificData struct {
InternalDataError string
AddressAliasRecords []AddressAliasRecord
+ Contracts []ContractInfo
}
diff --git a/db/rocksdb_ethereumtype.go b/db/rocksdb_ethereumtype.go
index 13457c7c..a75b5284 100644
--- a/db/rocksdb_ethereumtype.go
+++ b/db/rocksdb_ethereumtype.go
@@ -6,6 +6,7 @@ import (
"math/big"
"sync"
+ vlq "github.com/bsm/go-vlq"
"github.com/flier/gorocksdb"
"github.com/golang/glog"
"github.com/juju/errors"
@@ -18,12 +19,12 @@ const ContractIndexOffset = 2
// AddrContract is Contract address with number of transactions done by given address
type AddrContract struct {
- Type bchain.TokenTransferType
- Contract bchain.AddressDescriptor
- Txs uint
- Value big.Int // single value of ERC20
- Ids []big.Int // multiple ERC721 tokens
- IdValues []bchain.TokenTransferIdValue // multiple ERC1155 tokens
+ Type bchain.TokenType
+ Contract bchain.AddressDescriptor
+ Txs uint
+ Value big.Int // single value of ERC20
+ Ids []big.Int // multiple ERC721 tokens
+ MultiTokenValues []bchain.MultiTokenValue // multiple ERC1155 tokens
}
// AddrContracts contains number of transactions and contracts for an address
@@ -48,10 +49,10 @@ func packAddrContracts(acs *AddrContracts) []byte {
buf = append(buf, ac.Contract...)
l = packVaruint(uint(ac.Type)+ac.Txs<<2, varBuf)
buf = append(buf, varBuf[:l]...)
- if ac.Type == bchain.ERC20 {
+ if ac.Type == bchain.FungibleToken {
l = packBigint(&ac.Value, varBuf)
buf = append(buf, varBuf[:l]...)
- } else if ac.Type == bchain.ERC721 {
+ } else if ac.Type == bchain.NonFungibleToken {
l = packVaruint(uint(len(ac.Ids)), varBuf)
buf = append(buf, varBuf[:l]...)
for i := range ac.Ids {
@@ -59,12 +60,12 @@ func packAddrContracts(acs *AddrContracts) []byte {
buf = append(buf, varBuf[:l]...)
}
} else { // bchain.ERC1155
- l = packVaruint(uint(len(ac.IdValues)), varBuf)
+ l = packVaruint(uint(len(ac.MultiTokenValues)), varBuf)
buf = append(buf, varBuf[:l]...)
- for i := range ac.IdValues {
- l = packBigint(&ac.IdValues[i].Id, varBuf)
+ for i := range ac.MultiTokenValues {
+ l = packBigint(&ac.MultiTokenValues[i].Id, varBuf)
buf = append(buf, varBuf[:l]...)
- l = packBigint(&ac.IdValues[i].Value, varBuf)
+ l = packBigint(&ac.MultiTokenValues[i].Value, varBuf)
buf = append(buf, varBuf[:l]...)
}
}
@@ -87,21 +88,21 @@ func unpackAddrContracts(buf []byte, addrDesc bchain.AddressDescriptor) (*AddrCo
contract := append(bchain.AddressDescriptor(nil), buf[:eth.EthereumTypeAddressDescriptorLen]...)
txs, l := unpackVaruint(buf[eth.EthereumTypeAddressDescriptorLen:])
buf = buf[eth.EthereumTypeAddressDescriptorLen+l:]
- ttt := bchain.TokenTransferType(txs & 3)
+ ttt := bchain.TokenType(txs & 3)
txs >>= 2
ac := AddrContract{
Type: ttt,
Contract: contract,
Txs: txs,
}
- if ttt == bchain.ERC20 {
+ if ttt == bchain.FungibleToken {
b, ll := unpackBigint(buf)
buf = buf[ll:]
ac.Value = b
} else {
len, ll := unpackVaruint(buf)
buf = buf[ll:]
- if ttt == bchain.ERC721 {
+ if ttt == bchain.NonFungibleToken {
ac.Ids = make([]big.Int, len)
for i := uint(0); i < len; i++ {
b, ll := unpackBigint(buf)
@@ -109,14 +110,14 @@ func unpackAddrContracts(buf []byte, addrDesc bchain.AddressDescriptor) (*AddrCo
ac.Ids[i] = b
}
} else {
- ac.IdValues = make([]bchain.TokenTransferIdValue, len)
+ ac.MultiTokenValues = make([]bchain.MultiTokenValue, len)
for i := uint(0); i < len; i++ {
b, ll := unpackBigint(buf)
buf = buf[ll:]
- ac.IdValues[i].Id = b
+ ac.MultiTokenValues[i].Id = b
b, ll = unpackBigint(buf)
buf = buf[ll:]
- ac.IdValues[i].Value = b
+ ac.MultiTokenValues[i].Value = b
}
}
}
@@ -226,9 +227,9 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
s.Add(s, v)
}
}
- if transfer.Type == bchain.ERC20 {
+ if transfer.Type == bchain.FungibleToken {
aggregate(&c.Value, &transfer.Value)
- } else if transfer.Type == bchain.ERC721 {
+ } else if transfer.Type == bchain.NonFungibleToken {
if index < 0 {
// remove token from the list
for i := range c.Ids {
@@ -242,14 +243,14 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
c.Ids = append(c.Ids, transfer.Value)
}
} else { // bchain.ERC1155
- for _, t := range transfer.IdValues {
- for i := range c.IdValues {
+ for _, t := range transfer.MultiTokenValues {
+ for i := range c.MultiTokenValues {
// find the token in the list
- if c.IdValues[i].Id.Cmp(&t.Id) == 0 {
- aggregate(&c.IdValues[i].Value, &t.Value)
+ if c.MultiTokenValues[i].Id.Cmp(&t.Id) == 0 {
+ aggregate(&c.MultiTokenValues[i].Value, &t.Value)
// if transfer from, remove if the value is zero
- if index < 0 && len(c.IdValues[i].Value.Bits()) == 0 {
- c.IdValues = append(c.IdValues[:i], c.IdValues[i+1:]...)
+ if index < 0 && len(c.MultiTokenValues[i].Value.Bits()) == 0 {
+ c.MultiTokenValues = append(c.MultiTokenValues[:i], c.MultiTokenValues[i+1:]...)
}
goto nextTransfer
}
@@ -257,7 +258,7 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
// if not found and transfer to, add to the list
// it is necessary to add a copy of the value so that subsequent calls to addToContract do not change the transfer value
if index >= 0 {
- c.IdValues = append(c.IdValues, bchain.TokenTransferIdValue{
+ c.MultiTokenValues = append(c.MultiTokenValues, bchain.MultiTokenValue{
Id: t.Id,
Value: *new(big.Int).Set(&t.Value),
})
@@ -327,9 +328,9 @@ func (d *RocksDB) addToAddressesAndContractsEthereumType(addrDesc bchain.Address
type ethBlockTxContract struct {
from, to, contract bchain.AddressDescriptor
- transferType bchain.TokenTransferType
+ transferType bchain.TokenType
value big.Int
- idValues []bchain.TokenTransferIdValue
+ idValues []bchain.MultiTokenValue
}
type ethInternalTransfer struct {
@@ -476,7 +477,7 @@ func (d *RocksDB) processContractTransfers(blockTx *ethBlockTx, tx *bchain.Tx, a
bc.to = to
bc.contract = contract
bc.value = t.Value
- bc.idValues = t.IdValues
+ bc.idValues = t.MultiTokenValues
}
return nil
}
@@ -699,6 +700,113 @@ func (d *RocksDB) storeInternalDataEthereumType(wb *gorocksdb.WriteBatch, blockT
return nil
}
+var cachedContracts = make(map[string]*bchain.ContractInfo)
+var cachedContractsMux sync.Mutex
+
+func packContractInfo(contractInfo *bchain.ContractInfo) []byte {
+ buf := packString(contractInfo.Name)
+ buf = append(buf, packString(contractInfo.Symbol)...)
+ buf = append(buf, packString(string(contractInfo.Type))...)
+ varBuf := make([]byte, vlq.MaxLen64)
+ l := packVaruint(uint(contractInfo.Decimals), varBuf)
+ buf = append(buf, varBuf[:l]...)
+ l = packVaruint(uint(contractInfo.CreatedInBlock), varBuf)
+ buf = append(buf, varBuf[:l]...)
+ l = packVaruint(uint(contractInfo.DestructedInBlock), varBuf)
+ buf = append(buf, varBuf[:l]...)
+ return buf
+}
+
+func unpackContractInfo(buf []byte) (*bchain.ContractInfo, error) {
+ var contractInfo bchain.ContractInfo
+ var s string
+ var l int
+ var ui uint
+ contractInfo.Name, l = unpackString(buf)
+ buf = buf[l:]
+ contractInfo.Symbol, l = unpackString(buf)
+ buf = buf[l:]
+ s, l = unpackString(buf)
+ contractInfo.Type = bchain.TokenTypeName(s)
+ buf = buf[l:]
+ ui, l = unpackVaruint(buf)
+ contractInfo.Decimals = int(ui)
+ buf = buf[l:]
+ ui, l = unpackVaruint(buf)
+ contractInfo.CreatedInBlock = uint32(ui)
+ buf = buf[l:]
+ ui, l = unpackVaruint(buf)
+ contractInfo.DestructedInBlock = uint32(ui)
+ return &contractInfo, nil
+}
+
+func (d *RocksDB) GetContractInfoForAddress(address string) (*bchain.ContractInfo, error) {
+ contract, err := d.chainParser.GetAddrDescFromAddress(address)
+ if err != nil || contract == nil {
+ return nil, err
+ }
+ return d.GetContractInfo(contract, "")
+}
+
+// GetContractInfo gets contract from cache or DB and possibly updates the type from typeFromContext
+// this is because it is hard to guess the type of the contract using API, it is easier to set it the first time its usage is detected in tx
+func (d *RocksDB) GetContractInfo(contract bchain.AddressDescriptor, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, error) {
+ cacheKey := string(contract)
+ cachedContractsMux.Lock()
+ contractInfo, found := cachedContracts[cacheKey]
+ cachedContractsMux.Unlock()
+ if !found {
+ val, err := d.db.GetCF(d.ro, d.cfh[cfContracts], contract)
+ if err != nil {
+ return nil, err
+ }
+ defer val.Free()
+ buf := val.Data()
+ if len(buf) == 0 {
+ return nil, nil
+ }
+ contractInfo, err = unpackContractInfo(buf)
+ addresses, _, _ := d.chainParser.GetAddressesFromAddrDesc(contract)
+ if len(addresses) > 0 {
+ contractInfo.Contract = addresses[0]
+ }
+ // if the type is specified and stored contractInfo has unknown type, set and store it
+ if typeFromContext != bchain.UnknownTokenType && contractInfo.Type == bchain.UnknownTokenType {
+ contractInfo.Type = typeFromContext
+ err = d.db.PutCF(d.wo, d.cfh[cfContracts], contract, packContractInfo(contractInfo))
+ }
+ cachedContractsMux.Lock()
+ cachedContracts[cacheKey] = contractInfo
+ cachedContractsMux.Unlock()
+ }
+ return contractInfo, nil
+}
+
+// StoreContractInfo stores contractInfo in DB
+// if CreatedInBlock==0 and DestructedInBlock!=0, it is evaluated as a desctruction of a contract, the contract info is updated
+// in all other cases the contractInfo overwrites previously stored data in DB (however it should not really happen as contract is created only once)
+func (d *RocksDB) StoreContractInfo(wb *gorocksdb.WriteBatch, contractInfo *bchain.ContractInfo) error {
+ if contractInfo.Contract != "" {
+ key, err := d.chainParser.GetAddrDescFromAddress(contractInfo.Contract)
+ if err != nil {
+ return err
+ }
+ if contractInfo.CreatedInBlock == 0 && contractInfo.DestructedInBlock != 0 {
+ storedCI, err := d.GetContractInfo(key, "")
+ if err != nil {
+ return err
+ }
+ if storedCI == nil {
+ return nil
+ }
+ storedCI.DestructedInBlock = contractInfo.DestructedInBlock
+ contractInfo = storedCI
+ }
+ wb.PutCF(d.cfh[cfContracts], key, packContractInfo(contractInfo))
+ }
+ return nil
+}
+
func packBlockTx(buf []byte, blockTx *ethBlockTx) []byte {
varBuf := make([]byte, maxPackedBigintBytes)
buf = append(buf, blockTx.btxID...)
@@ -715,7 +823,7 @@ func packBlockTx(buf []byte, blockTx *ethBlockTx) []byte {
buf = appendAddress(buf, c.contract)
l = packVaruint(uint(c.transferType), varBuf)
buf = append(buf, varBuf[:l]...)
- if c.transferType == bchain.ERC1155 {
+ if c.transferType == bchain.MultiToken {
l = packVaruint(uint(len(c.idValues)), varBuf)
buf = append(buf, varBuf[:l]...)
for i := range c.idValues {
@@ -773,6 +881,11 @@ func (d *RocksDB) storeBlockSpecificDataEthereumType(wb *gorocksdb.WriteBatch, b
return err
}
}
+ for i := range blockSpecificData.Contracts {
+ if err := d.StoreContractInfo(wb, &blockSpecificData.Contracts[i]); err != nil {
+ return err
+ }
+ }
}
return nil
}
@@ -823,12 +936,12 @@ func unpackBlockTx(buf []byte, pos int) (*ethBlockTx, int, error) {
return nil, 0, err
}
cc, l = unpackVaruint(buf[pos:])
- c.transferType = bchain.TokenTransferType(cc)
+ c.transferType = bchain.TokenType(cc)
pos += l
- if c.transferType == bchain.ERC1155 {
+ if c.transferType == bchain.MultiToken {
cc, l = unpackVaruint(buf[pos:])
pos += l
- c.idValues = make([]bchain.TokenTransferIdValue, cc)
+ c.idValues = make([]bchain.MultiTokenValue, cc)
for i := range c.idValues {
c.idValues[i].Id, l = unpackBigint(buf[pos:])
pos += l
@@ -938,9 +1051,9 @@ func (d *RocksDB) disconnectAddress(btxID []byte, internal bool, addrDesc bchain
index = transferTo
}
addToContract(addrContract, contractIndex, index, btxContract.contract, &bchain.TokenTransfer{
- Type: btxContract.transferType,
- Value: btxContract.value,
- IdValues: btxContract.idValues,
+ Type: btxContract.transferType,
+ Value: btxContract.value,
+ MultiTokenValues: btxContract.idValues,
}, false)
}
} else {
diff --git a/db/rocksdb_ethereumtype_test.go b/db/rocksdb_ethereumtype_test.go
index 6631df9f..bf651335 100644
--- a/db/rocksdb_ethereumtype_test.go
+++ b/db/rocksdb_ethereumtype_test.go
@@ -58,11 +58,11 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "020102", nil},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
- "020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"), nil,
+ "020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
- "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintToHex(big.NewInt(0)), nil,
+ "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintToHex(big.NewInt(0)), nil,
},
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010002", nil},
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010101", nil},
@@ -72,6 +72,25 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
}
}
+ var destructedInBlock uint
+ if afterDisconnect {
+ destructedInBlock = 44445
+ }
+ if err := checkColumn(d, cfContracts, []keyPair{
+ {
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
+ "0b436f6e7472616374203734" + // Contract 74
+ "03533734" + // S74
+ "054552433230" + // ERC20
+ varuintToHex(12) + varuintToHex(44444) + varuintToHex(destructedInBlock),
+ nil,
+ },
+ }); err != nil {
+ {
+ t.Fatal(err)
+ }
+ }
+
if err := checkColumn(d, cfInternalData, []keyPair{
{
dbtestdata.EthTxidB1T2,
@@ -98,7 +117,7 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" +
dbtestdata.EthTxidB1T2 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
- "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"),
+ "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"),
nil,
},
}
@@ -158,43 +177,43 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
if err := checkColumn(d, cfAddressContracts, []keyPair{
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
- "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintToHex(big.NewInt(0)), nil,
+ "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintToHex(big.NewInt(0)), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser),
- "030202" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(1) + bigintFromStringToHex("150") + bigintFromStringToHex("1"), nil,
+ "030202" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(1) + bigintFromStringToHex("150") + bigintFromStringToHex("1"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser),
"010101" +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("8086") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("871180000950184"), nil,
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("8086") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("871180000950184"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
"050300" +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("10000000854307892726464") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0"), nil,
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000854307892726464") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser),
- "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(2) + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10"), nil,
+ "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(2) + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser),
"020000" +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("7674999999999991915") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC721)) + varuintToHex(1) + bigintFromStringToHex("1"), nil,
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("7674999999999991915") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.NonFungibleToken)) + varuintToHex(1) + bigintFromStringToHex("1"), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser),
- "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC721)) + varuintToHex(0), nil,
+ "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.NonFungibleToken)) + varuintToHex(0), nil,
},
{
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser),
- "010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(0), nil,
+ "010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(0), nil,
},
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser), "010100", nil},
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "030104", nil},
@@ -209,6 +228,21 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
}
}
+ if err := checkColumn(d, cfContracts, []keyPair{
+ {
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
+ "0b436f6e7472616374203734" + // Contract 74
+ "03533734" + // S74
+ "054552433230" + // ERC20
+ varuintToHex(12) + varuintToHex(44444) + varuintToHex(44445),
+ nil,
+ },
+ }); err != nil {
+ {
+ t.Fatal(err)
+ }
+ }
+
if err := checkColumn(d, cfInternalData, []keyPair{
{
dbtestdata.EthTxidB1T2,
@@ -243,22 +277,22 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" +
dbtestdata.EthTxidB2T2 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser) +
- "04" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("7675000000000000001") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("854307892726464") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("871180000950184") +
- dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("7674999999999991915") +
+ "04" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("7675000000000000001") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("854307892726464") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("871180000950184") +
+ dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("7674999999999991915") +
dbtestdata.EthTxidB2T3 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) +
- "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(uint(bchain.ERC721)) + bigintFromStringToHex("1") +
+ "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(uint(bchain.NonFungibleToken)) + bigintFromStringToHex("1") +
dbtestdata.EthTxidB2T4 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser) +
- "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.ERC1155)) + "01" + bigintFromStringToHex("150") + bigintFromStringToHex("1") +
+ "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.MultiToken)) + "01" + bigintFromStringToHex("150") + bigintFromStringToHex("1") +
dbtestdata.EthTxidB2T5 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) +
- "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrZero, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.ERC1155)) + "02" + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10") +
+ "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrZero, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.MultiToken)) + "02" + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10") +
dbtestdata.EthTxidB2T6 +
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) +
- "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"),
+ "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"),
nil,
},
}); err != nil {
@@ -722,13 +756,13 @@ func Test_packUnpackAddrContracts(t *testing.T) {
InternalTxs: 8873,
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract0d, parser),
Txs: 8,
Value: *big.NewInt(793201132),
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Txs: 41235,
Ids: []big.Int{
@@ -740,10 +774,10 @@ func Test_packUnpackAddrContracts(t *testing.T) {
},
},
{
- Type: bchain.ERC1155,
+ Type: bchain.MultiToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
Txs: 64,
- IdValues: []bchain.TokenTransferIdValue{
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(1),
Value: *big.NewInt(1412341234),
@@ -796,7 +830,7 @@ func Test_addToContracts(t *testing.T) {
index: 1,
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Value: *big.NewInt(123456),
},
addTxCount: true,
@@ -805,7 +839,7 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Txs: 1,
Value: *big.NewInt(123456),
@@ -819,7 +853,7 @@ func Test_addToContracts(t *testing.T) {
index: ^1,
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Value: *big.NewInt(23456),
},
addTxCount: true,
@@ -828,7 +862,7 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
@@ -842,7 +876,7 @@ func Test_addToContracts(t *testing.T) {
index: 1,
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Value: *big.NewInt(1),
},
addTxCount: true,
@@ -851,13 +885,13 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 1,
Ids: []big.Int{*big.NewInt(1)},
@@ -871,7 +905,7 @@ func Test_addToContracts(t *testing.T) {
index: 1,
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Value: *big.NewInt(2),
},
addTxCount: true,
@@ -880,13 +914,13 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 2,
Ids: []big.Int{*big.NewInt(1), *big.NewInt(2)},
@@ -900,7 +934,7 @@ func Test_addToContracts(t *testing.T) {
index: ^1,
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Value: *big.NewInt(1),
},
addTxCount: false,
@@ -909,13 +943,13 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 2,
Ids: []big.Int{*big.NewInt(2)},
@@ -929,8 +963,8 @@ func Test_addToContracts(t *testing.T) {
index: 1,
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC1155,
- IdValues: []bchain.TokenTransferIdValue{
+ Type: bchain.MultiToken,
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(56789),
@@ -943,22 +977,22 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 2,
Ids: []big.Int{*big.NewInt(2)},
},
{
- Type: bchain.ERC1155,
+ Type: bchain.MultiToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
Txs: 1,
- IdValues: []bchain.TokenTransferIdValue{
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(56789),
@@ -974,8 +1008,8 @@ func Test_addToContracts(t *testing.T) {
index: 1,
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC1155,
- IdValues: []bchain.TokenTransferIdValue{
+ Type: bchain.MultiToken,
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(111),
@@ -992,22 +1026,22 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 2,
Ids: []big.Int{*big.NewInt(2)},
},
{
- Type: bchain.ERC1155,
+ Type: bchain.MultiToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
Txs: 2,
- IdValues: []bchain.TokenTransferIdValue{
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(56900),
@@ -1027,8 +1061,8 @@ func Test_addToContracts(t *testing.T) {
index: ^1,
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
transfer: &bchain.TokenTransfer{
- Type: bchain.ERC1155,
- IdValues: []bchain.TokenTransferIdValue{
+ Type: bchain.MultiToken,
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(112),
@@ -1045,22 +1079,22 @@ func Test_addToContracts(t *testing.T) {
wantAddrContracts: &AddrContracts{
Contracts: []AddrContract{
{
- Type: bchain.ERC20,
+ Type: bchain.FungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
Value: *big.NewInt(100000),
Txs: 2,
},
{
- Type: bchain.ERC721,
+ Type: bchain.NonFungibleToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
Txs: 2,
Ids: []big.Int{*big.NewInt(2)},
},
{
- Type: bchain.ERC1155,
+ Type: bchain.MultiToken,
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
Txs: 3,
- IdValues: []bchain.TokenTransferIdValue{
+ MultiTokenValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(11),
Value: *big.NewInt(56788),
@@ -1119,7 +1153,7 @@ func Test_packUnpackBlockTx(t *testing.T) {
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
to: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
- transferType: bchain.ERC20,
+ transferType: bchain.FungibleToken,
value: *big.NewInt(10000),
},
},
@@ -1137,22 +1171,22 @@ func Test_packUnpackBlockTx(t *testing.T) {
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
to: addressToAddrDesc(dbtestdata.EthAddr3e, parser),
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
- transferType: bchain.ERC20,
+ transferType: bchain.FungibleToken,
value: *big.NewInt(987654321),
},
{
from: addressToAddrDesc(dbtestdata.EthAddr4b, parser),
to: addressToAddrDesc(dbtestdata.EthAddr55, parser),
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
- transferType: bchain.ERC721,
+ transferType: bchain.NonFungibleToken,
value: *big.NewInt(13),
},
{
from: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
to: addressToAddrDesc(dbtestdata.EthAddr7b, parser),
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
- transferType: bchain.ERC1155,
- idValues: []bchain.TokenTransferIdValue{
+ transferType: bchain.MultiToken,
+ idValues: []bchain.MultiTokenValue{
{
Id: *big.NewInt(1234),
Value: *big.NewInt(98765),
@@ -1222,3 +1256,45 @@ func Test_packUnpackFourByteSignature(t *testing.T) {
})
}
}
+
+func Test_packUnpackContractInfo(t *testing.T) {
+ tests := []struct {
+ name string
+ contractInfo bchain.ContractInfo
+ }{
+ {
+ name: "empty",
+ contractInfo: bchain.ContractInfo{},
+ },
+ {
+ name: "unknown",
+ contractInfo: bchain.ContractInfo{
+ Type: bchain.UnknownTokenType,
+ Name: "Test contract",
+ Symbol: "TCT",
+ Decimals: 18,
+ CreatedInBlock: 1234567,
+ DestructedInBlock: 234567890,
+ },
+ },
+ {
+ name: "ERC20",
+ contractInfo: bchain.ContractInfo{
+ Type: bchain.ERC20TokenType,
+ Name: "GreenContract🟢",
+ Symbol: "🟢",
+ Decimals: 0,
+ CreatedInBlock: 1,
+ DestructedInBlock: 2,
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ buf := packContractInfo(&tt.contractInfo)
+ if got, err := unpackContractInfo(buf); !reflect.DeepEqual(*got, tt.contractInfo) || err != nil {
+ t.Errorf("packUnpackContractInfo() = %v, want %v, error %v", *got, tt.contractInfo, err)
+ }
+ })
+ }
+}
diff --git a/server/public.go b/server/public.go
index be0dc402..963056dd 100644
--- a/server/public.go
+++ b/server/public.go
@@ -562,7 +562,7 @@ func isOwnAddress(td *TemplateData, a string) bool {
}
// called from template, returns count of token transfers of given type in a tx
-func tokenTransfersCount(tx *api.Tx, t api.TokenType) int {
+func tokenTransfersCount(tx *api.Tx, t bchain.TokenTypeName) int {
count := 0
for i := range tx.TokenTransfers {
if tx.TokenTransfers[i].Type == t {
@@ -573,7 +573,7 @@ func tokenTransfersCount(tx *api.Tx, t api.TokenType) int {
}
// called from template, returns count of tokens in array of given type
-func tokenCount(tokens []api.Token, t api.TokenType) int {
+func tokenCount(tokens []api.Token, t bchain.TokenTypeName) int {
count := 0
for i := range tokens {
if tokens[i].Type == t {
diff --git a/server/public_ethereumtype_test.go b/server/public_ethereumtype_test.go
index bd4461c6..93367959 100644
--- a/server/public_ethereumtype_test.go
+++ b/server/public_ethereumtype_test.go
@@ -24,7 +24,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "text/html; charset=utf-8",
body: []string{
- `
Trezor Fake Coin ExplorerContract Contract 123 (S123) 0.000000000123450123 FAKE
0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b
Confirmed
| Balance | 0.000000000123450123 FAKE |
| Transactions | 2 |
| Non-contract Transactions | 0 |
| Internal Transactions | 0 |
| Nonce | 123 |
| ERC20 Tokens | |
| ERC721 Tokens | |
Transactions
ERC721 Token Transfers
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
ID 1 S205
Fee: 0.00008794500041041 FAKE
Unconfirmed Transaction!0 FAKE
ERC20 Token Transfers
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
0.000871180000950184 S74
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
7.674999999999991915 S13
Fee: 0.000216368 FAKE
Unconfirmed Transaction!0 FAKE
`,
+ `Trezor Fake Coin ExplorerAddress 0.000000000123450123 FAKE
0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b
Confirmed
| Balance | 0.000000000123450123 FAKE |
| Transactions | 2 |
| Non-contract Transactions | 0 |
| Internal Transactions | 0 |
| Nonce | 123 |
| ERC20 Tokens | |
| ERC721 Tokens | |
Transactions
ERC721 Token Transfers
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
ID 1 S205
Fee: 0.00008794500041041 FAKE
Unconfirmed Transaction!0 FAKE
ERC20 Token Transfers
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
871.180000950184 S74
| 0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b |
7.674999999999991915 S13
Fee: 0.000216368 FAKE
Unconfirmed Transaction!0 FAKE
`,
},
},
{
@@ -33,7 +33,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "text/html; charset=utf-8",
body: []string{
- `Trezor Fake Coin ExplorerContract Contract 93 (S93) 0.000000000123450093 FAKE
0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e
Confirmed
| Balance | 0.000000000123450093 FAKE |
| Transactions | 1 |
| Non-contract Transactions | 1 |
| Internal Transactions | 0 |
| Nonce | 93 |
| ERC1155 Tokens | | Contract | Tokens | Transfers |
|---|
| Contract 111 | 1776:1 S111, 1898:10 S111 | 1 |
|
Transactions
| 0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e |
0 FAKE
ERC1155 Token Transfers
| 0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e |
1776:1 S1111898:10 S111
Fee: 0.000081891755740665 FAKE
Unconfirmed Transaction!0 FAKE
`,
+ `Trezor Fake Coin ExplorerAddress 0.000000000123450093 FAKE
0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e
Confirmed
| Balance | 0.000000000123450093 FAKE |
| Transactions | 1 |
| Non-contract Transactions | 1 |
| Internal Transactions | 0 |
| Nonce | 93 |
| ERC1155 Tokens | | Contract | Tokens | Transfers |
|---|
| Contract 111 | 1776:1 S111, 1898:10 S111 | 1 |
|
Transactions
| 0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e |
0 FAKE
ERC1155 Token Transfers
| 0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e |
1776:1 S1111898:10 S111
Fee: 0.000081891755740665 FAKE
Unconfirmed Transaction!0 FAKE
`,
},
},
{
@@ -42,7 +42,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "text/html; charset=utf-8",
body: []string{
- `Trezor Fake Coin ExplorerTransaction
0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101
Summary
| In Block | Unconfirmed |
| Status | Success |
| Value | 0 FAKE |
| Gas Used / Limit | 52025 / 78037 |
| Gas Price | 0.00000004 FAKE |
| Fees | 0.002081 FAKE |
| RBF | ON |
Details
Transfer
Method ID: 0xa9059cbb
ERC20 Token Transfers
Fee: 0.002081 FAKE
Unconfirmed Transaction!0 FAKE
Input Data
Transfer
Method ID: 0xa9059cbb
Function: transfer(address, uint256)
`,
+ `Trezor Fake Coin ExplorerTransaction
0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101
Summary
| In Block | Unconfirmed |
| Status | Success |
| Value | 0 FAKE |
| Gas Used / Limit | 52025 / 78037 |
| Gas Price | 0.00000004 FAKE |
| Fees | 0.002081 FAKE |
| RBF | ON |
Details
Transfer
Method ID: 0xa9059cbb
ERC20 Token Transfers
Fee: 0.002081 FAKE
Unconfirmed Transaction!0 FAKE
Input Data
Transfer
Method ID: 0xa9059cbb
Function: transfer(address, uint256)
`,
},
},
{
@@ -64,7 +64,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
- `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","balance":"123450075","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":1,"nonTokenTxs":1,"internalTxs":1,"txids":["0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2"],"nonce":"75","tokens":[{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":2,"symbol":"S13","decimals":18,"balance":"1000075013"},{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":2,"symbol":"S74","decimals":18,"balance":"1000075074"}],"erc20Contract":{"contract":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","name":"Contract 75","symbol":"S75","decimals":18}}`,
+ `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","balance":"123450075","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":1,"nonTokenTxs":1,"internalTxs":1,"txids":["0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2"],"nonce":"75","tokens":[{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":2,"symbol":"S13","decimals":18,"balance":"1000075013"},{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":2,"symbol":"S74","decimals":12,"balance":"1000075074"}]}`,
},
},
{
@@ -73,7 +73,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
- `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","balance":"123450123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"transactions":[{"txid":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","vin":[{"n":0,"addresses":["0x837E3f699d85a4b0B99894567e9233dFB1DcB081"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"87945000410410","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x2","gasPrice":"0x59682f07","gas":"0x173a9","to":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","value":"0x0","input":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","hash":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","blockNumber":"0xb33b9f","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","transactionIndex":"0x1"},"receipt":{"gasUsed":"0xe506","status":"0x1","logs":[{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"},{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"}]}},"tokenTransfers":[{"type":"ERC721","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","token":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","name":"Contract 205","symbol":"S205","decimals":18,"value":"1"}],"ethereumSpecific":{"status":1,"nonce":2,"gasLimit":95145,"gasUsed":58630,"gasPrice":"1500000007","data":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","parsedData":{"methodId":"0x23b872dd","name":""}}},{"txid":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","vin":[{"n":0,"addresses":["0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x479CC461fEcd078F766eCc58533D6F69580CF3AC"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"216368000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x1df76","gasPrice":"0x3b9aca00","gas":"0x3d090","to":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","value":"0x0","input":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","hash":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","blockNumber":"0x41eee9","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","transactionIndex":"0x24"},"internalData":{"type":1,"contract":"0d0f936ee4c93e25944694d6c121de94d9760f11","transfers":[{"type":0,"from":"4bda106325c335df99eab7fe363cac8a0ba2a24d","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000010},{"type":2,"from":"4af4114f73d1c1c903ac9e0361b379d1291808a2","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000011}],"Error":""},"receipt":{"gasUsed":"0x34d30","status":"0x1","logs":[{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f8001"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x000000000000000000000000000000000000000000000000000308fd0e798ac0"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000000000000000000000000000000000000000000000","0x5af266c0a89a07c1917deaa024414577e6c3c31c8907d079e13eb448c082594f"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000000000000000000000000006a8313d60b1f8001000000000000000000000000000000000000000000000000000308fd0e798ac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e083a16f4b092c5729a49f9c3ed3cc171bb3d3d0c22e20b1de6063c32f399ac"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x00000000000000000000000000000000000000000000000000031855667df7a8"},{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f606b"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000000","0xb0b69dad58df6032c3b266e19b1045b19c87acd2c06fb0c598090f44b8e263aa"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f1100000000000000000000000000000000000000000000000000031855667df7a80000000000000000000000000000000000000000000000006a8313d60b1f606b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f2b0d62c44ed08f2a5adef40c875d20310a42a9d4f488bd26323256fe01c7f48"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","token":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7675000000000000001"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":18,"value":"854307892726464"},{"type":"ERC20","from":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":18,"value":"871180000950184"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","token":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7674999999999991915"}],"ethereumSpecific":{"status":1,"nonce":122742,"gasLimit":250000,"gasUsed":216368,"gasPrice":"1000000000","data":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","parsedData":{"methodId":"0x4f150787","name":""}}}],"nonce":"123","tokens":[{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":1,"symbol":"S74","decimals":18,"balance":"1000123074"},{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":1,"symbol":"S13","decimals":18,"balance":"1000123013"},{"type":"ERC721","name":"Contract 205","contract":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","transfers":1,"symbol":"S205","decimals":18,"ids":["1"]}],"erc20Contract":{"contract":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","name":"Contract 123","symbol":"S123","decimals":18},"addressAliases":{"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b":{"Type":"ENS","Alias":"address7b.eth"}}}`,
+ `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","balance":"123450123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"transactions":[{"txid":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","vin":[{"n":0,"addresses":["0x837E3f699d85a4b0B99894567e9233dFB1DcB081"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"87945000410410","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x2","gasPrice":"0x59682f07","gas":"0x173a9","to":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","value":"0x0","input":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","hash":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","blockNumber":"0xb33b9f","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","transactionIndex":"0x1"},"receipt":{"gasUsed":"0xe506","status":"0x1","logs":[{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"},{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"}]}},"tokenTransfers":[{"type":"ERC721","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","token":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","name":"Contract 205","symbol":"S205","decimals":18,"value":"1"}],"ethereumSpecific":{"status":1,"nonce":2,"gasLimit":95145,"gasUsed":58630,"gasPrice":"1500000007","data":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","parsedData":{"methodId":"0x23b872dd","name":""}}},{"txid":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","vin":[{"n":0,"addresses":["0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x479CC461fEcd078F766eCc58533D6F69580CF3AC"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"216368000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x1df76","gasPrice":"0x3b9aca00","gas":"0x3d090","to":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","value":"0x0","input":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","hash":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","blockNumber":"0x41eee9","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","transactionIndex":"0x24"},"internalData":{"type":1,"contract":"0d0f936ee4c93e25944694d6c121de94d9760f11","transfers":[{"type":0,"from":"4bda106325c335df99eab7fe363cac8a0ba2a24d","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000010},{"type":2,"from":"4af4114f73d1c1c903ac9e0361b379d1291808a2","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000011}],"Error":""},"receipt":{"gasUsed":"0x34d30","status":"0x1","logs":[{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f8001"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x000000000000000000000000000000000000000000000000000308fd0e798ac0"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000000000000000000000000000000000000000000000","0x5af266c0a89a07c1917deaa024414577e6c3c31c8907d079e13eb448c082594f"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000000000000000000000000006a8313d60b1f8001000000000000000000000000000000000000000000000000000308fd0e798ac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e083a16f4b092c5729a49f9c3ed3cc171bb3d3d0c22e20b1de6063c32f399ac"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x00000000000000000000000000000000000000000000000000031855667df7a8"},{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f606b"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000000","0xb0b69dad58df6032c3b266e19b1045b19c87acd2c06fb0c598090f44b8e263aa"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f1100000000000000000000000000000000000000000000000000031855667df7a80000000000000000000000000000000000000000000000006a8313d60b1f606b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f2b0d62c44ed08f2a5adef40c875d20310a42a9d4f488bd26323256fe01c7f48"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","token":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7675000000000000001"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"854307892726464"},{"type":"ERC20","from":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"871180000950184"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","token":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7674999999999991915"}],"ethereumSpecific":{"status":1,"nonce":122742,"gasLimit":250000,"gasUsed":216368,"gasPrice":"1000000000","data":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","parsedData":{"methodId":"0x4f150787","name":""}}}],"nonce":"123","tokens":[{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":1,"symbol":"S74","decimals":12,"balance":"1000123074"},{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":1,"symbol":"S13","decimals":18,"balance":"1000123013"},{"type":"ERC721","name":"Contract 205","contract":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","transfers":1,"symbol":"S205","decimals":18,"ids":["1"]}],"addressAliases":{"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b":{"Type":"ENS","Alias":"address7b.eth"}}}`,
},
},
{
@@ -82,7 +82,7 @@ func httpTestsEthereumType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
- `{"txid":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","vin":[{"n":0,"addresses":["0x20cD153de35D469BA46127A0C8F18626b59a256A"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x4af4114F73d1c1C903aC9E0361b379D1291808A2"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"2081000000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0xd0","gasPrice":"0x9502f9000","gas":"0x130d5","to":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","value":"0x0","input":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","hash":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","blockNumber":"0x41eee8","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","transactionIndex":"0x0"},"internalData":{"type":0,"transfers":[{"type":1,"from":"9f4981531fda132e83c44680787dfa7ee31e4f8d","to":"4af4114f73d1c1c903ac9e0361b379d1291808a2","value":1000000},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000001},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","value":1000002}],"Error":""},"receipt":{"gasUsed":"0xcb39","status":"0x1","logs":[{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000020cd153de35d469ba46127a0c8f18626b59a256a","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":18,"value":"10000000000000000000000"}],"ethereumSpecific":{"status":1,"nonce":208,"gasLimit":78037,"gasUsed":52025,"gasPrice":"40000000000","data":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","parsedData":{"methodId":"0xa9059cbb","name":"Transfer","function":"transfer(address, uint256)","params":[{"type":"address","values":["0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"]},{"type":"uint256","values":["10000000000000000000000"]}]}},"addressAliases":{"0x20cD153de35D469BA46127A0C8F18626b59a256A":{"Type":"ENS","Alias":"address20.eth"}}}`,
+ `{"txid":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","vin":[{"n":0,"addresses":["0x20cD153de35D469BA46127A0C8F18626b59a256A"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x4af4114F73d1c1C903aC9E0361b379D1291808A2"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"2081000000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0xd0","gasPrice":"0x9502f9000","gas":"0x130d5","to":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","value":"0x0","input":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","hash":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","blockNumber":"0x41eee8","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","transactionIndex":"0x0"},"internalData":{"type":0,"transfers":[{"type":1,"from":"9f4981531fda132e83c44680787dfa7ee31e4f8d","to":"4af4114f73d1c1c903ac9e0361b379d1291808a2","value":1000000},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000001},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","value":1000002}],"Error":""},"receipt":{"gasUsed":"0xcb39","status":"0x1","logs":[{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000020cd153de35d469ba46127a0c8f18626b59a256a","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","token":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"10000000000000000000000"}],"ethereumSpecific":{"status":1,"nonce":208,"gasLimit":78037,"gasUsed":52025,"gasPrice":"40000000000","data":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","parsedData":{"methodId":"0xa9059cbb","name":"Transfer","function":"transfer(address, uint256)","params":[{"type":"address","values":["0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"]},{"type":"uint256","values":["10000000000000000000000"]}]}},"addressAliases":{"0x20cD153de35D469BA46127A0C8F18626b59a256A":{"Type":"ENS","Alias":"address20.eth"},"0x4af4114F73d1c1C903aC9E0361b379D1291808A2":{"Type":"Contract","Alias":"Contract 74"}}}`,
},
},
}
diff --git a/server/websocket.go b/server/websocket.go
index 27a73827..ab47f565 100644
--- a/server/websocket.go
+++ b/server/websocket.go
@@ -896,7 +896,7 @@ func (s *WebsocketServer) sendOnNewTxAddr(stringAddressDescriptor string, tx *ap
}
func (s *WebsocketServer) getNewTxSubscriptions(tx *bchain.MempoolTx) map[string]struct{} {
- // check if there is any subscription in inputs, outputs and erc20
+ // check if there is any subscription in inputs, outputs and token transfers
s.addressSubscriptionsLock.Lock()
defer s.addressSubscriptionsLock.Unlock()
subscribed := make(map[string]struct{})
diff --git a/static/templates/address.html b/static/templates/address.html
index c662ff12..987ea89e 100644
--- a/static/templates/address.html
+++ b/static/templates/address.html
@@ -1,5 +1,5 @@
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
-{{if $addr.Erc20Contract}}Contract {{$addr.Erc20Contract.Name}} ({{$addr.Erc20Contract.Symbol}}){{else}}Address{{end}} {{formatAmount $addr.BalanceSat}} {{$cs}}
+{{if $addr.ContractInfo}}Contract {{$addr.ContractInfo.Name}} ({{$addr.ContractInfo.Symbol}}){{else}}Address{{end}} {{formatAmount $addr.BalanceSat}} {{$cs}}
{{$addr.AddrStr}}
@@ -98,7 +98,7 @@
| {{if $t.Contract}}{{$t.Name}}{{else}}{{$t.Name}}{{end}} |
- {{range $i, $iv := $t.IdValues}}{{if $i}}, {{end}}{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$t.Symbol}}{{end}}
+ {{range $i, $iv := $t.MultiTokenValues}}{{if $i}}, {{end}}{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$t.Symbol}}{{end}}
|
{{$t.Transfers}} |
diff --git a/static/templates/txdetail_ethereumtype.html b/static/templates/txdetail_ethereumtype.html
index d47d7f0c..28bcfe78 100644
--- a/static/templates/txdetail_ethereumtype.html
+++ b/static/templates/txdetail_ethereumtype.html
@@ -267,7 +267,7 @@
- {{- range $iv := $tt.Values -}}
+ {{- range $iv := $tt.MultiTokenValues -}}
{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$tt.Symbol}}
{{- end -}}
diff --git a/tests/dbtestdata/dbtestdata_ethereumtype.go b/tests/dbtestdata/dbtestdata_ethereumtype.go
index e34012bd..41cfac57 100644
--- a/tests/dbtestdata/dbtestdata_ethereumtype.go
+++ b/tests/dbtestdata/dbtestdata_ethereumtype.go
@@ -128,6 +128,19 @@ var EthTx4InternalData = &bchain.EthereumInternalData{
},
}
+var Block1SpecificData = &bchain.EthereumBlockSpecificData{
+ Contracts: []bchain.ContractInfo{
+ {
+ Contract: EthAddrContract4a,
+ Type: bchain.ERC20TokenType,
+ Name: "Contract 74",
+ Symbol: "S74",
+ Decimals: 12,
+ CreatedInBlock: 44444,
+ },
+ },
+}
+
var Block2SpecificData = &bchain.EthereumBlockSpecificData{
InternalDataError: "test error",
AddressAliasRecords: []bchain.AddressAliasRecord{
@@ -140,6 +153,12 @@ var Block2SpecificData = &bchain.EthereumBlockSpecificData{
Name: "address20",
},
},
+ Contracts: []bchain.ContractInfo{
+ {
+ Contract: EthAddrContract4a,
+ DestructedInBlock: 44445,
+ },
+ },
}
type packedAndInternal struct {
@@ -182,6 +201,7 @@ func GetTestEthereumTypeBlock1(parser bchain.BlockChainParser) *bchain.Block {
packed: EthTx2Packed,
internal: EthTx2InternalData,
}}, parser),
+ CoinSpecificData: Block1SpecificData,
}
}
diff --git a/tests/dbtestdata/fakechain_ethereumtype.go b/tests/dbtestdata/fakechain_ethereumtype.go
index b1927616..4ee50472 100644
--- a/tests/dbtestdata/fakechain_ethereumtype.go
+++ b/tests/dbtestdata/fakechain_ethereumtype.go
@@ -117,13 +117,15 @@ func (c *fakeBlockChainEthereumType) EthereumTypeGetNonce(addrDesc bchain.Addres
return uint64(addrDesc[0]), nil
}
-func (c *fakeBlockChainEthereumType) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) {
+func (c *fakeBlockChainEthereumType) GetContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.ContractInfo, error) {
addresses, _, _ := c.Parser.GetAddressesFromAddrDesc(contractDesc)
- return &bchain.Erc20Contract{
- Contract: addresses[0],
- Name: "Contract " + strconv.Itoa(int(contractDesc[0])),
- Symbol: "S" + strconv.Itoa(int(contractDesc[0])),
- Decimals: 18,
+ return &bchain.ContractInfo{
+ Type: bchain.ERC20TokenType,
+ Contract: addresses[0],
+ Name: "Contract " + strconv.Itoa(int(contractDesc[0])),
+ Symbol: "S" + strconv.Itoa(int(contractDesc[0])),
+ Decimals: 18,
+ CreatedInBlock: 12345,
}, nil
}