From 5a2a7dff46bcf087f7c2db0b003706a06e4ae24f Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Wed, 6 May 2026 13:15:11 +0200 Subject: [PATCH 01/12] add qbtc chain config and remove unrelated chains - add qbtc mainnet and testnet configs pointing to odindex.io endpoints - add qbtc logo asset - remove other chains (axelar, cosmos, neutron, nolus, osmosis, xion, bfhevm, crossfi) since this fork is dedicated to qbtc Co-Authored-By: Claude Opus 4.7 (1M context) --- chains/mainnet/axelar.json | 70 ----------------- chains/mainnet/cosmos.json | 28 ------- chains/mainnet/neutron.json | 43 ----------- chains/mainnet/nolus.json | 29 ------- chains/mainnet/osmosis.json | 47 ----------- chains/mainnet/qbtc.json | 24 ++++++ chains/mainnet/xion.json | 150 ------------------------------------ chains/testnet/bfhevm.json | 21 ----- chains/testnet/crossfi.json | 11 --- chains/testnet/qbtc.json | 24 ++++++ public/logos/qbtc.svg | 4 + 11 files changed, 52 insertions(+), 399 deletions(-) delete mode 100644 chains/mainnet/axelar.json delete mode 100644 chains/mainnet/cosmos.json delete mode 100644 chains/mainnet/neutron.json delete mode 100644 chains/mainnet/nolus.json delete mode 100644 chains/mainnet/osmosis.json create mode 100644 chains/mainnet/qbtc.json delete mode 100644 chains/mainnet/xion.json delete mode 100644 chains/testnet/bfhevm.json delete mode 100644 chains/testnet/crossfi.json create mode 100644 chains/testnet/qbtc.json create mode 100644 public/logos/qbtc.svg diff --git a/chains/mainnet/axelar.json b/chains/mainnet/axelar.json deleted file mode 100644 index 255f99187d..0000000000 --- a/chains/mainnet/axelar.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "chain_name": "axelar", - "api": ["https://rest.axelar.lava.build/lava-referer-97409c72-1a82-4861-8651-119c15151cbe"], - "rpc": ["https://tm.axelar.lava.build/lava-referer-97409c72-1a82-4861-8651-119c15151cbe"], - "snapshot_provider": "", - "sdk_version": "0.45.6", - "coin_type": "118", - "min_tx_fee": "800", - "addr_prefix": "axelar", - "logo": "/logos/axelar.svg", - "theme_color": "#161723", - "assets": [ - { - "base": "uaxl", - "symbol": "AXL", - "exponent": "6", - "coingecko_id": "axelar", - "logo": "/logos/axelar.svg" - }, - { - "base": "uusdc", - "symbol": "axlUSDC", - "exponent": "6", - "coingecko_id": "usd-coin", - "logo": "/logos/usdc.svg" - }, - { - "base": "uusdt", - "symbol": "axlUSDT", - "exponent": "6", - "coingecko_id": "tether", - "logo": "/logos/usdt.svg" - }, - { - "base": "dai-wei", - "symbol": "axlDAI", - "exponent": "18", - "coingecko_id": "dai", - "logo": "/logos/dai.svg" - }, - { - "base": "weth-wei", - "symbol": "axlWETH", - "exponent": "18", - "coingecko_id": "ethereum", - "logo": "/logos/weth.svg" - }, - { - "base": "wmatic-wei", - "symbol": "axlWMATIC", - "exponent": "18", - "coingecko_id": "matic-network", - "logo": "/logos/wmatic.svg" - }, - { - "base": "wavax-wei", - "symbol": "axlWAVAX", - "exponent": "18", - "coingecko_id": "avalanche-2", - "logo": "/logos/wavax.svg" - }, - { - "base": "dot-planck", - "symbol": "axlDOT", - "exponent": "10", - "coingecko_id": "polkadot", - "logo": "/logos/dot.svg" - } - ] -} diff --git a/chains/mainnet/cosmos.json b/chains/mainnet/cosmos.json deleted file mode 100644 index 91e03b71a2..0000000000 --- a/chains/mainnet/cosmos.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "chain_name": "cosmos", - "registry_name": "cosmoshub", - "api": [ - { "provider": "cosmos.directory", "address": "https://rest.cosmos.directory/cosmoshub" }, - { "provider": "publicnode", "address": "https://cosmos-rest.publicnode.com" }, - { "provider": "silknode", "address": "https://cosmos.api.silknodes.io" } - ], - "rpc": [ - { "provider": "icycro", "address": "https://cosmos-rpc.icycro.org" }, - { "provider": "dragonstake", "address": "https://rpc.cosmos.dragonstake.io" }, - { "provider": "Golden Ratio Staking", "address": "https://rpc-cosmoshub.goldenratiostaking.net" } - ], - "sdk_version": "0.45.1", - "coin_type": "118", - "min_tx_fee": "800", - "addr_prefix": "cosmos", - "logo": "/logos/cosmos.svg", - "assets": [ - { - "base": "uatom", - "symbol": "ATOM", - "exponent": "6", - "coingecko_id": "cosmos", - "logo": "/logos/cosmos.svg" - } - ] -} diff --git a/chains/mainnet/neutron.json b/chains/mainnet/neutron.json deleted file mode 100644 index 6d9594a908..0000000000 --- a/chains/mainnet/neutron.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "chain_name": "neutron", - "api": [ - { "provider": "Polkachu", "address": "https://neutron-api.polkachu.com" }, - { "provider": "NodeStake", "address": "https://api.neutron.nodestake.top" }, - { "provider": "Allnodes", "address": "https://neutron-rest.publicnode.com" } - ], - "rpc": [ - { "provider": "Polkachu", "address": "https://neutron-rpc.polkachu.com" }, - { "provider": "NodeStake", "address": "https://rpc.neutron.nodestake.top" }, - { "provider": "Allnodes", "address": "https://neutron-rpc.publicnode.com:443" } - ], - "provider_chain": { - "api": ["https://rest.cosmos.directory/cosmoshub"] - }, - "features": [ - "dashboard", - "blocks", - "ibc", - "cosmwasm", - "uptime", - "parameters", - "state-sync", - "consensus", - "supply", - "widget" - ], - "sdk_version": "0.45.1", - "coin_type": "118", - "min_tx_fee": "8000", - "assets": [ - { - "base": "untrn", - "symbol": "NTRN", - "exponent": "6", - "coingecko_id": "neutron", - "logo": "/logos/neutron.svg" - } - ], - "addr_prefix": "neutron", - "theme_color": "#161723", - "logo": "/logos/neutron.svg" -} diff --git a/chains/mainnet/nolus.json b/chains/mainnet/nolus.json deleted file mode 100644 index 2c832db946..0000000000 --- a/chains/mainnet/nolus.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "chain_name": "nolus", - "coingecko": "nolus", - "api": [ - { "provider": "Nolus", "address": "https://pirin-cl.nolus.network:1317" }, - { "provider": "LavenderFive", "address": "https://nolus-api.lavenderfive.com:443" }, - { "provider": "Allnodes", "address": "https://nolus-rest.publicnode.com" } - ], - "rpc": [ - { "provider": "Nolus", "address": "https://pirin-cl.nolus.network:26657" }, - { "provider": "LavenderFive", "address": "https://nolus-rpc.lavenderfive.com:443" }, - { "provider": "Allnodes", "address": "https://nolus-rpc.publicnode.com:443" } - ], - "snapshot_provider": "", - "sdk_version": "v0.47.6", - "coin_type": "118", - "min_tx_fee": "0", - "addr_prefix": "nolus", - "logo": "/logos/nolus.svg", - "assets": [ - { - "base": "unls", - "symbol": "NLS", - "exponent": "6", - "coingecko_id": "nolus", - "logo": "/logos/nolus.svg" - } - ] -} diff --git a/chains/mainnet/osmosis.json b/chains/mainnet/osmosis.json deleted file mode 100644 index 449480d65d..0000000000 --- a/chains/mainnet/osmosis.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "chain_name": "osmosis", - "coingecko": "osmosis", - "api": [ - "https://lcd.osmosis.zone", - "https://api-osmosis-ia.cosmosia.notional.ventures", - "https://osmosis-api.polkachu.com", - "https://lcd-osmosis.blockapsis.com" - ], - "rpc": [ - "https://rpc.osmosis.zone", - "https://rpc-osmosis-ia.cosmosia.notional.ventures:443", - "https://osmosis-rpc.polkachu.com:443", - "https://osmosis.validator.network:443", - "https://rpc-osmosis.blockapsis.com:443" - ], - "snapshot_provider": "", - "sdk_version": "0.46.1", - "coin_type": "118", - "min_tx_fee": "800", - "addr_prefix": "osmo", - "logo": "/logos/osmosis.jpg", - "theme_color": "#812cd6", - "assets": [ - { - "base": "uosmo", - "symbol": "OSMO", - "exponent": "6", - "coingecko_id": "osmosis", - "logo": "/logos/osmosis.jpg" - }, - { - "base": "uion", - "symbol": "ION", - "exponent": "6", - "coingecko_id": "ion", - "logo": "/logos/osmosis.jpg" - }, - { - "base": "usomm", - "symbol": "SOMM", - "exponent": "6", - "coingecko_id": "somm", - "logo": "" - } - ] -} diff --git a/chains/mainnet/qbtc.json b/chains/mainnet/qbtc.json new file mode 100644 index 0000000000..8ef0026297 --- /dev/null +++ b/chains/mainnet/qbtc.json @@ -0,0 +1,24 @@ +{ + "chain_name": "qbtc", + "registry_name": "qbtc", + "logo": "https://ping-dashboard-five.vercel.app/logos/qbtc.svg", + "api": [ + "https://qbtcapi.odindex.io" + ], + "rpc": [ + "https://qbtcrpc.odindex.io" + ], + "sdk_version": "0.53.4", + "coin_type": "118", + "min_tx_fee": "800", + "addr_prefix": "qbtc", + "assets": [ + { + "base": "qbtc", + "symbol": "QBTC", + "exponent": "8", + "coingecko_id": "", + "logo": "https://ping-dashboard-five.vercel.app/logos/qbtc.svg" + } + ] +} \ No newline at end of file diff --git a/chains/mainnet/xion.json b/chains/mainnet/xion.json deleted file mode 100644 index 49dafec078..0000000000 --- a/chains/mainnet/xion.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "chain_name": "xion", - "chain_id": "xion-mainnet-1", - "registry_name": "xion", - "coingecko": "xion", - "network_type": "mainnet", - "rpc": [ - { - "address": "https://rpc.xion-mainnet-1.burnt.com", - "provider": "🔥BurntLabs🔥" - }, - { - "address": "https://rpc-burnt.imperator.co/", - "provider": "Imperator.co" - }, - { - "address": "https://xion-rpc.polkachu.com", - "provider": "Polkachu" - } - ], - "api": [ - { - "address": "https://api.xion-mainnet-1.burnt.com", - "provider": "🔥BurntLabs🔥" - }, - { - "address": "https://lcd-burnt.imperator.co/", - "provider": "Imperator.co" - }, - { - "address": "https://xion-api.polkachu.com", - "provider": "Polkachu" - } - ], - "snapshot_provider": "", - "sdk_version": "0.53.3", - "coin_type": "118", - "min_tx_fee": "100", - "addr_prefix": "xion", - "theme_color": "#96b325", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/xion/images/burnt-round.png", - "assets": [ - { - "base": "uxion", - "symbol": "XION", - "exponent": "6", - "coingecko_id": "xion-2", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/xion/images/burnt-round.png" - }, - { - "base": "ibc/0471F1C4E7AFD3F07702BEF6DC365268D64570F7C1FDC98EA6098DD6DE59817B", - "symbol": "OSMO", - "exponent": "6", - "coingecko_id": "osmosis", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/osmo.png" - }, - { - "base": "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349", - "symbol": "USDC", - "exponent": "6", - "coingecko_id": "usd-coin", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/noble/images/USDCoin.png" - }, - { - "base": "ibc/CC7B293B3F08EA7DB96AFD4765BD0C7F95ABD7ECEAF21C74F3ACCBF7CEFB6591", - "symbol": "OSMO", - "exponent": "6", - "coingecko_id": "osmosis", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/osmosis/images/osmo.png" - }, - { - "base": "ibc/9463E39D230614B313B487836D13A392BD1731928713D4C8427A083627048DB3", - "symbol": "AXL", - "exponent": "6", - "coingecko_id": "axelar", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axl.png" - }, - { - "base": "ibc/6490A7EAB61059BFC1CDDEB05917DD70BDF3A611654162A1A47DB930D40D8AF4", - "symbol": "axlUSDC", - "exponent": "6", - "coingecko_id": "usd-coin", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axlusdc.png" - }, - { - "base": "ibc/0000000000000000000000000000000000000000000000000000000000000000", - "symbol": "axlUSDT", - "exponent": "6", - "coingecko_id": "tether", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axlusdc.png" - }, - { - "base": "ibc/0000000000000000000000000000000000000000000000000000000000000000", - "symbol": "axlDAI", - "exponent": "18", - "coingecko_id": "dai", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axldai.png" - }, - { - "base": "ibc/0000000000000000000000000000000000000000000000000000000000000000", - "symbol": "axlFRAX", - "exponent": "6", - "coingecko_id": "frax", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/axlfrax.png" - }, - { - "base": "ibc/AAD7136DD626569C3DDE7C5F764968BB2E939875EFC568AE5712B62081850814", - "symbol": "axlWETH", - "exponent": "18", - "coingecko_id": "axlweth", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/axelar/images/weth.png" - }, - { - "base": "ibc/056EA54C3D9B49B3C0418955A27980A91DD4F210914BFE240A1DB19E27895ECA", - "symbol": "KYVE", - "exponent": "6", - "coingecko_id": "kyve-network", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/kyve/images/kyve-token.png" - }, - { - "base": "ibc/DBE9697AC1044255A305A2034AD360B4152632BFBFB5785234731F60196B9645", - "symbol": "ELYS", - "exponent": "6", - "coingecko_id": "elys", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/elys/images/elys.png" - }, - { - "base": "ibc/E706A0C6CACB374ADC2BCF6A74FE1B260840FC822E45DCB776DEA962A57FED30", - "symbol": "axlARB", - "exponent": "18", - "coingecko_id": "arb", - "logo": "https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/arbitrum/images/arb.png" - } - ], - "features": [ - "dashboard", - "governance", - "staking", - "blocks", - "tx", - "uptime", - "ibc", - "supply", - "parameters", - "consensus", - "cosmwasm", - "account" - ], - "keplr_features": ["ibc-go", "ibc-transfer", "no-legacy-stdTx"] -} diff --git a/chains/testnet/bfhevm.json b/chains/testnet/bfhevm.json deleted file mode 100644 index c136f030db..0000000000 --- a/chains/testnet/bfhevm.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "chain_name": "bfhevm_777-1", - "api": ["https://rest-testnet-bfhevm.xyz:443"], - "rpc": ["https://rpc-bfhevm.xyz:8443"], - "coingecko": "", - "snapshot_provider": "", - "sdk_version": "0.45.7", - "coin_type": "60", - "min_tx_fee": "700", - "addr_prefix": "bfh", - "logo": "", - "assets": [ - { - "base": "abfh", - "symbol": "BFH", - "exponent": "18", - "coingecko_id": "", - "logo": "" - } - ] -} diff --git a/chains/testnet/crossfi.json b/chains/testnet/crossfi.json deleted file mode 100644 index d602617509..0000000000 --- a/chains/testnet/crossfi.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "chain_name": "crossfi-testnet-1", - "api": ["https://crossfi-testnet-api.forpeaky.xyz"], - "rpc": ["https://crossfi-testnet-rpc.forpeaky.xyz"], - "coingecko": "", - "snapshot_provider": "", - "sdk_version": "0.47.1", - "coin_type": "118", - "min_tx_fee": "500", - "addr_prefix": "crossfi" -} diff --git a/chains/testnet/qbtc.json b/chains/testnet/qbtc.json new file mode 100644 index 0000000000..8ef0026297 --- /dev/null +++ b/chains/testnet/qbtc.json @@ -0,0 +1,24 @@ +{ + "chain_name": "qbtc", + "registry_name": "qbtc", + "logo": "https://ping-dashboard-five.vercel.app/logos/qbtc.svg", + "api": [ + "https://qbtcapi.odindex.io" + ], + "rpc": [ + "https://qbtcrpc.odindex.io" + ], + "sdk_version": "0.53.4", + "coin_type": "118", + "min_tx_fee": "800", + "addr_prefix": "qbtc", + "assets": [ + { + "base": "qbtc", + "symbol": "QBTC", + "exponent": "8", + "coingecko_id": "", + "logo": "https://ping-dashboard-five.vercel.app/logos/qbtc.svg" + } + ] +} \ No newline at end of file diff --git a/public/logos/qbtc.svg b/public/logos/qbtc.svg new file mode 100644 index 0000000000..03d4ab56f3 --- /dev/null +++ b/public/logos/qbtc.svg @@ -0,0 +1,4 @@ + + + + From 68d91f7b64698c2962bd5d45d6ff98b9e978c484 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Wed, 6 May 2026 13:23:51 +0200 Subject: [PATCH 02/12] add vercel SPA rewrite config Rewrite all non-asset paths to / so the Vue Router can handle deep links like /qbtc directly without Vercel returning 404. Co-Authored-By: Claude Opus 4.7 (1M context) --- vercel.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000000..2124409429 --- /dev/null +++ b/vercel.json @@ -0,0 +1,9 @@ +{ + "routes": [ + { + "src": "/[^.]+", + "dest": "/", + "status": 200 + } + ] +} From f3636541642184c8102f18358d3b2b478d1219a1 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Wed, 6 May 2026 13:28:54 +0200 Subject: [PATCH 03/12] redirect root to /qbtc on Vercel Visiting / now 308-redirects to /qbtc so users land on the qbtc explorer directly instead of the chain list page. Co-Authored-By: Claude Opus 4.7 (1M context) --- vercel.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/vercel.json b/vercel.json index 2124409429..2c0c1e725a 100644 --- a/vercel.json +++ b/vercel.json @@ -1,9 +1,6 @@ { "routes": [ - { - "src": "/[^.]+", - "dest": "/", - "status": 200 - } + { "src": "^/$", "status": 308, "headers": { "Location": "/qbtc" } }, + { "src": "/[^.]+", "dest": "/", "status": 200 } ] } From abfb910ab77af2e1a811faec4a3958a392d6ffa4 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Sun, 10 May 2026 12:10:34 +0200 Subject: [PATCH 04/12] fix: auto-suggest chain to Keplr on connect When Keplr lacks a chain in its modular registry, calling enable/getKey throws "There is no modular chain info for {chainId}" and the connect modal surfaces the error inline without ever opening a popup. Wire the ping-connect-wallet keplr-config event to call experimentalSuggestChain directly so Keplr prompts the user to add the chain, instead of routing to a separate manual /wallet/keplr page. Falls back to the manual page if Keplr is missing or the suggestion rejects. Extracts the ChainInfo builder from modules/wallet/keplr.vue into a shared libs/keplr.ts helper to avoid duplicating the payload shape. --- src/libs/keplr.ts | 69 +++++++++++++++++++++++++++++++++++ src/modules/wallet/keplr.vue | 70 ++++-------------------------------- src/stores/useWalletStore.ts | 18 ++++++++-- 3 files changed, 90 insertions(+), 67 deletions(-) create mode 100644 src/libs/keplr.ts diff --git a/src/libs/keplr.ts b/src/libs/keplr.ts new file mode 100644 index 0000000000..d2085800d6 --- /dev/null +++ b/src/libs/keplr.ts @@ -0,0 +1,69 @@ +import type { ChainConfig, DenomUnit } from '@/types/chaindata'; +import { CosmosRestClient } from '@/libs/client'; + +export async function buildKeplrChainInfo(chain: ChainConfig) { + if (!chain.endpoints?.rest?.at(0)) throw new Error('Endpoint does not set'); + const client = CosmosRestClient.newDefault(chain.endpoints.rest.at(0)!.address); + const b = await client.getBaseBlockLatest(); + const chainId = b.block.header.chain_id; + + const gasPriceStep = chain.keplrPriceStep || { + low: 0.01, + average: 0.025, + high: 0.03, + }; + const coinDecimals = + chain.assets[0].denom_units.find((x: DenomUnit) => x.denom === chain.assets[0].symbol.toLowerCase())?.exponent || + 6; + + return { + chainId, + chainName: chain.chainName, + rpc: chain.endpoints?.rpc?.at(0)?.address, + rest: chain.endpoints?.rest?.at(0)?.address, + bip44: { coinType: Number(chain.coinType) }, + coinType: Number(chain.coinType), + bech32Config: { + bech32PrefixAccAddr: chain.bech32Prefix, + bech32PrefixAccPub: `${chain.bech32Prefix}pub`, + bech32PrefixValAddr: `${chain.bech32Prefix}valoper`, + bech32PrefixValPub: `${chain.bech32Prefix}valoperpub`, + bech32PrefixConsAddr: `${chain.bech32Prefix}valcons`, + bech32PrefixConsPub: `${chain.bech32Prefix}valconspub`, + }, + currencies: [ + { + coinDenom: chain.assets[0].symbol, + coinMinimalDenom: chain.assets[0].base, + coinDecimals, + coinGeckoId: chain.assets[0].coingecko_id || 'unknown', + }, + ], + feeCurrencies: [ + { + coinDenom: chain.assets[0].symbol, + coinMinimalDenom: chain.assets[0].base, + coinDecimals, + coinGeckoId: chain.assets[0].coingecko_id || 'unknown', + gasPriceStep, + }, + ], + gasPriceStep, + stakeCurrency: { + coinDenom: chain.assets[0].symbol, + coinMinimalDenom: chain.assets[0].base, + coinDecimals, + coinGeckoId: chain.assets[0].coingecko_id || 'unknown', + }, + features: chain.keplrFeatures || [], + }; +} + +export async function suggestKeplrChain(chain: ChainConfig) { + // @ts-ignore + const keplr = window.keplr; + if (!keplr) throw new Error('Keplr extension not detected'); + const info = await buildKeplrChainInfo(chain); + await keplr.experimentalSuggestChain(info); + return info.chainId; +} diff --git a/src/modules/wallet/keplr.vue b/src/modules/wallet/keplr.vue index 319dfd25ce..5fe13007a1 100644 --- a/src/modules/wallet/keplr.vue +++ b/src/modules/wallet/keplr.vue @@ -1,9 +1,8 @@