diff --git a/public/logos/ledger.jpeg b/public/logos/ledger.jpeg new file mode 100644 index 00000000..46949821 Binary files /dev/null and b/public/logos/ledger.jpeg differ diff --git a/public/logos/ledger.webp b/public/logos/ledger.webp new file mode 100644 index 00000000..9c733a10 Binary files /dev/null and b/public/logos/ledger.webp differ diff --git a/src/layouts/components/ChainProfile.vue b/src/layouts/components/ChainProfile.vue index ac37ff08..28c3323f 100644 --- a/src/layouts/components/ChainProfile.vue +++ b/src/layouts/components/ChainProfile.vue @@ -85,6 +85,8 @@ function changeEndpoint(item: Endpoint) { Height: {{ baseStore.latest.block?.header.height }} + +
 
diff --git a/src/layouts/components/NavBarWallet.vue b/src/layouts/components/NavBarWallet.vue index 712555d8..baa01899 100644 --- a/src/layouts/components/NavBarWallet.vue +++ b/src/layouts/components/NavBarWallet.vue @@ -37,7 +37,7 @@ const tipMsg = computed(() => { -
+
Application Versions
+
-
+
Node Information
- + +
diff --git a/src/modules/wallet/accounts.vue b/src/modules/wallet/accounts.vue index 9b777372..867634e1 100644 --- a/src/modules/wallet/accounts.vue +++ b/src/modules/wallet/accounts.vue @@ -2,15 +2,17 @@ import { CosmosRestClient } from '@/libs/client'; import { useDashboard, useFormatter } from '@/stores'; import type { Coin, Delegation } from '@/types'; -import { fromBech32, toBase64, toBech32 } from '@cosmjs/encoding'; +import { fromBech32, toBase64, toBech32, toHex } from '@cosmjs/encoding'; import { Icon } from '@iconify/vue'; import { computed } from 'vue'; import { ref } from 'vue'; -import { scanLocalKeys, type AccountEntry, scanCompatibleAccounts } from './utils'; +import { scanLocalKeys, type AccountEntry, scanCompatibleAccounts, type LocalKey } from './utils'; const dashboard = useDashboard() const format = useFormatter() const editable = ref(false) // to edit addresses +const sourceAddress = ref('') // +const selectedSource = ref({} as LocalKey) // function toggleEdit() { editable.value = !editable.value } @@ -19,42 +21,21 @@ const conf = ref(JSON.parse(localStorage.getItem("imported-addresses") || "{}") const balances = ref({} as Record) const delegations = ref({} as Record) -scanLocalKeys().forEach(wallet => { - const { data } = fromBech32(wallet.cosmosAddress) - const walletKey = toBase64(data) - let imported = conf.value[walletKey] - // save the default address to local storage - if (!imported) { - imported = [] - dashboard.favorite.forEach(x => { - const chain = dashboard.chains[x] - if (chain && wallet.hdPath.indexOf(chain.coinType) === 6) { - imported.push({ - chainName: chain.chainName, - logo: chain.logo, - address: toBech32(chain.bech32Prefix, data), - coinType: chain.coinType, - endpoint: chain.endpoints.rest?.at(0)?.address - }) +// load balances +Object.values(conf.value).forEach(imported => { + let promise = Promise.resolve() + for(let i = 0;i < imported.length; i++) { + promise = promise.then(() => new Promise((resolve) => { + // continue only if the page is living + if(imported[i].endpoint) { + loadBalances(imported[i].endpoint || "", imported[i].address).finally(()=> resolve()) + } else { + resolve() } - }) - conf.value[walletKey] = imported; - localStorage.setItem("imported-addresses", JSON.stringify(conf.value)) + })) } - // load balance & delegations - imported.forEach(x => { - if (x.endpoint) { - const client = CosmosRestClient.newDefault(x.endpoint) - client.getBankBalances(x.address).then(res => { - balances.value[x.address] = res.balances.filter(x => x.denom.length < 10) - }) - client.getStakingDelegations(x.address).then(res => { - delegations.value[x.address] = res.delegation_responses - }) - } - }) -}) +}) const accounts = computed(() => { let a = [] as AccountEntry[] @@ -69,6 +50,8 @@ const accounts = computed(() => { denom = b.balance.denom }) entry.delegation = { amount: String(amount), denom } + }else{ + entry.delegation = undefined } entry.balances = balances.value[entry.address] }) @@ -81,43 +64,97 @@ const addresses = computed(() => { return accounts.value.map(x => (x.address)) }) +const sourceOptions = computed(() => { + // scan all connected wallet + const keys = scanLocalKeys() + // all existed keys + Object.values(conf.value).forEach(x => { + const [first] = x + if (first) { + const { data } = fromBech32(first.address) + const hex = toHex(data) + if (keys.findIndex(k => toHex(fromBech32(k.cosmosAddress).data) === hex) === -1) { + keys.push({ + cosmosAddress: first.address, + hdPath: `m/44/${first.coinType}/0'/0/0` + }) + } + } + }) + // address + if (sourceAddress.value) { + const { prefix, data } = fromBech32(sourceAddress.value) + const chain = Object.values(dashboard.chains).find(x => x.bech32Prefix === prefix) + if (chain) { + keys.push({ + cosmosAddress: sourceAddress.value, + hdPath: `m/44/${chain.coinType}/0'/0/0` + }) + } + } + if (!selectedSource.value.cosmosAddress && keys.length > 0) { + selectedSource.value = keys[0] + } + return keys +}) + const availableAccount = computed(() => { - return scanCompatibleAccounts().filter(x => !addresses.value.includes(x.address)) + if (selectedSource.value.cosmosAddress) { + return scanCompatibleAccounts([selectedSource.value]).filter(x => !addresses.value.includes(x.address)) + } + return [] }) function removeAddress(addr: string) { const newConf = {} as Record Object.keys(conf.value).forEach(key => { - newConf[key] = conf.value[key].filter(x => x.address !== addr) + const acc = conf.value[key].filter(x => x.address !== addr) + if (acc.length > 0) newConf[key] = acc }) conf.value = newConf localStorage.setItem("imported-addresses", JSON.stringify(conf.value)) } async function addAddress(acc: AccountEntry) { - console.log('add', acc) - const {data} = fromBech32(acc.address) + const { data } = fromBech32(acc.address) const key = toBase64(data) - if(conf.value[key]) { + if (conf.value[key]) { + // existed + if (conf.value[key].findIndex(x => x.address === acc.address) > -1) { + return + } conf.value[key].push(acc) } else { conf.value[key] = [acc] } - if(acc.endpoint) { - const client = CosmosRestClient.newDefault(acc.endpoint) - client.getBankBalances(acc.address).then(res => { - balances.value[acc.address] = res.balances.filter(x => x.denom.length < 10) - }) - client.getStakingDelegations(acc.address).then(res => { - delegations.value[acc.address] = res.delegation_responses - }) + // also add chain to favorite + if(!dashboard?.favoriteMap?.[acc.chainName]) { + dashboard.favoriteMap[acc.chainName] = true + window.localStorage.setItem( + 'favoriteMap', + JSON.stringify(dashboard.favoriteMap) + ); + } + + if (acc.endpoint) { + loadBalances(acc.endpoint, acc.address) } localStorage.setItem("imported-addresses", JSON.stringify(conf.value)) } +async function loadBalances(endpoint:string, address: string) { + const client = CosmosRestClient.newDefault(endpoint) + await client.getBankBalances(address).then(res => { + balances.value[address] = res.balances.filter(x => x.denom.length < 10) + }) + await client.getStakingDelegations(address).then(res => { + delegations.value[address] = res.delegation_responses + }) +} + diff --git a/src/modules/wallet/utils.ts b/src/modules/wallet/utils.ts index f096d9c3..88be608d 100644 --- a/src/modules/wallet/utils.ts +++ b/src/modules/wallet/utils.ts @@ -10,39 +10,42 @@ export interface AccountEntry { endpoint?: string, delegation?: Coin, balances?: Coin[], + compatiable?: boolean, +} + +export interface LocalKey { + cosmosAddress: string, hdPath: string } export function scanLocalKeys() { - const connected = [] as {cosmosAddress: string, hdPath: string}[] - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i) - if (key?.startsWith("m/44")) { - const wallet = JSON.parse(localStorage.getItem(key) || "") - if (wallet) { - connected.push(wallet) - } + const connected = [] as LocalKey[] + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i) + if (key?.startsWith("m/44")) { + const wallet = JSON.parse(localStorage.getItem(key) || "") + if (wallet) { + connected.push(wallet) } } - return connected } + return connected +} - -export function scanCompatibleAccounts() { - const dashboard = useDashboard() - const available = [] as AccountEntry[] - scanLocalKeys().forEach(wallet => { - Object.values(dashboard.chains).forEach(chain => { - if (wallet.hdPath.indexOf(chain.coinType) === 6) { - const { data } = fromBech32(wallet.cosmosAddress) - available.push({ - chainName: chain.chainName, - logo: chain.logo, - address: toBech32(chain.bech32Prefix, data), - coinType: chain.coinType, - endpoint: chain.endpoints.rest?.at(0)?.address - }) - } +export function scanCompatibleAccounts(keys: LocalKey[]) { + const dashboard = useDashboard() + const available = [] as AccountEntry[] + keys.forEach(wallet => { + Object.values(dashboard.chains).forEach(chain => { + const { data } = fromBech32(wallet.cosmosAddress) + available.push({ + chainName: chain.chainName, + logo: chain.logo, + address: toBech32(chain.bech32Prefix, data), + coinType: chain.coinType, + compatiable: wallet.hdPath.indexOf(chain.coinType) > 0, + endpoint: chain.endpoints.rest?.at(0)?.address }) }) - return available - } \ No newline at end of file + }) + return available +} \ No newline at end of file diff --git a/src/stores/useWalletStore.ts b/src/stores/useWalletStore.ts index eebea3a1..17814896 100644 --- a/src/stores/useWalletStore.ts +++ b/src/stores/useWalletStore.ts @@ -17,7 +17,7 @@ export const useWalletStore = defineStore('walletStore', { delegations: [] as Delegation[], unbonding: [] as UnbondingResponses[], rewards: {} as DelegatorRewards, - walletIsConnected: {} as WalletConnected | null + walletIsConnected: {} as WalletConnected }; }, getters: {