Skip to content

Commit

Permalink
backend: implement block explorer selection
Browse files Browse the repository at this point in the history
Add the block explorer prefix url to the configuration that will be used
to open the transaction. The available options to select are statically
defined and the frontend can learn them by calling the
available-explorers endpoint.
  • Loading branch information
NicolaLS committed Feb 26, 2024
1 parent c0c1d30 commit 07e315a
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 16 deletions.
38 changes: 29 additions & 9 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,21 @@ var fixedURLWhitelist = []string{
"https://shiftcrypto.support/",
// Exchange rates.
"https://www.coingecko.com/",
// Block explorers.
// Block explorers (btc).
"https://blockstream.info/tx/",
"https://blockstream.info/testnet/tx/",
"https://mempool.space/tx/",
"https://mempool.space/testnet/tx/",
// Block explorers (ltc).
"https://sochain.com/tx/LTCTEST/",
"https://blockchair.com/litecoin/transaction/",
// Block explorers (eth).
"https://etherscan.io/tx/",
"https://goerli.etherscan.io/tx/",
"https://sepolia.etherscan.io/tx/",
"https://ethplorer.io/tx/",
"https://goerli.ethplorer.io/tx/",
"https://sepolia.ethplorer.io/tx/",
// Moonpay onramp
"https://www.moonpay.com/",
"https://support.moonpay.com/",
Expand Down Expand Up @@ -485,43 +493,51 @@ func (backend *Backend) Coin(code coinpkg.Code) (coinpkg.Coin, error) {
servers := backend.defaultElectrumXServers(code)
coin = btc.NewCoin(coinpkg.CodeRBTC, "Bitcoin Regtest", "RBTC", coinpkg.BtcUnitDefault, &chaincfg.RegressionNetParams, dbFolder, servers, "", backend.socksProxy)
case code == coinpkg.CodeTBTC:
blockExplorerPrefix := backend.config.AppConfig().Backend.TBTC.BlockExplorerTxPrefix
servers := backend.defaultElectrumXServers(code)
coin = btc.NewCoin(coinpkg.CodeTBTC, "Bitcoin Testnet", "TBTC", btcFormatUnit, &chaincfg.TestNet3Params, dbFolder, servers,
"https://blockstream.info/testnet/tx/", backend.socksProxy)
blockExplorerPrefix, backend.socksProxy)
case code == coinpkg.CodeBTC:
blockExplorerPrefix := backend.config.AppConfig().Backend.BTC.BlockExplorerTxPrefix
servers := backend.defaultElectrumXServers(code)
coin = btc.NewCoin(coinpkg.CodeBTC, "Bitcoin", "BTC", btcFormatUnit, &chaincfg.MainNetParams, dbFolder, servers,
"https://blockstream.info/tx/", backend.socksProxy)
blockExplorerPrefix, backend.socksProxy)
case code == coinpkg.CodeTLTC:
blockExplorerPrefix := backend.config.AppConfig().Backend.TLTC.BlockExplorerTxPrefix
servers := backend.defaultElectrumXServers(code)
coin = btc.NewCoin(coinpkg.CodeTLTC, "Litecoin Testnet", "TLTC", coinpkg.BtcUnitDefault, &ltc.TestNet4Params, dbFolder, servers,
"https://sochain.com/tx/LTCTEST/", backend.socksProxy)
blockExplorerPrefix, backend.socksProxy)
case code == coinpkg.CodeLTC:
blockExplorerPrefix := backend.config.AppConfig().Backend.LTC.BlockExplorerTxPrefix
servers := backend.defaultElectrumXServers(code)
coin = btc.NewCoin(coinpkg.CodeLTC, "Litecoin", "LTC", coinpkg.BtcUnitDefault, &ltc.MainNetParams, dbFolder, servers,
"https://blockchair.com/litecoin/transaction/", backend.socksProxy)
blockExplorerPrefix, backend.socksProxy)
case code == coinpkg.CodeETH:
blockExplorerPrefix := backend.config.AppConfig().Backend.ETH.BlockExplorerTxPrefix
etherScan := etherscan.NewEtherScan("https://api.etherscan.io/api", backend.etherScanHTTPClient)
coin = eth.NewCoin(etherScan, code, "Ethereum", "ETH", "ETH", params.MainnetChainConfig,
"https://etherscan.io/tx/",
blockExplorerPrefix,
etherScan,
nil)
case code == coinpkg.CodeGOETH:
blockExplorerPrefix := backend.config.AppConfig().Backend.GOETH.BlockExplorerTxPrefix
etherScan := etherscan.NewEtherScan("https://api-goerli.etherscan.io/api", backend.etherScanHTTPClient)
coin = eth.NewCoin(etherScan, code, "Ethereum Goerli", "GOETH", "GOETH", params.GoerliChainConfig,
"https://goerli.etherscan.io/tx/",
blockExplorerPrefix,
etherScan,
nil)
case code == coinpkg.CodeSEPETH:
blockExplorerPrefix := backend.config.AppConfig().Backend.SEPETH.BlockExplorerTxPrefix
etherScan := etherscan.NewEtherScan("https://api-sepolia.etherscan.io/api", backend.etherScanHTTPClient)
coin = eth.NewCoin(etherScan, code, "Ethereum Sepolia", "SEPETH", "SEPETH", params.SepoliaChainConfig,
"https://sepolia.etherscan.io/tx/",
blockExplorerPrefix,
etherScan,
nil)
case erc20Token != nil:
blockExplorerPrefix := backend.config.AppConfig().Backend.ETH.BlockExplorerTxPrefix
etherScan := etherscan.NewEtherScan("https://api.etherscan.io/api", backend.etherScanHTTPClient)
coin = eth.NewCoin(etherScan, erc20Token.code, erc20Token.name, erc20Token.unit, "ETH", params.MainnetChainConfig,
"https://etherscan.io/tx/",
blockExplorerPrefix,
etherScan,
erc20Token.token,
)
Expand Down Expand Up @@ -1028,3 +1044,7 @@ func (backend *Backend) SetWatchonly(rootFingerprint []byte, watchonly bool) err
&t,
)
}

func (backend *Backend) AvailableExplorers() config.AvailableBlockExplorers {
return config.AvailableExplorers
}
88 changes: 88 additions & 0 deletions backend/config/blockexplorer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package config

// BlockExplorer defines a selectable block explorer.
type BlockExplorer struct {
Name string `json:"name"`
Url string `json:"url"`
}

// AvailableBlockExplorers defines all available block explorers for each coin.
type AvailableBlockExplorers struct {
Btc []BlockExplorer `json:"btc"`
Tbtc []BlockExplorer `json:"tbtc"`
Ltc []BlockExplorer `json:"ltc"`
Tltc []BlockExplorer `json:"tltc"`
Eth []BlockExplorer `json:"eth"`
GoEth []BlockExplorer `json:"goeth"`
SepEth []BlockExplorer `json:"sepeth"`
}

// AvailableExplorers FIXME: Localize AvailableExplorers.
var AvailableExplorers = AvailableBlockExplorers{
Btc: []BlockExplorer{
{
Name: "blockstream.info",
Url: "https://blockstream.info/tx/",
},
{
Name: "mempool.space",
Url: "https://mempool.space/tx",
},
},
Tbtc: []BlockExplorer{
{
Name: "mempool.space",
Url: "https://mempool.space/testnet/tx/",
},
{
Name: "blockstream.info",
Url: "https://blockstream.info/testnet/tx/",
},
},
Ltc: []BlockExplorer{
{
Name: "sochain.com",
Url: "https://sochain.com/tx/",
},
{
Name: "blockchair.com",
Url: "https://blockchair.com/litecoin/transaction",
},
},
Tltc: []BlockExplorer{
{
Name: "sochain.com",
Url: "https://sochain.com/tx/LTCTEST/",
},
},
Eth: []BlockExplorer{
{
Name: "etherscan.io",
Url: "https://etherscan.io/tx/",
},
{
Name: "ethplorer.io",
Url: "https://ethplorer.io/tx/",
},
},
GoEth: []BlockExplorer{
{
Name: "etherscan.io",
Url: "https://goerli.etherscan.io/tx/",
},
{
Name: "ethplorer.io",
Url: "https://goerli.ethplorer.io/tx/",
},
},
SepEth: []BlockExplorer{
{
Name: "etherscan.io",
Url: "https://sepolia.etherscan.io/tx/",
},
{
Name: "ethplorer.io",
Url: "https://sepolia.ethplorer.io/tx/",
},
},
}
31 changes: 24 additions & 7 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func (s *ServerInfo) String() string {

// btcCoinConfig holds configurations specific to a btc-based coin.
type btcCoinConfig struct {
ElectrumServers []*ServerInfo `json:"electrumServers"`
ElectrumServers []*ServerInfo `json:"electrumServers"`
BlockExplorerTxPrefix string `json:"blockExplorerTxPrefix"`
}

// ETHTransactionsSource where to get Ethereum transactions from. See the list of consts
Expand All @@ -59,6 +60,7 @@ const (
// ethCoinConfig holds configurations for ethereum coins.
type ethCoinConfig struct {
DeprecatedActiveERC20Tokens []string `json:"activeERC20Tokens"`
BlockExplorerTxPrefix string `json:"blockExplorerTxPrefix"`
}

type proxyConfig struct {
Expand All @@ -76,12 +78,14 @@ type Backend struct {

Authentication bool `json:"authentication"`

BTC btcCoinConfig `json:"btc"`
TBTC btcCoinConfig `json:"tbtc"`
RBTC btcCoinConfig `json:"rbtc"`
LTC btcCoinConfig `json:"ltc"`
TLTC btcCoinConfig `json:"tltc"`
ETH ethCoinConfig `json:"eth"`
BTC btcCoinConfig `json:"btc"`
TBTC btcCoinConfig `json:"tbtc"`
RBTC btcCoinConfig `json:"rbtc"`
LTC btcCoinConfig `json:"ltc"`
TLTC btcCoinConfig `json:"tltc"`
ETH ethCoinConfig `json:"eth"`
GOETH ethCoinConfig `json:"goeth"`
SEPETH ethCoinConfig `json:"sepeth"`

// Removed in v4.35 - don't reuse these two keys.
TETH struct{} `json:"teth"`
Expand Down Expand Up @@ -168,6 +172,7 @@ func NewDefaultAppConfig() AppConfig {
PEMCert: shiftRootCA,
},
},
BlockExplorerTxPrefix: AvailableExplorers.Btc[0].Url,
},
TBTC: btcCoinConfig{
ElectrumServers: []*ServerInfo{
Expand All @@ -182,6 +187,7 @@ func NewDefaultAppConfig() AppConfig {
PEMCert: shiftRootCA,
},
},
BlockExplorerTxPrefix: AvailableExplorers.Tbtc[0].Url,
},
RBTC: btcCoinConfig{
ElectrumServers: []*ServerInfo{
Expand Down Expand Up @@ -210,6 +216,7 @@ func NewDefaultAppConfig() AppConfig {
PEMCert: shiftRootCA,
},
},
BlockExplorerTxPrefix: AvailableExplorers.Ltc[0].Url,
},
TLTC: btcCoinConfig{
ElectrumServers: []*ServerInfo{
Expand All @@ -224,9 +231,19 @@ func NewDefaultAppConfig() AppConfig {
PEMCert: shiftRootCA,
},
},
BlockExplorerTxPrefix: AvailableExplorers.Tltc[0].Url,
},
ETH: ethCoinConfig{
DeprecatedActiveERC20Tokens: []string{},
BlockExplorerTxPrefix: AvailableExplorers.Eth[0].Url,
},
GOETH: ethCoinConfig{
DeprecatedActiveERC20Tokens: []string{},
BlockExplorerTxPrefix: AvailableExplorers.GoEth[0].Url,
},
SEPETH: ethCoinConfig{
DeprecatedActiveERC20Tokens: []string{},
BlockExplorerTxPrefix: AvailableExplorers.SepEth[0].Url,
},
// Copied from frontend/web/src/components/rates/rates.tsx.
FiatList: []string{rates.USD.String(), rates.EUR.String(), rates.CHF.String()},
Expand Down
9 changes: 9 additions & 0 deletions backend/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ type Backend interface {
AOPPCancel()
AOPPApprove()
AOPPChooseAccount(code accountsTypes.Code)
AvailableExplorers() config.AvailableBlockExplorers
GetAccountFromCode(code accountsTypes.Code) (accounts.Interface, error)
HTTPClient() *http.Client
LookupInsuredAccounts(accountCode accountsTypes.Code) ([]bitsurance.AccountDetails, error)
Expand Down Expand Up @@ -250,6 +251,7 @@ func NewHandlers(
getAPIRouterNoError(apiRouter)("/set-watchonly", handlers.postSetWatchonly).Methods("POST")
getAPIRouterNoError(apiRouter)("/on-auth-setting-changed", handlers.postOnAuthSettingChanged).Methods("POST")
getAPIRouterNoError(apiRouter)("/accounts/eth-account-code", handlers.lookupEthAccountCode).Methods("POST")
getAPIRouterNoError(apiRouter)("/available-explorers", handlers.getAvailableExplorers).Methods("GET")

devicesRouter := getAPIRouterNoError(apiRouter.PathPrefix("/devices").Subrouter())
devicesRouter("/registered", handlers.getDevicesRegistered).Methods("GET")
Expand Down Expand Up @@ -1400,3 +1402,10 @@ func (handlers *Handlers) postOnAuthSettingChanged(r *http.Request) interface{}
handlers.backend.Config().AppConfig().Backend.Authentication)
return nil
}

// getAvailableExplorers returns a struct containing arrays with block explorers for each
// individual coin code.
func (handlers *Handlers) getAvailableExplorers(*http.Request) interface{} {
// TODO: maybe filter out testing coins if not testing and real if testing
return config.AvailableExplorers
}

0 comments on commit 07e315a

Please sign in to comment.