feat(explorer): dual-chain wallet metadata, native coin pricing, and UI refresh.
Add Chain 138 wallet network metadata and stats coin-price enrichment; sync frontend explorer SPA, command center, and address/token pages with backend config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,23 +1,52 @@
|
||||
{
|
||||
"name": "MetaMask Multi-Chain Networks (13 chains)",
|
||||
"version": {"major": 1, "minor": 2, "patch": 0},
|
||||
"version": {"major": 1, "minor": 2, "patch": 1},
|
||||
"defaultChainId": 138,
|
||||
"explorerUrl": "https://explorer.d-bis.org",
|
||||
"tokenListUrl": "https://explorer.d-bis.org/api/v1/report/token-list?chainId=138",
|
||||
"tokenListUrl": "https://explorer.d-bis.org/api/config/token-list",
|
||||
"generatedBy": "DBIS Explorer",
|
||||
"chains": [
|
||||
{"chainId":"0x8a","chainIdDecimal":138,"chainName":"DeFi Oracle Meta Mainnet","shortName":"dbis","rpcUrls":["https://rpc-http-pub.d-bis.org","https://rpc.d-bis.org","https://rpc2.d-bis.org","https://rpc.defi-oracle.io"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://explorer.d-bis.org","https://blockscout.defi-oracle.io"],"iconUrls":["https://explorer.d-bis.org/token-icons/chain-138.png","https://explorer.d-bis.org/api/v1/report/logo/chain-138","https://explorer.d-bis.org/favicon.ico"],"infoURL":"https://explorer.d-bis.org","explorerApiUrl":"https://explorer.d-bis.org/api/v2","testnet":false},
|
||||
{"chainId":"0x1","chainIdDecimal":1,"chainName":"Ethereum Mainnet","shortName":"eth","rpcUrls":["https://eth.llamarpc.com","https://rpc.ankr.com/eth","https://ethereum.publicnode.com","https://1rpc.io/eth"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://etherscan.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"],"infoURL":"https://ethereum.org","testnet":false},
|
||||
{"chainId":"0x9f2c4","chainIdDecimal":651940,"chainName":"ALL Mainnet","shortName":"all","rpcUrls":["https://mainnet-rpc.alltra.global"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://alltra.global"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"],"infoURL":"https://alltra.global","testnet":false},
|
||||
{"chainId":"0x19","chainIdDecimal":25,"chainName":"Cronos Mainnet","rpcUrls":["https://evm.cronos.org","https://cronos-rpc.publicnode.com"],"nativeCurrency":{"name":"CRO","symbol":"CRO","decimals":18},"blockExplorerUrls":["https://cronos.org/explorer"],"iconUrls":["https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong"]},
|
||||
{"chainId":"0x38","chainIdDecimal":56,"chainName":"BNB Smart Chain","rpcUrls":["https://bsc-dataseed.binance.org","https://bsc-dataseed1.defibit.io","https://bsc-dataseed1.ninicoin.io"],"nativeCurrency":{"name":"BNB","symbol":"BNB","decimals":18},"blockExplorerUrls":["https://bscscan.com"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0x64","chainIdDecimal":100,"chainName":"Gnosis Chain","rpcUrls":["https://rpc.gnosischain.com","https://gnosis-rpc.publicnode.com","https://1rpc.io/gnosis"],"nativeCurrency":{"name":"xDAI","symbol":"xDAI","decimals":18},"blockExplorerUrls":["https://gnosisscan.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0x89","chainIdDecimal":137,"chainName":"Polygon","rpcUrls":["https://polygon-rpc.com","https://polygon.llamarpc.com","https://polygon-bor-rpc.publicnode.com"],"nativeCurrency":{"name":"MATIC","symbol":"MATIC","decimals":18},"blockExplorerUrls":["https://polygonscan.com"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0xa","chainIdDecimal":10,"chainName":"Optimism","rpcUrls":["https://mainnet.optimism.io","https://optimism.llamarpc.com","https://optimism-rpc.publicnode.com"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://optimistic.etherscan.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0xa4b1","chainIdDecimal":42161,"chainName":"Arbitrum One","rpcUrls":["https://arb1.arbitrum.io/rpc","https://arbitrum.llamarpc.com","https://arbitrum-one-rpc.publicnode.com"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://arbiscan.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0x2105","chainIdDecimal":8453,"chainName":"Base","rpcUrls":["https://mainnet.base.org","https://base.llamarpc.com","https://base-rpc.publicnode.com"],"nativeCurrency":{"name":"Ether","symbol":"ETH","decimals":18},"blockExplorerUrls":["https://basescan.org"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0xa86a","chainIdDecimal":43114,"chainName":"Avalanche C-Chain","rpcUrls":["https://api.avax.network/ext/bc/C/rpc","https://avalanche-c-chain-rpc.publicnode.com","https://1rpc.io/avax/c"],"nativeCurrency":{"name":"AVAX","symbol":"AVAX","decimals":18},"blockExplorerUrls":["https://snowtrace.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0xa4ec","chainIdDecimal":42220,"chainName":"Celo","rpcUrls":["https://forno.celo.org","https://celo-mainnet-rpc.publicnode.com","https://1rpc.io/celo"],"nativeCurrency":{"name":"CELO","symbol":"CELO","decimals":18},"blockExplorerUrls":["https://celoscan.io"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]},
|
||||
{"chainId":"0x457","chainIdDecimal":1111,"chainName":"Wemix","rpcUrls":["https://api.wemix.com","https://wemix-mainnet-rpc.publicnode.com"],"nativeCurrency":{"name":"WEMIX","symbol":"WEMIX","decimals":18},"blockExplorerUrls":["https://scan.wemix.com"],"iconUrls":["https://raw.githubusercontent.com/ethereum/ethereum.org/main/static/images/eth-diamond-black.png"]}
|
||||
{
|
||||
"chainId": "0x8a",
|
||||
"chainIdDecimal": 138,
|
||||
"chainName": "DeFi Oracle Meta Mainnet",
|
||||
"shortName": "dbis",
|
||||
"rpcUrls": ["https://rpc-http-pub.d-bis.org"],
|
||||
"nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18},
|
||||
"blockExplorerUrls": ["https://explorer.d-bis.org"],
|
||||
"infoURL": "https://d-bis.org",
|
||||
"explorerApiUrl": "https://explorer.d-bis.org/api/v2",
|
||||
"testnet": false,
|
||||
"iconUrls": [
|
||||
"https://explorer.d-bis.org/api/v1/report/logo/chain-138",
|
||||
"https://explorer.d-bis.org/token-icons/chain-138.png",
|
||||
"https://explorer.d-bis.org/favicon.ico"
|
||||
],
|
||||
"oracles": [
|
||||
{"name": "ETH/USD (proxy)", "address": "0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6", "decimals": 8},
|
||||
{"name": "ETH/USD (aggregator)", "address": "0x99b3511a2d315a497c8112c1fdd8d508d4b1e506", "decimals": 8}
|
||||
]
|
||||
},
|
||||
{
|
||||
"chainId": "0x1",
|
||||
"chainIdDecimal": 1,
|
||||
"chainName": "Ethereum Mainnet",
|
||||
"rpcUrls": ["https://eth.llamarpc.com", "https://rpc.ankr.com/eth", "https://ethereum.publicnode.com", "https://1rpc.io/eth"],
|
||||
"nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18},
|
||||
"blockExplorerUrls": ["https://etherscan.io"],
|
||||
"iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png"],
|
||||
"oracles": [{"name": "ETH/USD", "address": "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", "decimals": 8}]
|
||||
},
|
||||
{"chainId": "0x9f2c4", "chainIdDecimal": 651940, "chainName": "ALL Mainnet", "rpcUrls": ["https://mainnet-rpc.alltra.global"], "nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18}, "blockExplorerUrls": ["https://alltra.global"], "iconUrls": ["https://alltra.global/favicon.ico"], "oracles": []},
|
||||
{"chainId": "0x19", "chainIdDecimal": 25, "chainName": "Cronos Mainnet", "rpcUrls": ["https://evm.cronos.org", "https://cronos-rpc.publicnode.com"], "nativeCurrency": {"name": "CRO", "symbol": "CRO", "decimals": 18}, "blockExplorerUrls": ["https://cronos.org/explorer"], "iconUrls": ["https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong"], "oracles": []},
|
||||
{"chainId": "0x38", "chainIdDecimal": 56, "chainName": "BNB Smart Chain", "rpcUrls": ["https://bsc-dataseed.binance.org", "https://bsc-dataseed1.defibit.io", "https://bsc-dataseed1.ninicoin.io"], "nativeCurrency": {"name": "BNB", "symbol": "BNB", "decimals": 18}, "blockExplorerUrls": ["https://bscscan.com"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/smartchain/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0x64", "chainIdDecimal": 100, "chainName": "Gnosis Chain", "rpcUrls": ["https://rpc.gnosischain.com", "https://gnosis-rpc.publicnode.com", "https://1rpc.io/gnosis"], "nativeCurrency": {"name": "xDAI", "symbol": "xDAI", "decimals": 18}, "blockExplorerUrls": ["https://gnosisscan.io"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/xdai/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0x89", "chainIdDecimal": 137, "chainName": "Polygon", "rpcUrls": ["https://polygon-rpc.com", "https://polygon.llamarpc.com", "https://polygon-bor-rpc.publicnode.com"], "nativeCurrency": {"name": "MATIC", "symbol": "MATIC", "decimals": 18}, "blockExplorerUrls": ["https://polygonscan.com"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/polygon/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0xa", "chainIdDecimal": 10, "chainName": "Optimism", "rpcUrls": ["https://mainnet.optimism.io", "https://optimism.llamarpc.com", "https://optimism-rpc.publicnode.com"], "nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18}, "blockExplorerUrls": ["https://optimistic.etherscan.io"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/optimism/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0xa4b1", "chainIdDecimal": 42161, "chainName": "Arbitrum One", "rpcUrls": ["https://arb1.arbitrum.io/rpc", "https://arbitrum.llamarpc.com", "https://arbitrum-one-rpc.publicnode.com"], "nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18}, "blockExplorerUrls": ["https://arbiscan.io"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/arbitrum/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0x2105", "chainIdDecimal": 8453, "chainName": "Base", "rpcUrls": ["https://mainnet.base.org", "https://base.llamarpc.com", "https://base-rpc.publicnode.com"], "nativeCurrency": {"name": "Ether", "symbol": "ETH", "decimals": 18}, "blockExplorerUrls": ["https://basescan.org"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/base/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0xa86a", "chainIdDecimal": 43114, "chainName": "Avalanche C-Chain", "rpcUrls": ["https://api.avax.network/ext/bc/C/rpc", "https://avalanche-c-chain-rpc.publicnode.com", "https://1rpc.io/avax/c"], "nativeCurrency": {"name": "AVAX", "symbol": "AVAX", "decimals": 18}, "blockExplorerUrls": ["https://snowtrace.io"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/avalanchec/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0xa4ec", "chainIdDecimal": 42220, "chainName": "Celo", "rpcUrls": ["https://forno.celo.org", "https://celo-mainnet-rpc.publicnode.com", "https://1rpc.io/celo"], "nativeCurrency": {"name": "CELO", "symbol": "CELO", "decimals": 18}, "blockExplorerUrls": ["https://celoscan.io"], "iconUrls": ["https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/celo/info/logo.png"], "oracles": []},
|
||||
{"chainId": "0x457", "chainIdDecimal": 1111, "chainName": "Wemix", "rpcUrls": ["https://api.wemix.com", "https://wemix-mainnet-rpc.publicnode.com"], "nativeCurrency": {"name": "WEMIX", "symbol": "WEMIX", "decimals": 18}, "blockExplorerUrls": ["https://scan.wemix.com"], "iconUrls": ["https://scan.wemix.com/favicon.ico"], "oracles": []}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ type explorerStats struct {
|
||||
GasPrices *explorerGasPrices `json:"gas_prices,omitempty"`
|
||||
NetworkUtilizationPercentage *float64 `json:"network_utilization_percentage,omitempty"`
|
||||
TransactionsToday *int64 `json:"transactions_today,omitempty"`
|
||||
CoinPrice *string `json:"coin_price,omitempty"`
|
||||
CoinImage *string `json:"coin_image,omitempty"`
|
||||
Freshness freshness.Snapshot `json:"freshness"`
|
||||
Completeness freshness.SummaryCompleteness `json:"completeness"`
|
||||
Sampling freshness.Sampling `json:"sampling"`
|
||||
@@ -268,6 +270,8 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
enrichNativeCoinMarket(ctx, &stats)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(stats)
|
||||
}
|
||||
|
||||
150
backend/api/rest/stats_coin_price.go
Normal file
150
backend/api/rest/stats_coin_price.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
chain138WETHAddress = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
||||
)
|
||||
|
||||
type blockscoutCoinStats struct {
|
||||
CoinPrice *string `json:"coin_price"`
|
||||
CoinImage *string `json:"coin_image"`
|
||||
}
|
||||
|
||||
type tokenAggregationTokenResponse struct {
|
||||
Token struct {
|
||||
Market struct {
|
||||
PriceUsd *float64 `json:"priceUsd"`
|
||||
} `json:"market"`
|
||||
} `json:"token"`
|
||||
}
|
||||
|
||||
func enrichNativeCoinMarket(ctx context.Context, stats *explorerStats) {
|
||||
if stats.CoinPrice != nil && strings.TrimSpace(*stats.CoinPrice) != "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Prefer on-chain token-aggregation WETH/ETH oracle over Blockscout CoinGecko on Chain 138.
|
||||
if price := fetchTokenAggregationEthUsd(ctx); price != "" {
|
||||
stats.CoinPrice = &price
|
||||
if image := fetchBlockscoutCoinImage(ctx); image != "" {
|
||||
stats.CoinImage = &image
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
bsURL := strings.TrimSpace(os.Getenv("BLOCKSCOUT_STATS_URL"))
|
||||
if bsURL == "" {
|
||||
bsURL = "http://127.0.0.1:4000/api/v2/stats"
|
||||
}
|
||||
if price, image := fetchBlockscoutCoinMarket(ctx, bsURL); price != "" {
|
||||
stats.CoinPrice = &price
|
||||
if image != "" {
|
||||
stats.CoinImage = &image
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchBlockscoutCoinImage(ctx context.Context) string {
|
||||
bsURL := strings.TrimSpace(os.Getenv("BLOCKSCOUT_STATS_URL"))
|
||||
if bsURL == "" {
|
||||
bsURL = "http://127.0.0.1:4000/api/v2/stats"
|
||||
}
|
||||
_, image := fetchBlockscoutCoinMarket(ctx, bsURL)
|
||||
return image
|
||||
}
|
||||
|
||||
func fetchBlockscoutCoinMarket(ctx context.Context, url string) (price string, image string) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 4 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
var payload blockscoutCoinStats
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
return "", ""
|
||||
}
|
||||
if payload.CoinPrice != nil {
|
||||
price = strings.TrimSpace(*payload.CoinPrice)
|
||||
}
|
||||
if payload.CoinImage != nil {
|
||||
image = strings.TrimSpace(*payload.CoinImage)
|
||||
}
|
||||
return price, image
|
||||
}
|
||||
|
||||
func tokenAggregationAPIV1Base() string {
|
||||
base := strings.TrimRight(strings.TrimSpace(firstNonEmptyEnv(
|
||||
"TOKEN_AGGREGATION_API_BASE",
|
||||
"TOKEN_AGGREGATION_URL",
|
||||
"TOKEN_AGGREGATION_BASE_URL",
|
||||
)), "/")
|
||||
if base == "" {
|
||||
return "http://127.0.0.1:3001/api/v1"
|
||||
}
|
||||
if strings.HasSuffix(base, "/api/v1") {
|
||||
return base
|
||||
}
|
||||
return base + "/api/v1"
|
||||
}
|
||||
|
||||
func fetchTokenAggregationEthUsd(ctx context.Context) string {
|
||||
url := fmt.Sprintf("%s/tokens/%s?chainId=138", tokenAggregationAPIV1Base(), chain138WETHAddress)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return ""
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var payload tokenAggregationTokenResponse
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
return ""
|
||||
}
|
||||
if payload.Token.Market.PriceUsd == nil || *payload.Token.Market.PriceUsd <= 0 {
|
||||
return ""
|
||||
}
|
||||
return formatUsdPrice(*payload.Token.Market.PriceUsd)
|
||||
}
|
||||
|
||||
func formatUsdPrice(value float64) string {
|
||||
return fmt.Sprintf("%.2f", value)
|
||||
}
|
||||
133
backend/api/rest/stats_coin_price_test.go
Normal file
133
backend/api/rest/stats_coin_price_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEnrichNativeCoinMarketFromBlockscout(t *testing.T) {
|
||||
tokenAgg := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
defer tokenAgg.Close()
|
||||
t.Setenv("TOKEN_AGGREGATION_BASE_URL", tokenAgg.URL)
|
||||
|
||||
blockscout := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"coin_price": "1701.77",
|
||||
"coin_image": "https://example.com/eth.png",
|
||||
}))
|
||||
}))
|
||||
defer blockscout.Close()
|
||||
|
||||
t.Setenv("BLOCKSCOUT_STATS_URL", blockscout.URL)
|
||||
stats := explorerStats{}
|
||||
enrichNativeCoinMarket(context.Background(), &stats)
|
||||
|
||||
require.NotNil(t, stats.CoinPrice)
|
||||
require.Equal(t, "1701.77", *stats.CoinPrice)
|
||||
require.NotNil(t, stats.CoinImage)
|
||||
require.Equal(t, "https://example.com/eth.png", *stats.CoinImage)
|
||||
}
|
||||
|
||||
func TestEnrichNativeCoinMarketFallsBackToTokenAggregation(t *testing.T) {
|
||||
blockscout := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"coin_price": nil,
|
||||
}))
|
||||
}))
|
||||
defer blockscout.Close()
|
||||
|
||||
tokenAgg := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Contains(t, r.URL.Path, chain138WETHAddress)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"token": map[string]any{
|
||||
"market": map[string]any{
|
||||
"priceUsd": 1678.67,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}))
|
||||
defer tokenAgg.Close()
|
||||
|
||||
t.Setenv("BLOCKSCOUT_STATS_URL", blockscout.URL)
|
||||
t.Setenv("TOKEN_AGGREGATION_BASE_URL", tokenAgg.URL)
|
||||
stats := explorerStats{}
|
||||
enrichNativeCoinMarket(context.Background(), &stats)
|
||||
|
||||
require.NotNil(t, stats.CoinPrice)
|
||||
require.Equal(t, "1678.67", *stats.CoinPrice)
|
||||
}
|
||||
|
||||
func TestEnrichNativeCoinMarketPrefersTokenAggregationWithHostOnlyBaseURL(t *testing.T) {
|
||||
blockscout := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"coin_price": "1740.00",
|
||||
}))
|
||||
}))
|
||||
defer blockscout.Close()
|
||||
|
||||
tokenAgg := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/api/v1/tokens/"+chain138WETHAddress, r.URL.Path)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"token": map[string]any{
|
||||
"market": map[string]any{
|
||||
"priceUsd": 1732.18,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}))
|
||||
defer tokenAgg.Close()
|
||||
|
||||
t.Setenv("BLOCKSCOUT_STATS_URL", blockscout.URL)
|
||||
t.Setenv("TOKEN_AGGREGATION_BASE_URL", tokenAgg.URL)
|
||||
stats := explorerStats{}
|
||||
enrichNativeCoinMarket(context.Background(), &stats)
|
||||
|
||||
require.NotNil(t, stats.CoinPrice)
|
||||
require.Equal(t, "1732.18", *stats.CoinPrice)
|
||||
}
|
||||
|
||||
func TestEnrichNativeCoinMarketPrefersTokenAggregationOverBlockscout(t *testing.T) {
|
||||
blockscout := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"coin_price": "1740.00",
|
||||
"coin_image": "https://example.com/eth.png",
|
||||
}))
|
||||
}))
|
||||
defer blockscout.Close()
|
||||
|
||||
tokenAgg := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Contains(t, r.URL.Path, chain138WETHAddress)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{
|
||||
"token": map[string]any{
|
||||
"market": map[string]any{
|
||||
"priceUsd": 1732.18,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}))
|
||||
defer tokenAgg.Close()
|
||||
|
||||
t.Setenv("BLOCKSCOUT_STATS_URL", blockscout.URL)
|
||||
t.Setenv("TOKEN_AGGREGATION_BASE_URL", tokenAgg.URL)
|
||||
stats := explorerStats{}
|
||||
enrichNativeCoinMarket(context.Background(), &stats)
|
||||
|
||||
require.NotNil(t, stats.CoinPrice)
|
||||
require.Equal(t, "1732.18", *stats.CoinPrice)
|
||||
require.NotNil(t, stats.CoinImage)
|
||||
require.Equal(t, "https://example.com/eth.png", *stats.CoinImage)
|
||||
}
|
||||
Reference in New Issue
Block a user