Merge remote-tracking branch 'origin/v3-single' into v3-single

# Conflicts:
#	yarn.lock
This commit is contained in:
liangping
2023-05-05 07:39:39 +08:00
16 changed files with 15646 additions and 389 deletions
+103 -91
View File
@@ -1,121 +1,133 @@
import { defineStore } from "pinia";
import { useDashboard, type ChainConfig, type Endpoint, EndpointType } from "./useDashboard";
import type { VerticalNavItems } from '@/@layouts/types'
import { useRouter } from "vue-router";
import { CosmosRestClient } from "@/libs/client";
import { useBankStore, useBaseStore, useGovStore, useMintStore, useStakingStore } from ".";
import { useBlockModule } from "@/modules/[chain]/block/block";
import { DEFAULT } from "@/libs";
import { defineStore } from 'pinia';
import {
useDashboard,
type ChainConfig,
type Endpoint,
EndpointType,
} from './useDashboard';
import type { VerticalNavItems } from '@/@layouts/types';
import { useRouter } from 'vue-router';
import { CosmosRestClient } from '@/libs/client';
import {
useBankStore,
useBaseStore,
useGovStore,
useMintStore,
useStakingStore,
} from '.';
import { useBlockModule } from '@/modules/[chain]/block/block';
import { DEFAULT } from '@/libs';
export const useBlockchain = defineStore("blockchain", {
export const useBlockchain = defineStore('blockchain', {
state: () => {
return {
status: {} as Record<string, string>,
rest: '',
chainName: "",
chainName: '',
endpoint: {} as {
type?: EndpointType,
address: string
provider: string
type?: EndpointType;
address: string;
provider: string;
},
connErr: ""
}
connErr: '',
};
},
getters: {
current() : ChainConfig | undefined {
return this.dashboard.chains[this.chainName]
current(): ChainConfig | undefined {
return this.dashboard.chains[this.chainName];
},
logo(): string {
return this.current?.logo || ''
return this.current?.logo || '';
},
dashboard() {
return useDashboard()
return useDashboard();
},
computedChainMenu() {
let currNavItem: VerticalNavItems = [];
let currNavItem: VerticalNavItems = []
const router = useRouter()
const routes = router?.getRoutes()||[]
if(this.current && routes) {
currNavItem = [{
title: this.current?.prettyName || this.chainName || '',
icon: {image: this.current.logo, size: '22'},
i18n: false,
children: routes
.filter(x=> x.meta.i18n)
.map(x => ({
title: `module.${x.meta.i18n}`,
to: {path: x.path.replace(':chain',this.chainName)},
icon: { icon: 'mdi-chevron-right', size: '22'},
i18n: true
}))
.sort((a,b)=>a.to.path.length - b.to.path.length)
}]
const router = useRouter();
const routes = router?.getRoutes() || [];
if (this.current && routes) {
currNavItem = [
{
title: this.current?.prettyName || this.chainName || '',
icon: { image: this.current.logo, size: '22' },
i18n: false,
children: routes
.filter((x) => x.meta.i18n)
.map((x) => ({
title: `module.${x.meta.i18n}`,
to: { path: x.path.replace(':chain', this.chainName) },
icon: { icon: 'mdi-chevron-right', size: '22' },
i18n: true,
}))
.sort((a, b) => a.to.path.length - b.to.path.length),
},
];
}
// compute favorite menu
const favNavItems: VerticalNavItems = []
this.dashboard.favorite.forEach(name => {
const ch = this.dashboard.chains[name]
if(ch) {
const favNavItems: VerticalNavItems = [];
Object.keys(this.dashboard.favoriteMap).forEach((name) => {
const ch = this.dashboard.chains[name];
if (ch && this.dashboard.favoriteMap?.[name]) {
favNavItems.push({
title: ch.prettyName || ch.chainName || name,
to: { path: `/${ch.chainName || name}`},
icon: {image: ch.logo, size: '22'}
} )
}
})
title: ch.prettyName || ch.chainName || name,
to: { path: `/${ch.chainName || name}` },
icon: { image: ch.logo, size: '22' },
});
}
});
// combine all together
return [...currNavItem,
{ heading: 'Ecosystem' },
{
title: 'Favorite',
children: favNavItems,
badgeContent: favNavItems.length,
badgeClass: 'bg-primary',
i18n: true,
icon: { icon: 'mdi-star', size: '22'}
},
{
title: 'All Blockchains',
to: { path : '/'},
badgeContent: this.dashboard.length,
badgeClass: 'bg-primary',
i18n: true,
icon: { icon: 'mdi-grid', size: '22'}
}
]
return [
...currNavItem,
{ heading: 'Ecosystem' },
{
title: 'Favorite',
children: favNavItems,
badgeContent: favNavItems.length,
badgeClass: 'bg-primary',
i18n: true,
icon: { icon: 'mdi-star', size: '22' },
},
{
title: 'All Blockchains',
to: { path: '/' },
badgeContent: this.dashboard.length,
badgeClass: 'bg-primary',
i18n: true,
icon: { icon: 'mdi-grid', size: '22' },
},
];
},
},
actions: {
async initial() {
await this.randomSetupEndpoint()
await useStakingStore().init()
useBankStore().initial()
useBaseStore().initial()
useGovStore().initial()
useMintStore().initial()
useBlockModule().initial()
await this.randomSetupEndpoint();
await useStakingStore().init();
useBankStore().initial();
useBaseStore().initial();
useGovStore().initial();
useMintStore().initial();
useBlockModule().initial();
},
async randomSetupEndpoint() {
const all = this.current?.endpoints?.rest
if(all) {
const rn = Math.random()
const endpoint = all[Math.floor(rn * all.length)]
await this.setRestEndpoint(endpoint)
}
},
async setRestEndpoint(endpoint: Endpoint) {
this.connErr = ''
this.endpoint = endpoint
this.rpc = new CosmosRestClient(endpoint.address, DEFAULT)
},
setCurrent(name: string) {
this.chainName = name
const all = this.current?.endpoints?.rest;
if (all) {
const rn = Math.random();
const endpoint = all[Math.floor(rn * all.length)];
await this.setRestEndpoint(endpoint);
}
},
}
})
async setRestEndpoint(endpoint: Endpoint) {
this.connErr = '';
this.endpoint = endpoint;
this.rpc = new CosmosRestClient(endpoint.address, DEFAULT);
},
setCurrent(name: string) {
this.chainName = name;
},
},
});
+202 -178
View File
@@ -1,8 +1,7 @@
import { defineStore } from "pinia";
import { get } from '../libs/http'
import type { Chain, Asset } from '@ping-pub/chain-registry-client/dist/types'
import { useBlockchain } from "./useBlockchain";
import { defineStore } from 'pinia';
import { get } from '../libs/http';
import type { Chain, Asset } from '@ping-pub/chain-registry-client/dist/types';
import { useBlockchain } from './useBlockchain';
export enum EndpointType {
rpc,
@@ -12,253 +11,278 @@ export enum EndpointType {
}
export interface Endpoint {
type?: EndpointType,
address: string,
provider: string
type?: EndpointType;
address: string;
provider: string;
}
// Chain config structure of cosmos.directory
export interface DirectoryChain {
assets: Asset[],
bech32_prefix: string,
assets: Asset[];
bech32_prefix: string;
best_apis: {
rest: Endpoint[]
rpc: Endpoint[]
},
chain_id: string,
chain_name: string,
pretty_name: string,
coingecko_id: string,
cosmwasm_enabled: boolean,
decimals: number,
denom: string,
display: string,
explorers: {
name?: string | undefined;
kind?: string | undefined;
url?: string | undefined;
tx_page?: string | undefined;
account_page?: string | undefined;
}[] | undefined,
height: number,
image: string,
name: string,
network_type: string,
symbol: string,
rest: Endpoint[];
rpc: Endpoint[];
};
chain_id: string;
chain_name: string;
pretty_name: string;
coingecko_id: string;
cosmwasm_enabled: boolean;
decimals: number;
denom: string;
display: string;
explorers:
| {
name?: string | undefined;
kind?: string | undefined;
url?: string | undefined;
tx_page?: string | undefined;
account_page?: string | undefined;
}[]
| undefined;
height: number;
image: string;
name: string;
network_type: string;
symbol: string;
versions?: {
application_version: string,
cosmos_sdk_version: string,
tendermint_version: string,
}
application_version: string;
cosmos_sdk_version: string;
tendermint_version: string;
};
}
export interface ChainConfig {
chainName: string,
prettyName: string,
bech32Prefix: string,
chainId: string,
assets: Asset[],
themeColor?: string,
chainName: string;
prettyName: string;
bech32Prefix: string;
chainId: string;
assets: Asset[];
themeColor?: string;
endpoints: {
rest?: Endpoint[]
rpc?: Endpoint[]
grpc?: Endpoint[]
},
logo: string,
rest?: Endpoint[];
rpc?: Endpoint[];
grpc?: Endpoint[];
};
logo: string;
versions: {
application?: string,
cosmosSdk?: string,
tendermint?: string,
},
exponent: string,
excludes?: string,
application?: string;
cosmosSdk?: string;
tendermint?: string;
};
exponent: string;
excludes?: string;
}
export interface LocalConfig {
addr_prefix: string,
alias: string,
api: string[] | Endpoint[],
assets: {base: string, coingecko_id: string, exponent: string, logo: string, symbol: string}[]
chain_name: string,
coin_type: string
logo: string,
min_tx_fee: string,
rpc: string[] | Endpoint[],
sdk_version: string,
addr_prefix: string;
alias: string;
api: string[] | Endpoint[];
assets: {
base: string;
coingecko_id: string;
exponent: string;
logo: string;
symbol: string;
}[];
chain_name: string;
coin_type: string;
logo: string;
min_tx_fee: string;
rpc: string[] | Endpoint[];
sdk_version: string;
}
function apiConverter(api: any[]){
if(!api) return []
const array = typeof api === 'string'? [api] : api
return array.map(x => {
if(typeof x === 'string') {
const parts = String(x).split('.')
function apiConverter(api: any[]) {
if (!api) return [];
const array = typeof api === 'string' ? [api] : api;
return array.map((x) => {
if (typeof x === 'string') {
const parts = String(x).split('.');
return {
address: x,
provider: parts.length >=2 ? parts[parts.length-2] : x
}
}else{
return x as Endpoint
provider: parts.length >= 2 ? parts[parts.length - 2] : x,
};
} else {
return x as Endpoint;
}
})
});
}
export function fromLocal(lc: LocalConfig ): ChainConfig {
const conf = {} as ChainConfig
conf.assets = lc.assets.map(x => ({
name: x.base,
base: x.base,
display: x.symbol,
symbol: x.symbol,
logo_URIs: { svg: x.logo },
export function fromLocal(lc: LocalConfig): ChainConfig {
const conf = {} as ChainConfig;
conf.assets = lc.assets.map((x) => ({
name: x.base,
base: x.base,
display: x.symbol,
symbol: x.symbol,
logo_URIs: { svg: x.logo },
coingecko_id: x.coingecko_id,
exponent: x.exponent,
denom_units: [{denom: x.base, exponent: 0}, {denom: x.symbol.toLowerCase(), exponent: Number(x.exponent)}]
}))
conf.bech32Prefix = lc.addr_prefix
conf.chainName = lc.chain_name
conf.prettyName = lc.chain_name
exponent: x.exponent,
denom_units: [
{ denom: x.base, exponent: 0 },
{ denom: x.symbol.toLowerCase(), exponent: Number(x.exponent) },
],
}));
conf.bech32Prefix = lc.addr_prefix;
conf.chainName = lc.chain_name;
conf.prettyName = lc.chain_name;
conf.endpoints = {
rest: apiConverter(lc.api),
rpc: apiConverter(lc.rpc),
}
conf.logo = lc.logo
return conf
};
conf.logo = lc.logo;
return conf;
}
export function fromDirectory(source: DirectoryChain): ChainConfig {
const conf = {} as ChainConfig
conf.assets = source.assets,
conf.bech32Prefix = source.bech32_prefix,
conf.chainId = source.chain_id,
conf.chainName = source.chain_name,
conf.prettyName = source.pretty_name,
conf.versions = {
application: source.versions?.application_version || '',
cosmosSdk: source.versions?.cosmos_sdk_version || '',
tendermint: source.versions?.tendermint_version || '',
},
conf.logo = pathConvert(source.image)
conf.endpoints = source.best_apis
return conf
const conf = {} as ChainConfig;
(conf.assets = source.assets),
(conf.bech32Prefix = source.bech32_prefix),
(conf.chainId = source.chain_id),
(conf.chainName = source.chain_name),
(conf.prettyName = source.pretty_name),
(conf.versions = {
application: source.versions?.application_version || '',
cosmosSdk: source.versions?.cosmos_sdk_version || '',
tendermint: source.versions?.tendermint_version || '',
}),
(conf.logo = pathConvert(source.image));
conf.endpoints = source.best_apis;
return conf;
}
function pathConvert(path: string | undefined) {
if(path) {
path = path.replace('https://raw.githubusercontent.com/cosmos/chain-registry/master', 'https://registry.ping.pub')
if (path) {
path = path.replace(
'https://raw.githubusercontent.com/cosmos/chain-registry/master',
'https://registry.ping.pub'
);
}
return path || ''
return path || '';
}
export function getLogo(conf: {
svg?: string,
png?: string,
jpeg?: string,
} | undefined) {
if(conf) {
return pathConvert(conf.svg || conf.png || conf.jpeg)
export function getLogo(
conf:
| {
svg?: string;
png?: string;
jpeg?: string;
}
| undefined
) {
if (conf) {
return pathConvert(conf.svg || conf.png || conf.jpeg);
}
return undefined
return undefined;
}
function createChainFromDirectory(source: DirectoryChain) : Chain {
const conf: Chain = {} as Chain;
conf.apis = source.best_apis
conf.bech32_prefix = source.bech32_prefix
conf.chain_id = source.chain_id
conf.chain_name = source.chain_name
conf.explorers = source.explorers
conf.pretty_name = source.pretty_name
if(source.versions) {
function createChainFromDirectory(source: DirectoryChain): Chain {
const conf: Chain = {} as Chain;
conf.apis = source.best_apis;
conf.bech32_prefix = source.bech32_prefix;
conf.chain_id = source.chain_id;
conf.chain_name = source.chain_name;
conf.explorers = source.explorers;
conf.pretty_name = source.pretty_name;
if (source.versions) {
conf.codebase = {
recommended_version: source.versions.application_version,
cosmos_sdk_version: source.versions.cosmos_sdk_version,
tendermint_version: source.versions.tendermint_version,
}
};
}
if(source.image) {
if (source.image) {
conf.logo_URIs = {
svg: source.image
}
svg: source.image,
};
}
return conf
return conf;
}
export enum LoadingStatus {
Empty,
Loading,
Loaded,
Empty,
Loading,
Loaded,
}
export enum NetworkType {
Mainnet,
Testnet,
}
export enum ConfigSource {
MainnetCosmosDirectory = "https://chains.cosmos.directory",
TestnetCosmosDirectory = "https://chains.testcosmos.directory",
MainnetCosmosDirectory = 'https://chains.cosmos.directory',
TestnetCosmosDirectory = 'https://chains.testcosmos.directory',
Local = 'local',
}
export const useDashboard = defineStore('dashboard', {
state: () => {
const fav = JSON.parse(localStorage.getItem('favorite') || '["cosmoshub", "osmosis"]')
return {
status: LoadingStatus.Empty,
source: ConfigSource.MainnetCosmosDirectory,
networkType: NetworkType.Mainnet,
favorite: fav as string[],
chains: {} as Record<string, ChainConfig>,
}
const fav = JSON.parse(
localStorage.getItem('favorite') || '["cosmoshub", "osmosis"]'
);
const favMap = JSON.parse(
localStorage.getItem('favoriteMap') ||
'{"cosmoshub":true, "osmosis":true}'
);
return {
status: LoadingStatus.Empty,
source: ConfigSource.MainnetCosmosDirectory,
networkType: NetworkType.Mainnet,
favorite: fav as string[],
favoriteMap: favMap as Record<string, boolean>,
chains: {} as Record<string, ChainConfig>,
};
},
getters: {
length() : number {
return Object.keys(this.chains).length
}
length(): number {
return Object.keys(this.chains).length;
},
},
actions: {
initial() {
this.loadingFromLocal()
this.loadingFromLocal();
// this.loadingFromRegistry()
},
async loadingFromRegistry() {
if(this.status === LoadingStatus.Empty) {
this.status = LoadingStatus.Loading
get(this.source).then((res)=> {
res.chains.forEach(( x: DirectoryChain ) => {
this.chains[x.chain_name] = fromDirectory(x)
});
this.status = LoadingStatus.Loaded
})
if (this.status === LoadingStatus.Empty) {
this.status = LoadingStatus.Loading;
get(this.source).then((res) => {
res.chains.forEach((x: DirectoryChain) => {
this.chains[x.chain_name] = fromDirectory(x);
});
this.status = LoadingStatus.Loaded;
});
}
},
async loadingFromLocal() {
const source: Record<string, LocalConfig> = this.networkType === NetworkType.Mainnet
? import.meta.glob('../../chains/mainnet/*.json', {eager: true})
: import.meta.glob('../../chains/testnet/*.json', {eager: true})
Object.values<LocalConfig>(source).forEach((x: LocalConfig) => {
this.chains[x.chain_name] = fromLocal(x)
})
this.setupDefault()
this.status = LoadingStatus.Loaded
const source: Record<string, LocalConfig> =
this.networkType === NetworkType.Mainnet
? import.meta.glob('../../chains/mainnet/*.json', { eager: true })
: import.meta.glob('../../chains/testnet/*.json', { eager: true });
Object.values<LocalConfig>(source).forEach((x: LocalConfig) => {
this.chains[x.chain_name] = fromLocal(x);
});
this.setupDefault();
this.status = LoadingStatus.Loaded;
},
setupDefault() {
if(this.length > 0) {
const blockchain = useBlockchain()
for(let i=0; i < this.favorite.length; i++) {
if(!blockchain.chainName && this.chains[this.favorite[i]]) {
blockchain.setCurrent(this.favorite[i])
if (this.length > 0) {
const blockchain = useBlockchain();
for (let i = 0; i < this.favorite.length; i++) {
if (!blockchain.chainName && this.chains[this.favorite[i]]) {
blockchain.setCurrent(this.favorite[i]);
}
}
if(!blockchain.chainName) {
const [first] = Object.keys(this.chains)
blockchain.setCurrent(first)
if (!blockchain.chainName) {
const [first] = Object.keys(this.chains);
blockchain.setCurrent(first);
}
}
},
setConfigSource(newSource: ConfigSource) {
this.source = newSource
this.initial()
}
}
})
this.source = newSource;
this.initial();
},
},
});