Add BNB Smart Chain (#869)

This commit is contained in:
kevin 2023-03-09 02:54:38 -07:00 committed by GitHub
parent adf50156bf
commit 9ecfdfe11d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 596 additions and 107 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/trezor/blockbook/bchain/coins/bellcoin"
"github.com/trezor/blockbook/bchain/coins/bitcore"
"github.com/trezor/blockbook/bchain/coins/bitzeny"
"github.com/trezor/blockbook/bchain/coins/bsc"
"github.com/trezor/blockbook/bchain/coins/btc"
"github.com/trezor/blockbook/bchain/coins/btg"
"github.com/trezor/blockbook/bchain/coins/cpuchain"
@ -134,6 +135,8 @@ func init() {
BlockChainFactories["ECash"] = ecash.NewECashRPC
BlockChainFactories["Avalanche"] = avalanche.NewAvalancheRPC
BlockChainFactories["Avalanche Archive"] = avalanche.NewAvalancheRPC
BlockChainFactories["BNB Smart Chain"] = bsc.NewBNBSmartChainRPC
BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC
}
// GetCoinNameFromConfig gets coin name and coin shortcut from config file

View File

@ -0,0 +1,91 @@
package bsc
import (
"context"
"encoding/json"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/eth"
)
const (
// MainNet is production network
MainNet eth.Network = 56
// bsc token type names
BEP20TokenType bchain.TokenTypeName = "BEP20"
BEP721TokenType bchain.TokenTypeName = "BEP721"
BEP1155TokenType bchain.TokenTypeName = "BEP1155"
)
// BNBSmartChainRPC is an interface to JSON-RPC bsc service.
type BNBSmartChainRPC struct {
*eth.EthereumRPC
}
// NewBNBSmartChainRPC returns new BNBSmartChainRPC instance.
func NewBNBSmartChainRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
c, err := eth.NewEthereumRPC(config, pushHandler)
if err != nil {
return nil, err
}
// overwrite EthereumTokenTypeMap with bsc specific token type names
bchain.EthereumTokenTypeMap = []bchain.TokenTypeName{BEP20TokenType, BEP721TokenType, BEP1155TokenType}
s := &BNBSmartChainRPC{
EthereumRPC: c.(*eth.EthereumRPC),
}
return s, nil
}
// Initialize bnb smart chain rpc interface
func (b *BNBSmartChainRPC) Initialize() error {
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
r, err := rpc.Dial(url)
if err != nil {
return nil, nil, err
}
rc := &eth.EthereumRPCClient{Client: r}
ec := &eth.EthereumClient{Client: ethclient.NewClient(r)}
return rc, ec, nil
}
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
if err != nil {
return err
}
// set chain specific
b.Client = ec
b.RPC = rc
b.MainNetChainID = MainNet
b.NewBlock = eth.NewEthereumNewBlock()
b.NewTx = eth.NewEthereumNewTx()
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
defer cancel()
id, err := b.Client.NetworkID(ctx)
if err != nil {
return err
}
// parameters for getInfo request
switch eth.Network(id.Uint64()) {
case MainNet:
b.Testnet = false
b.Network = "livenet"
default:
return errors.Errorf("Unknown network id %v", id)
}
glog.Info("rpc: block chain ", b.Network)
return nil
}

View File

@ -92,6 +92,11 @@ type EthereumNewBlock struct {
channel chan *types.Header
}
// NewEthereumNewBlock returns an initialized EthereumNewBlock struct
func NewEthereumNewBlock() *EthereumNewBlock {
return &EthereumNewBlock{channel: make(chan *types.Header)}
}
// Channel returns the underlying channel as an empty interface
func (s *EthereumNewBlock) Channel() interface{} {
return s.channel
@ -113,6 +118,11 @@ type EthereumNewTx struct {
channel chan common.Hash
}
// NewEthereumNewTx returns an initialized EthereumNewTx struct
func NewEthereumNewTx() *EthereumNewTx {
return &EthereumNewTx{channel: make(chan common.Hash)}
}
// Channel returns the underlying channel as an empty interface
func (s *EthereumNewTx) Channel() interface{} {
return s.channel

View File

@ -120,9 +120,9 @@ type TokenType int
// TokenType enumeration
const (
FungibleToken = TokenType(iota) // ERC20
NonFungibleToken // ERC721
MultiToken // ERC1155
FungibleToken = TokenType(iota) // ERC20/BEP20
NonFungibleToken // ERC721/BEP721
MultiToken // ERC1155/BEP1155
)
// TokenTypeName specifies type of token

View File

@ -6,8 +6,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
)
// EthereumType specific
// EthereumInternalTransfer contains data about internal transfer
type EthereumInternalTransfer struct {
Type EthereumInternalTransactionType `json:"type"`
@ -16,6 +14,7 @@ type EthereumInternalTransfer struct {
Value big.Int `json:"value"`
}
// FourByteSignature contains data about about a contract function signature
type FourByteSignature struct {
// stored in DB
Name string
@ -26,10 +25,13 @@ type FourByteSignature struct {
ParsedParameters []abi.Type
}
// EthereumParsedInputParam contains data about a contract function parameter
type EthereumParsedInputParam struct {
Type string `json:"type"`
Values []string `json:"values,omitempty"`
}
// EthereumParsedInputData contains the parsed data for an input data hex payload
type EthereumParsedInputData struct {
MethodId string `json:"methodId"`
Name string `json:"name"`
@ -75,7 +77,7 @@ const (
// 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}
var EthereumTokenTypeMap = []TokenTypeName{ERC20TokenType, ERC771TokenType, ERC1155TokenType}
type MultiTokenValue struct {
Id big.Int

View File

@ -3,4 +3,5 @@
backend/* {{.Env.BackendInstallPath}}/{{.Coin.Alias}}
server.conf => {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf
client.conf => {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}_client.conf
{{if .Backend.ExecScript }}exec.sh => {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}_exec.sh{{end}}
{{end}}

View File

@ -0,0 +1,40 @@
#!/bin/sh
{{define "main" -}}
set -e
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
GETH_BIN=$INSTALL_DIR/geth_linux
CHAINDATA_DIR=$DATA_DIR/geth/chaindata
if [ ! -d "$CHAINDATA_DIR" ]; then
$GETH_BIN init --datadir $DATA_DIR $INSTALL_DIR/genesis.json
fi
$GETH_BIN \
--config $INSTALL_DIR/config.toml \
--datadir $DATA_DIR \
--port {{.Ports.BackendP2P}} \
--http \
--http.addr 127.0.0.1 \
--http.port {{.Ports.BackendHttp}} \
--http.api eth,net,web3,debug,txpool \
--http.vhosts '*' \
--http.corsdomain '*' \
--ws \
--ws.addr 127.0.0.1 \
--ws.port {{.Ports.BackendRPC}} \
--ws.api eth,net,web3,debug,txpool \
--ws.origins '*' \
--syncmode full \
--maxpeers 100 \
--rpc.allow-unprotected-txs \
--txlookuplimit 0 \
--cache 8000 \
--ipcdisable \
--nat none
{{end}}

View File

@ -0,0 +1,43 @@
#!/bin/sh
{{define "main" -}}
set -e
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
GETH_BIN=$INSTALL_DIR/geth_linux
CHAINDATA_DIR=$DATA_DIR/geth/chaindata
if [ ! -d "$CHAINDATA_DIR" ]; then
$GETH_BIN init --datadir $DATA_DIR $INSTALL_DIR/genesis.json
fi
$GETH_BIN \
--config $INSTALL_DIR/config.toml \
--datadir $DATA_DIR \
--port {{.Ports.BackendP2P}} \
--http \
--http.addr 127.0.0.1 \
--http.port {{.Ports.BackendHttp}} \
--http.api eth,net,web3,debug,txpool \
--http.vhosts '*' \
--http.corsdomain '*' \
--ws \
--ws.addr 127.0.0.1 \
--ws.port {{.Ports.BackendRPC}} \
--ws.api eth,net,web3,debug,txpool \
--ws.origins '*' \
--gcmode archive \
--cache.gc 0 \
--cache.trie 30 \
--syncmode full \
--maxpeers 100 \
--rpc.allow-unprotected-txs \
--txlookuplimit 0 \
--cache 8000 \
--ipcdisable \
--nat none
{{end}}

View File

@ -26,6 +26,7 @@ type Backend struct {
ExtractCommand string `json:"extract_command"`
ExcludeFiles []string `json:"exclude_files"`
ExecCommandTemplate string `json:"exec_command_template"`
ExecScript string `json:"exec_script"`
LogrotateFilesTemplate string `json:"logrotate_files_template"`
PostinstScriptTemplate string `json:"postinst_script_template"`
ServiceType string `json:"service_type"`
@ -280,11 +281,15 @@ func GeneratePackageDefinitions(config *Config, templateDir, outputDir string) e
}
if !isEmpty(config, "backend") {
err = writeBackendServerConfigFile(config, outputDir)
if err == nil {
err = writeBackendClientConfigFile(config, outputDir)
if err := writeBackendServerConfigFile(config, outputDir); err != nil {
return err
}
if err != nil {
if err := writeBackendClientConfigFile(config, outputDir); err != nil {
return err
}
if err := writeBackendExecScript(config, outputDir); err != nil {
return err
}
}
@ -354,3 +359,24 @@ func writeBackendClientConfigFile(config *Config, outputDir string) error {
_, err = io.Copy(out, in)
return err
}
func writeBackendExecScript(config *Config, outputDir string) error {
if config.Backend.ExecScript == "" {
return nil
}
out, err := os.OpenFile(filepath.Join(outputDir, "backend/exec.sh"), os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
return err
}
defer out.Close()
in, err := os.Open(filepath.Join(outputDir, "backend/scripts", config.Backend.ExecScript))
if err != nil {
return err
}
defer in.Close()
_, err = io.Copy(out, in)
return err
}

71
configs/coins/bsc.json Normal file
View File

@ -0,0 +1,71 @@
{
"coin": {
"name": "BNB Smart Chain",
"shortcut": "BNB",
"label": "BNB Smart Chain",
"alias": "bsc"
},
"ports": {
"backend_rpc": 8064,
"backend_p2p": 38364,
"backend_http": 8164,
"blockbook_internal": 9064,
"blockbook_public": 9164
},
"ipc": {
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
"rpc_timeout": 25
},
"backend": {
"package_name": "backend-bsc",
"package_revision": "satoshilabs-1",
"system_user": "bsc",
"version": "1.1.19",
"binary_url": "https://github.com/bnb-chain/bsc/releases/download/v1.1.19/geth_linux",
"verification_type": "sha256",
"verification_source": "ad49b00a5df44fb67e0dc166a7cf02a02c67ab296d25e4ac3d56134567577c41",
"extract_command": "mv ${ARCHIVE} backend/geth_linux && chmod +x backend/geth_linux && echo",
"exclude_files": [],
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bsc_exec.sh'",
"exec_script": "bsc.sh",
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/bsc.log*",
"postinst_script_template": "wget https://github.com/bnb-chain/bsc/releases/download/v1.1.19/mainnet.zip -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip && unzip -o -d {{.Env.BackendInstallPath}}/{{.Coin.Alias}} {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip && rm -f {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip",
"service_type": "simple",
"service_additional_params_template": "",
"protect_memory": true,
"mainnet": true,
"server_config_file": "",
"client_config_file": "",
"platforms": {
"arm64": {
"binary_url": "https://github.com/bnb-chain/bsc/releases/download/v1.1.19/geth-linux-arm64",
"verification_source": "50aae5defb41cb5f4da462b5f86097c2daf945672ce9fb1c1e4393f6e038610f"
}
}
},
"blockbook": {
"package_name": "blockbook-bsc",
"system_user": "blockbook-bsc",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
"explorer_url": "",
"additional_params": "-workers=16",
"block_chain": {
"parse": true,
"mempool_workers": 8,
"mempool_sub_workers": 2,
"block_addresses_to_keep": 300,
"additional_params": {
"mempoolTxTimeoutHours": 48,
"queryBackendOnMempoolResync": false,
"fiat_rates": "coingecko",
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
"fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"binancecoin\",\"platformIdentifier\": \"binance-smart-chain\",\"platformVsCurrency\": \"bnb\",\"periodSeconds\": 900}"
}
}
},
"meta": {
"package_maintainer": "IT",
"package_maintainer_email": "it@satoshilabs.com"
}
}

View File

@ -0,0 +1,74 @@
{
"coin": {
"name": "BNB Smart Chain Archive",
"shortcut": "BNB",
"label": "BNB Smart Chain",
"alias": "bsc_archive"
},
"ports": {
"backend_rpc": 8065,
"backend_p2p": 38365,
"backend_http": 8165,
"blockbook_internal": 9065,
"blockbook_public": 9165
},
"ipc": {
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
"rpc_timeout": 25
},
"backend": {
"package_name": "backend-bsc-archive",
"package_revision": "satoshilabs-1",
"system_user": "bsc",
"version": "1.1.19",
"binary_url": "https://github.com/bnb-chain/bsc/releases/download/v1.1.19/geth_linux",
"verification_type": "sha256",
"verification_source": "ad49b00a5df44fb67e0dc166a7cf02a02c67ab296d25e4ac3d56134567577c41",
"extract_command": "mv ${ARCHIVE} backend/geth_linux && chmod +x backend/geth_linux && echo",
"exclude_files": [],
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bsc_archive_exec.sh'",
"exec_script": "bsc_archive.sh",
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/bsc.log*",
"postinst_script_template": "wget https://github.com/bnb-chain/bsc/releases/download/v1.1.19/mainnet.zip -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip && unzip -o -d {{.Env.BackendInstallPath}}/{{.Coin.Alias}} {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip && rm -f {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/mainnet.zip",
"service_type": "simple",
"service_additional_params_template": "",
"protect_memory": true,
"mainnet": true,
"server_config_file": "",
"client_config_file": "",
"platforms": {
"arm64": {
"binary_url": "https://github.com/bnb-chain/bsc/releases/download/v1.1.19/geth-linux-arm64",
"verification_source": "50aae5defb41cb5f4da462b5f86097c2daf945672ce9fb1c1e4393f6e038610f"
}
}
},
"blockbook": {
"package_name": "blockbook-bsc-archive",
"system_user": "blockbook-bsc",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
"explorer_url": "",
"additional_params": "-workers=16",
"block_chain": {
"parse": true,
"mempool_workers": 8,
"mempool_sub_workers": 2,
"block_addresses_to_keep": 600,
"additional_params": {
"address_aliases": true,
"mempoolTxTimeoutHours": 48,
"processInternalTransactions": true,
"queryBackendOnMempoolResync": false,
"fiat_rates": "coingecko",
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
"fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"binancecoin\",\"platformIdentifier\": \"binance-smart-chain\",\"platformVsCurrency\": \"bnb\",\"periodSeconds\": 900}",
"fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/"
}
}
},
"meta": {
"package_maintainer": "IT",
"package_maintainer_email": "it@satoshilabs.com"
}
}

View File

@ -1,76 +1,78 @@
# Registry of ports
| coin | blockbook internal port | blockbook public port | backend rpc port | backend service ports (zmq) |
|------------------------|-------------------------|-----------------------|------------------|-----------------------------|
| Bitcoin | 9030 | 9130 | 8030 | 38330 |
| Bitcoin Cash | 9031 | 9131 | 8031 | 38331 |
| Zcash | 9032 | 9132 | 8032 | 38332 |
| Dash | 9033 | 9133 | 8033 | 38333 |
| Litecoin | 9034 | 9134 | 8034 | 38334 |
| Bitcoin Gold | 9035 | 9135 | 8035 | 38335 |
| Ethereum | 9036 | 9136 | 8036 | 38336 p2p, 8136 http |
| Ethereum Classic | 9037 | 9137 | 8037 | |
| Dogecoin | 9038 | 9138 | 8038 | 38338 |
| Namecoin | 9039 | 9139 | 8039 | 38339 |
| Vertcoin | 9040 | 9140 | 8040 | 38340 |
| Monacoin | 9041 | 9141 | 8041 | 38341 |
| DigiByte | 9042 | 9142 | 8042 | 38342 |
| Myriad | 9043 | 9143 | 8043 | 38343 |
| GameCredits | 9044 | 9144 | 8044 | 38344 |
| Groestlcoin | 9045 | 9145 | 8045 | 38345 |
| Bitcoin Cash SV | 9046 | 9146 | 8046 | 38346 |
| Liquid | 9047 | 9147 | 8047 | 38347 |
| Fujicoin | 9048 | 9148 | 8048 | 38348 |
| PIVX | 9049 | 9149 | 8049 | 38349 |
| Firo | 9050 | 9150 | 8050 | 38350 |
| Koto | 9051 | 9151 | 8051 | 38351 |
| Bellcoin | 9052 | 9152 | 8052 | 38352 |
| NULS | 9053 | 9153 | 8053 | 38353 |
| Bitcore | 9054 | 9154 | 8054 | 38354 |
| Viacoin | 9055 | 9155 | 8055 | 38355 |
| VIPSTARCOIN | 9056 | 9156 | 8056 | 38356 |
| MonetaryUnit | 9057 | 9157 | 8057 | 38357 |
| Flux | 9058 | 9158 | 8058 | 38358 |
| Ravencoin | 9059 | 9159 | 8059 | 38359 |
| Ritocoin | 9060 | 9160 | 8060 | 38360 |
| Decred | 9061 | 9161 | 8061 | 38361 |
| SnowGem | 9062 | 9162 | 8062 | 38362 |
| Flo | 9066 | 9166 | 8066 | 38366 |
| Polis | 9067 | 9167 | 8067 | 38367 |
| Qtum | 9088 | 9188 | 8088 | 38388 |
| Divi Project | 9089 | 9189 | 8089 | 38389 |
| CPUchain | 9090 | 9190 | 8090 | 38390 |
| DeepOnion | 9091 | 9191 | 8091 | 38391 |
| Unobtanium | 9092 | 9192 | 65535 | 38392 |
| Omotenashicoin | 9094 | 9194 | 8094 | 38394 |
| BitZeny | 9095 | 9195 | 8095 | 38395 |
| Trezarcoin | 9096 | 9196 | 8096 | 38396 |
| eCash | 9097 | 9197 | 8097 | 38397 |
| Avalanche | 9098 | 9198 | 8098 | 38398 p2p |
| Avalanche Archive | 9099 | 9199 | 8099 | 38399 p2p |
| Bitcoin Signet | 19020 | 19120 | 18020 | 48320 |
| Bitcoin Regtest | 19021 | 19121 | 18021 | 48321 |
| Ethereum Goerli | 19026 | 19126 | 18026 | 48326 p2p |
| Ethereum Sepolia | 19176 | 19176 | 18076 | 48376 p2p |
| Bitcoin Testnet | 19030 | 19130 | 18030 | 48330 |
| Bitcoin Cash Testnet | 19031 | 19131 | 18031 | 48331 |
| Zcash Testnet | 19032 | 19132 | 18032 | 48332 |
| Dash Testnet | 19033 | 19133 | 18033 | 48333 |
| Litecoin Testnet | 19034 | 19134 | 18034 | 48334 |
| Bitcoin Gold Testnet | 19035 | 19135 | 18035 | 48335 |
| Ethereum Ropsten | 19036 | 19136 | 18036 | 48336 p2p |
| Dogecoin Testnet | 19038 | 19138 | 18038 | 48338 |
| Vertcoin Testnet | 19040 | 19140 | 18040 | 48340 |
| Monacoin Testnet | 19041 | 19141 | 18041 | 48341 |
| DigiByte Testnet | 19042 | 19142 | 18042 | 48342 |
| Groestlcoin Testnet | 19045 | 19145 | 18045 | 48345 |
| Groestlcoin Regtest | 19046 | 19146 | 18046 | 48346 |
| Groestlcoin Signet | 19047 | 19147 | 18047 | 48347 |
| PIVX Testnet | 19049 | 19149 | 18049 | 48349 |
| Koto Testnet | 19051 | 19151 | 18051 | 48351 |
| Decred Testnet | 19061 | 19161 | 18061 | 48361 |
| Flo Testnet | 19066 | 19166 | 18066 | 48366 |
| Qtum Testnet | 19088 | 19188 | 18088 | 48388 |
| Omotenashicoin Testnet | 19089 | 19189 | 18089 | 48389 |
| coin | blockbook internal port | blockbook public port | backend rpc port | backend service ports (zmq) |
|-------------------------|-------------------------|-----------------------|------------------|-----------------------------|
| Bitcoin | 9030 | 9130 | 8030 | 38330 |
| Bitcoin Cash | 9031 | 9131 | 8031 | 38331 |
| Zcash | 9032 | 9132 | 8032 | 38332 |
| Dash | 9033 | 9133 | 8033 | 38333 |
| Litecoin | 9034 | 9134 | 8034 | 38334 |
| Bitcoin Gold | 9035 | 9135 | 8035 | 38335 |
| Ethereum | 9036 | 9136 | 8036 | 38336 p2p, 8136 http |
| Ethereum Classic | 9037 | 9137 | 8037 | |
| Dogecoin | 9038 | 9138 | 8038 | 38338 |
| Namecoin | 9039 | 9139 | 8039 | 38339 |
| Vertcoin | 9040 | 9140 | 8040 | 38340 |
| Monacoin | 9041 | 9141 | 8041 | 38341 |
| DigiByte | 9042 | 9142 | 8042 | 38342 |
| Myriad | 9043 | 9143 | 8043 | 38343 |
| GameCredits | 9044 | 9144 | 8044 | 38344 |
| Groestlcoin | 9045 | 9145 | 8045 | 38345 |
| Bitcoin Cash SV | 9046 | 9146 | 8046 | 38346 |
| Liquid | 9047 | 9147 | 8047 | 38347 |
| Fujicoin | 9048 | 9148 | 8048 | 38348 |
| PIVX | 9049 | 9149 | 8049 | 38349 |
| Firo | 9050 | 9150 | 8050 | 38350 |
| Koto | 9051 | 9151 | 8051 | 38351 |
| Bellcoin | 9052 | 9152 | 8052 | 38352 |
| NULS | 9053 | 9153 | 8053 | 38353 |
| Bitcore | 9054 | 9154 | 8054 | 38354 |
| Viacoin | 9055 | 9155 | 8055 | 38355 |
| VIPSTARCOIN | 9056 | 9156 | 8056 | 38356 |
| MonetaryUnit | 9057 | 9157 | 8057 | 38357 |
| Flux | 9058 | 9158 | 8058 | 38358 |
| Ravencoin | 9059 | 9159 | 8059 | 38359 |
| Ritocoin | 9060 | 9160 | 8060 | 38360 |
| Decred | 9061 | 9161 | 8061 | 38361 |
| SnowGem | 9062 | 9162 | 8062 | 38362 |
| BNB Smart Chain | 9064 | 9164 | 8064 | 38364 p2p, 8164 http |
| BNB Smart Chain Archive | 9065 | 9165 | 8065 | 38365 p2p, 8165 http |
| Flo | 9066 | 9166 | 8066 | 38366 |
| Polis | 9067 | 9167 | 8067 | 38367 |
| Qtum | 9088 | 9188 | 8088 | 38388 |
| Divi Project | 9089 | 9189 | 8089 | 38389 |
| CPUchain | 9090 | 9190 | 8090 | 38390 |
| DeepOnion | 9091 | 9191 | 8091 | 38391 |
| Unobtanium | 9092 | 9192 | 65535 | 38392 |
| Omotenashicoin | 9094 | 9194 | 8094 | 38394 |
| BitZeny | 9095 | 9195 | 8095 | 38395 |
| Trezarcoin | 9096 | 9196 | 8096 | 38396 |
| eCash | 9097 | 9197 | 8097 | 38397 |
| Avalanche | 9098 | 9198 | 8098 | 38398 p2p |
| Avalanche Archive | 9099 | 9199 | 8099 | 38399 p2p |
| Bitcoin Signet | 19020 | 19120 | 18020 | 48320 |
| Bitcoin Regtest | 19021 | 19121 | 18021 | 48321 |
| Ethereum Goerli | 19026 | 19126 | 18026 | 48326 p2p |
| Ethereum Sepolia | 19176 | 19176 | 18076 | 48376 p2p |
| Bitcoin Testnet | 19030 | 19130 | 18030 | 48330 |
| Bitcoin Cash Testnet | 19031 | 19131 | 18031 | 48331 |
| Zcash Testnet | 19032 | 19132 | 18032 | 48332 |
| Dash Testnet | 19033 | 19133 | 18033 | 48333 |
| Litecoin Testnet | 19034 | 19134 | 18034 | 48334 |
| Bitcoin Gold Testnet | 19035 | 19135 | 18035 | 48335 |
| Ethereum Ropsten | 19036 | 19136 | 18036 | 48336 p2p |
| Dogecoin Testnet | 19038 | 19138 | 18038 | 48338 |
| Vertcoin Testnet | 19040 | 19140 | 18040 | 48340 |
| Monacoin Testnet | 19041 | 19141 | 18041 | 48341 |
| DigiByte Testnet | 19042 | 19142 | 18042 | 48342 |
| Groestlcoin Testnet | 19045 | 19145 | 18045 | 48345 |
| Groestlcoin Regtest | 19046 | 19146 | 18046 | 48346 |
| Groestlcoin Signet | 19047 | 19147 | 18047 | 48347 |
| PIVX Testnet | 19049 | 19149 | 18049 | 48349 |
| Koto Testnet | 19051 | 19151 | 18051 | 48351 |
| Decred Testnet | 19061 | 19161 | 18061 | 48361 |
| Flo Testnet | 19066 | 19166 | 18066 | 48366 |
| Qtum Testnet | 19088 | 19188 | 18088 | 48388 |
| Omotenashicoin Testnet | 19089 | 19189 | 18089 | 48389 |
> NOTE: This document is generated from coin definitions in `configs/coins`.

View File

@ -343,6 +343,11 @@ func (s *PublicServer) newTemplateData(r *http.Request) *TemplateData {
InternalExplorer: s.internalExplorer && !s.is.InitialSync,
TOSLink: api.Text.TOSLink,
}
if t.ChainType == bchain.ChainEthereumType {
t.FungibleTokenName = bchain.EthereumTokenTypeMap[bchain.FungibleToken]
t.NonFungibleTokenName = bchain.EthereumTokenTypeMap[bchain.NonFungibleToken]
t.MultiTokenName = bchain.EthereumTokenTypeMap[bchain.MultiToken]
}
if !s.debug {
t.Minified = ".min.2"
}
@ -486,6 +491,9 @@ type TemplateData struct {
CoinLabel string
InternalExplorer bool
ChainType bchain.ChainType
FungibleTokenName bchain.TokenTypeName
NonFungibleTokenName bchain.TokenTypeName
MultiTokenName bchain.TokenTypeName
Address *api.Address
AddrStr string
Tx *api.Tx

View File

@ -109,13 +109,13 @@
</table>
{{end}}
{{if eq .ChainType 1}}
{{if tokenCount $addr.Tokens "ERC20"}}
{{if tokenCount $addr.Tokens .FungibleTokenName}}
<div class="accordion mt-2 mb-2" id="erc20">
<div class="accordion-item">
<div class="accordion-header" id="erc20Heading">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#erc20Body" aria-expanded="false" aria-controls="erc20Body">
<div class="row g-0 w-100">
<h5 class="col-md-4 mb-md-0">ERC20 Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens "ERC20"}}</span></h5>
<h5 class="col-md-4 mb-md-0">{{.FungibleTokenName}} Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens .FungibleTokenName}}</span></h5>
<h5 class="col-md-8 mb-md-0"><span tt="Total value of tokens">{{summaryValuesSpan $addr.TokensBaseValue $addr.TokensSecondaryValue $data}}</span></h5>
</div>
</button>
@ -131,7 +131,7 @@
<th class="text-end" style="width: 10%;"><span class="d-none d-md-block">Transfers</span><span class="d-block d-md-none">#</span></th>
</tr>
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC20"}}
{{if eq $t.Type $.FungibleTokenName}}
<tr>
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}<span class="copyable" cc="{{$t.Contract}}" alias-type="Contract">{{$t.Name}}</span>{{else}}<span class="copyable">{{$t.Contract}}</span>{{end}}</a></td>
<td>{{formattedAmountSpan $t.BalanceSat $t.Decimals $t.Symbol $data "copyable"}}</td>
@ -147,13 +147,13 @@
</div>
</div>
{{end}}
{{if tokenCount $addr.Tokens "ERC721"}}
{{if tokenCount $addr.Tokens .NonFungibleTokenName}}
<div class="accordion mt-2 mb-2" id="erc721">
<div class="accordion-item">
<div class="accordion-header" id="erc721Heading">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#erc721Body" aria-expanded="false" aria-controls="erc721Body">
<div class="row g-0 w-100">
<h5 class="col-12 mb-md-0">ERC721 Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens "ERC721"}}</span></h5>
<h5 class="col-12 mb-md-0">{{.NonFungibleTokenName}} Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens .NonFungibleTokenName}}</span></h5>
</div>
</button>
</div>
@ -167,7 +167,7 @@
<th class="text-end" style="width: 10%;"><span class="d-none d-md-block">Transfers</span><span class="d-block d-md-none">#</span></th>
</tr>
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC721"}}
{{if eq $t.Type $.NonFungibleTokenName}}
<tr>
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}<span class="copyable" cc="{{$t.Contract}}" alias-type="Contract">{{$t.Name}}</span>{{else}}<span class="copyable">{{$t.Contract}}</span>{{end}}</a></td>
<td>
@ -184,13 +184,13 @@
</div>
</div>
{{end}}
{{if tokenCount $addr.Tokens "ERC1155"}}
{{if tokenCount $addr.Tokens .MultiTokenName}}
<div class="accordion mt-2 mb-2" id="erc1155">
<div class="accordion-item">
<div class="accordion-header" id="erc1155Heading">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#erc1155Body" aria-expanded="false" aria-controls="erc1155Body">
<div class="row g-0 w-100">
<h5 class="col-12 mb-md-0">ERC1155 Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens "ERC1155"}}</span></h5>
<h5 class="col-12 mb-md-0">{{.MultiTokenName}} Tokens <span class="badge bg-secondary">{{tokenCount $addr.Tokens .MultiTokenName}}</span></h5>
</div>
</button>
</div>
@ -204,7 +204,7 @@
<th class="text-end" style="width: 10%;"><span class="d-none d-md-block">Transfers</span><span class="d-block d-md-none">#</span></th>
</tr>
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC1155"}}
{{if eq $t.Type $.MultiTokenName}}
<tr>
<td class="ellipsis"><a href="/address/{{$t.Contract}}">{{if $t.Name}}<span class="copyable" cc="{{$t.Contract}}" alias-type="Contract">{{$t.Name}}</span>{{else}}<span class="copyable">{{$t.Contract}}</span>{{end}}</a></td>
<td>
@ -234,18 +234,18 @@
<option {{if eq $addr.Filter "0"}}selected{{end}} value="0">Non-contract</option>
<option {{if eq $addr.Filter "1"}}selected{{end}} value="1">Internal</option>
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC20"}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} (ERC20)</option>
{{if eq $t.Type $.FungibleTokenName}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} ({{$.FungibleTokenName}})</option>
{{end}}
{{end}}
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC721"}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} (ERC721)</option>
{{if eq $t.Type $.NonFungibleTokenName}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} ({{$.NonFungibleTokenName}})</option>
{{end}}
{{end}}
{{range $t := $addr.Tokens}}
{{if eq $t.Type "ERC1155"}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} (ERC1155)</option>
{{if eq $t.Type $.MultiTokenName}}
<option {{if eq $addr.Filter $t.ContractIndex}}selected{{end}} value="{{$t.ContractIndex}}">{{if $t.Name}}{{$t.Name}}{{else}}{{$t.Contract}}{{end}} ({{$.MultiTokenName}})</option>
{{end}}
{{end}}
{{end}}

View File

@ -95,12 +95,12 @@
{{end}}
{{end}}
{{if tokenTransfersCount $tx "ERC20"}}
{{if tokenTransfersCount $tx .FungibleTokenName}}
<div class="row subhead">
ERC20 Token Transfers
{{.FungibleTokenName}} Token Transfers
</div>
{{range $tt := $tx.TokenTransfers}}
{{if eq $tt.Type "ERC20"}}
{{if eq $tt.Type $.FungibleTokenName}}
<div class="row body">
<div class="col-md-4">
<div class="row tx-addr">
@ -123,12 +123,12 @@
{{end}}
{{end}}
{{if tokenTransfersCount $tx "ERC721"}}
{{if tokenTransfersCount $tx .NonFungibleTokenName}}
<div class="row subhead">
ERC721 Token Transfers
{{.NonFungibleTokenName}} Token Transfers
</div>
{{range $tt := $tx.TokenTransfers}}
{{if eq $tt.Type "ERC721"}}
{{if eq $tt.Type $.NonFungibleTokenName}}
<div class="row body">
<div class="col-md-4">
<div class="row tx-addr">
@ -151,12 +151,12 @@
{{end}}
{{end}}
{{if tokenTransfersCount $tx "ERC1155"}}
{{if tokenTransfersCount $tx .MultiTokenName}}
<div class="row subhead">
ERC1155 Token Transfers
{{.MultiTokenName}} Token Transfers
</div>
{{range $tt := $tx.TokenTransfers}}
{{if eq $tt.Type "ERC1155"}}
{{if eq $tt.Type $.MultiTokenName}}
<div class="row body">
<div class="col-md-4">
<div class="row tx-addr">

56
tests/rpc/testdata/bsc.json vendored Normal file
View File

@ -0,0 +1,56 @@
{
"blockHeight": 12823819,
"blockHash": "0x13a36aea55df099a02f777980840fc82dd0a6748fd1245a5185ec4401fdc196c",
"blockTime": 1637466737,
"blockSize": 945,
"blockTxs": [
"0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12",
"0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc"
],
"txDetails": {
"0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12": {
"txid": "0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12",
"blockTime": 1637466737,
"time": 1637466737,
"vin": [
{
"addresses": [
"0xd6f2815c885f3c628b99873cb0feb3b96df63163"
]
}
],
"vout": [
{
"value": 4,
"scriptPubKey": {
"addresses": [
"0xfd53b1b4af84d59b20bf2c20ca89a6beeaa2c628"
]
}
}
]
},
"0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc": {
"txid": "0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc",
"blockTime": 1637466737,
"time": 1637466737,
"vin": [
{
"addresses": [
"0x295e26495cef6f69dfa69911d9d8e4f3bbadb89b"
]
}
],
"vout": [
{
"value": 0.00206658,
"scriptPubKey": {
"addresses": [
"0x0000000000000000000000000000000000001000"
]
}
}
]
}
}
}

56
tests/rpc/testdata/bsc_archive.json vendored Normal file
View File

@ -0,0 +1,56 @@
{
"blockHeight": 12823819,
"blockHash": "0x13a36aea55df099a02f777980840fc82dd0a6748fd1245a5185ec4401fdc196c",
"blockTime": 1637466737,
"blockSize": 945,
"blockTxs": [
"0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12",
"0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc"
],
"txDetails": {
"0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12": {
"txid": "0x970fec39c96e92669d68ac2366ffe9dab7314eefc075f1db760a9792a8bffa12",
"blockTime": 1637466737,
"time": 1637466737,
"vin": [
{
"addresses": [
"0xd6f2815c885f3c628b99873cb0feb3b96df63163"
]
}
],
"vout": [
{
"value": 4,
"scriptPubKey": {
"addresses": [
"0xfd53b1b4af84d59b20bf2c20ca89a6beeaa2c628"
]
}
}
]
},
"0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc": {
"txid": "0x05618ba2e7e98c6cb3a9d05e6e62c0983b430103c69f1045608e812730bd61fc",
"blockTime": 1637466737,
"time": 1637466737,
"vin": [
{
"addresses": [
"0x295e26495cef6f69dfa69911d9d8e4f3bbadb89b"
]
}
],
"vout": [
{
"value": 0.00206658,
"scriptPubKey": {
"addresses": [
"0x0000000000000000000000000000000000001000"
]
}
}
]
}
}
}

View File

@ -44,7 +44,13 @@
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
"EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
},
},
"bsc": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBlockHeader"]
},
"bsc_archive": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBlockHeader"]
},
"cpuchain": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
"EstimateSmartFee", "EstimateFee"],