@1001-digital/components 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -22
- package/src/base/components/AppShell.vue +60 -0
- package/src/base/components/BottomNav.vue +44 -0
- package/src/base/components/Sidebar.vue +282 -0
- package/src/index.ts +3 -3
- package/src/evm/assets/wallets/coinbase.svg +0 -4
- package/src/evm/assets/wallets/in-app.svg +0 -5
- package/src/evm/assets/wallets/metamask.svg +0 -1
- package/src/evm/assets/wallets/phantom.svg +0 -4
- package/src/evm/assets/wallets/rabby.svg +0 -24
- package/src/evm/assets/wallets/rainbow.svg +0 -59
- package/src/evm/assets/wallets/safe.png +0 -0
- package/src/evm/assets/wallets/walletconnect.svg +0 -1
- package/src/evm/components/EvmAccount.vue +0 -28
- package/src/evm/components/EvmAvatar.vue +0 -62
- package/src/evm/components/EvmConnect.vue +0 -303
- package/src/evm/components/EvmConnectDialog.vue +0 -75
- package/src/evm/components/EvmConnectionStatus.vue +0 -13
- package/src/evm/components/EvmConnectorQR.vue +0 -86
- package/src/evm/components/EvmInAppWalletSetup.vue +0 -251
- package/src/evm/components/EvmMetaMaskQR.vue +0 -34
- package/src/evm/components/EvmProfile.vue +0 -186
- package/src/evm/components/EvmSeedPhraseInput.vue +0 -193
- package/src/evm/components/EvmSiwe.vue +0 -190
- package/src/evm/components/EvmSiweDialog.vue +0 -93
- package/src/evm/components/EvmSwitchNetwork.vue +0 -132
- package/src/evm/components/EvmTransactionFlow.vue +0 -353
- package/src/evm/components/EvmWalletConnectQR.vue +0 -13
- package/src/evm/components/EvmWalletConnectWallets.vue +0 -200
- package/src/evm/composables/base.ts +0 -7
- package/src/evm/composables/chainId.ts +0 -42
- package/src/evm/composables/ens.ts +0 -113
- package/src/evm/composables/gasPrice.ts +0 -37
- package/src/evm/composables/priceFeed.ts +0 -116
- package/src/evm/composables/siwe.ts +0 -89
- package/src/evm/composables/uri.ts +0 -12
- package/src/evm/composables/walletExplorer.ts +0 -130
- package/src/evm/config.ts +0 -35
- package/src/evm/connectors/inAppWallet.ts +0 -5
- package/src/evm/index.ts +0 -60
- package/src/evm/utils/addresses.ts +0 -6
- package/src/evm/utils/cache.ts +0 -59
- package/src/evm/utils/chains.ts +0 -32
- package/src/evm/utils/ens.ts +0 -116
- package/src/evm/utils/format-eth.ts +0 -15
- package/src/evm/utils/price.ts +0 -17
- package/src/evm/utils/siwe.ts +0 -70
- package/src/evm/utils/uri.ts +0 -24
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { ref, computed, watchEffect, toValue, type MaybeRefOrGetter, type Ref } from 'vue'
|
|
2
|
-
import { getPublicClient } from '@wagmi/core'
|
|
3
|
-
import { useConfig, type Config } from '@wagmi/vue'
|
|
4
|
-
import { useEvmConfig } from '../config'
|
|
5
|
-
import {
|
|
6
|
-
ensCache,
|
|
7
|
-
fetchEnsFromIndexer,
|
|
8
|
-
fetchEnsFromChain,
|
|
9
|
-
ENS_KEYS_AVATAR,
|
|
10
|
-
ENS_KEYS_PROFILE,
|
|
11
|
-
} from '../utils/ens'
|
|
12
|
-
import type { EnsProfile } from '../utils/ens'
|
|
13
|
-
|
|
14
|
-
type EnsMode = 'indexer' | 'chain'
|
|
15
|
-
|
|
16
|
-
interface UseEnsOptions {
|
|
17
|
-
mode?: MaybeRefOrGetter<EnsMode | undefined>
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function resolve(
|
|
21
|
-
identifier: string,
|
|
22
|
-
strategies: EnsMode[],
|
|
23
|
-
indexerUrls: string[],
|
|
24
|
-
wagmi: Config,
|
|
25
|
-
chainKeys: string[],
|
|
26
|
-
): Promise<EnsProfile> {
|
|
27
|
-
for (const strategy of strategies) {
|
|
28
|
-
try {
|
|
29
|
-
if (strategy === 'indexer') {
|
|
30
|
-
if (!indexerUrls.length) continue
|
|
31
|
-
return await fetchEnsFromIndexer(identifier, indexerUrls)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (strategy === 'chain') {
|
|
35
|
-
const client = getPublicClient(wagmi, { chainId: 1 })
|
|
36
|
-
if (!client) continue
|
|
37
|
-
return await fetchEnsFromChain(identifier, client, chainKeys)
|
|
38
|
-
}
|
|
39
|
-
} catch {
|
|
40
|
-
continue
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return { address: identifier, ens: null, data: null }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function useEnsBase(
|
|
48
|
-
tier: string,
|
|
49
|
-
identifier: MaybeRefOrGetter<string | undefined>,
|
|
50
|
-
chainKeys: string[],
|
|
51
|
-
options: UseEnsOptions = {},
|
|
52
|
-
) {
|
|
53
|
-
const config = useConfig()
|
|
54
|
-
const evmConfig = useEvmConfig()
|
|
55
|
-
|
|
56
|
-
const mode = computed<EnsMode>(
|
|
57
|
-
() => toValue(options.mode) || evmConfig.ens?.mode || 'indexer',
|
|
58
|
-
)
|
|
59
|
-
const indexerUrls = computed(() => evmConfig.ens?.indexerUrls || [])
|
|
60
|
-
const cacheKey = computed(() => `ens-${tier}-${toValue(identifier)}`)
|
|
61
|
-
|
|
62
|
-
const data: Ref<EnsProfile | null | undefined> = ref(
|
|
63
|
-
ensCache.get(cacheKey.value) ?? undefined,
|
|
64
|
-
)
|
|
65
|
-
const pending = ref(false)
|
|
66
|
-
|
|
67
|
-
watchEffect(async () => {
|
|
68
|
-
const id = toValue(identifier)
|
|
69
|
-
if (!id) {
|
|
70
|
-
data.value = null
|
|
71
|
-
pending.value = false
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const cached = ensCache.get(cacheKey.value)
|
|
76
|
-
if (cached) {
|
|
77
|
-
data.value = cached
|
|
78
|
-
pending.value = false
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const strategies: EnsMode[] =
|
|
83
|
-
mode.value === 'indexer' ? ['indexer', 'chain'] : ['chain', 'indexer']
|
|
84
|
-
|
|
85
|
-
pending.value = true
|
|
86
|
-
try {
|
|
87
|
-
data.value = await ensCache.fetch(cacheKey.value, () =>
|
|
88
|
-
resolve(id, strategies, indexerUrls.value, config, chainKeys),
|
|
89
|
-
)
|
|
90
|
-
} catch {
|
|
91
|
-
data.value = null
|
|
92
|
-
} finally {
|
|
93
|
-
pending.value = false
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
return { data, pending }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const useEns = (
|
|
101
|
-
identifier: MaybeRefOrGetter<string | undefined>,
|
|
102
|
-
options?: UseEnsOptions,
|
|
103
|
-
) => useEnsBase('resolve', identifier, [], options)
|
|
104
|
-
|
|
105
|
-
export const useEnsWithAvatar = (
|
|
106
|
-
identifier: MaybeRefOrGetter<string | undefined>,
|
|
107
|
-
options?: UseEnsOptions,
|
|
108
|
-
) => useEnsBase('avatar', identifier, [...ENS_KEYS_AVATAR], options)
|
|
109
|
-
|
|
110
|
-
export const useEnsProfile = (
|
|
111
|
-
identifier: MaybeRefOrGetter<string | undefined>,
|
|
112
|
-
options?: UseEnsOptions,
|
|
113
|
-
) => useEnsBase('profile', identifier, [...ENS_KEYS_PROFILE], options)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { ref, computed, watch, type Ref, type WatchStopHandle } from 'vue'
|
|
2
|
-
import { formatEther, formatGwei } from 'viem'
|
|
3
|
-
import { getGasPrice } from '@wagmi/core'
|
|
4
|
-
import { useConfig, useBlockNumber } from '@wagmi/vue'
|
|
5
|
-
|
|
6
|
-
let priceWatcher: WatchStopHandle | null = null
|
|
7
|
-
const price: Ref<bigint> = ref(0n)
|
|
8
|
-
|
|
9
|
-
export const useGasPrice = () => {
|
|
10
|
-
const config = useConfig()
|
|
11
|
-
const { data: blockNumber } = useBlockNumber()
|
|
12
|
-
|
|
13
|
-
const updatePrice = async () => {
|
|
14
|
-
price.value = await getGasPrice(config)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (!priceWatcher) {
|
|
18
|
-
updatePrice()
|
|
19
|
-
priceWatcher = watch(blockNumber, () => updatePrice())
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const unitPrice = computed(() => ({
|
|
23
|
-
wei: price.value,
|
|
24
|
-
gwei: formatGwei(price.value),
|
|
25
|
-
eth: formatEther(price.value),
|
|
26
|
-
|
|
27
|
-
formatted: {
|
|
28
|
-
gwei:
|
|
29
|
-
price.value > 2_000_000_000_000n
|
|
30
|
-
? Math.round(parseFloat(formatGwei(price.value)))
|
|
31
|
-
: parseFloat(formatGwei(price.value)).toFixed(1),
|
|
32
|
-
eth: formatEther(price.value),
|
|
33
|
-
},
|
|
34
|
-
}))
|
|
35
|
-
|
|
36
|
-
return unitPrice
|
|
37
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { reactive, computed } from 'vue'
|
|
2
|
-
import { readContract } from '@wagmi/core'
|
|
3
|
-
import { useConfig } from '@wagmi/vue'
|
|
4
|
-
import { parseJSON, stringifyJSON, formatPrice } from '../utils/price'
|
|
5
|
-
import { nowInSeconds } from '../../base/utils/time'
|
|
6
|
-
|
|
7
|
-
const CHAINLINK_ETH_USD_ABI = [
|
|
8
|
-
{
|
|
9
|
-
inputs: [],
|
|
10
|
-
name: 'latestRoundData',
|
|
11
|
-
outputs: [
|
|
12
|
-
{ internalType: 'uint80', name: 'roundId', type: 'uint80' },
|
|
13
|
-
{ internalType: 'int256', name: 'answer', type: 'int256' },
|
|
14
|
-
{ internalType: 'uint256', name: 'startedAt', type: 'uint256' },
|
|
15
|
-
{ internalType: 'uint256', name: 'updatedAt', type: 'uint256' },
|
|
16
|
-
{ internalType: 'uint80', name: 'answeredInRound', type: 'uint80' },
|
|
17
|
-
],
|
|
18
|
-
stateMutability: 'view',
|
|
19
|
-
type: 'function',
|
|
20
|
-
},
|
|
21
|
-
] as const
|
|
22
|
-
|
|
23
|
-
const CHAINLINK_ETH_USD = '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'
|
|
24
|
-
const STORAGE_KEY = 'evm:price-feed'
|
|
25
|
-
const CACHE_TTL = 3_600 // 1 hour in seconds
|
|
26
|
-
|
|
27
|
-
interface PriceFeedState {
|
|
28
|
-
ethUSDRaw: bigint | null
|
|
29
|
-
lastUpdated: number
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const state = reactive<PriceFeedState>({
|
|
33
|
-
ethUSDRaw: null,
|
|
34
|
-
lastUpdated: 0,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
function loadFromStorage() {
|
|
38
|
-
if (typeof window === 'undefined') return
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const stored = localStorage.getItem(STORAGE_KEY)
|
|
42
|
-
if (!stored) return
|
|
43
|
-
|
|
44
|
-
const parsed = parseJSON(stored) as PriceFeedState
|
|
45
|
-
if (parsed.ethUSDRaw) state.ethUSDRaw = parsed.ethUSDRaw
|
|
46
|
-
if (parsed.lastUpdated) state.lastUpdated = parsed.lastUpdated
|
|
47
|
-
} catch {
|
|
48
|
-
// Ignore corrupted storage
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function saveToStorage() {
|
|
53
|
-
if (typeof window === 'undefined') return
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
localStorage.setItem(
|
|
57
|
-
STORAGE_KEY,
|
|
58
|
-
stringifyJSON({
|
|
59
|
-
ethUSDRaw: state.ethUSDRaw,
|
|
60
|
-
lastUpdated: state.lastUpdated,
|
|
61
|
-
}),
|
|
62
|
-
)
|
|
63
|
-
} catch {
|
|
64
|
-
// Ignore storage errors
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export const usePriceFeed = () => {
|
|
69
|
-
const config = useConfig()
|
|
70
|
-
|
|
71
|
-
// Load cached data on first use
|
|
72
|
-
if (!state.lastUpdated) loadFromStorage()
|
|
73
|
-
|
|
74
|
-
const ethUSD = computed(() =>
|
|
75
|
-
state.ethUSDRaw ? state.ethUSDRaw / BigInt(1e8) : 0n,
|
|
76
|
-
)
|
|
77
|
-
const ethUSC = computed(() =>
|
|
78
|
-
state.ethUSDRaw ? state.ethUSDRaw / BigInt(1e6) : 0n,
|
|
79
|
-
)
|
|
80
|
-
const ethUSDFormatted = computed(() =>
|
|
81
|
-
formatPrice(Number(ethUSC.value) / 100, 2),
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
const weiToUSD = (wei: bigint) => {
|
|
85
|
-
const cents = (wei * (state.ethUSDRaw || 0n)) / 10n ** 18n / 10n ** 6n
|
|
86
|
-
return formatPrice(Number(cents) / 100, 2)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function fetchPrice() {
|
|
90
|
-
if (nowInSeconds() - state.lastUpdated < CACHE_TTL) return
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
const [, answer] = await readContract(config, {
|
|
94
|
-
address: CHAINLINK_ETH_USD,
|
|
95
|
-
abi: CHAINLINK_ETH_USD_ABI,
|
|
96
|
-
functionName: 'latestRoundData',
|
|
97
|
-
chainId: 1,
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
state.ethUSDRaw = answer
|
|
101
|
-
state.lastUpdated = nowInSeconds()
|
|
102
|
-
saveToStorage()
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.warn('Error fetching ETH/USD price:', error)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
ethUSDRaw: computed(() => state.ethUSDRaw),
|
|
110
|
-
ethUSD,
|
|
111
|
-
ethUSC,
|
|
112
|
-
ethUSDFormatted,
|
|
113
|
-
weiToUSD,
|
|
114
|
-
fetchPrice,
|
|
115
|
-
}
|
|
116
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { ref, readonly } from 'vue'
|
|
2
|
-
import { signMessage } from '@wagmi/core'
|
|
3
|
-
import { useConfig, useConnection } from '@wagmi/vue'
|
|
4
|
-
import type { Config } from '@wagmi/vue'
|
|
5
|
-
import { createSiweMessage, type SiweMessageParams } from '../utils/siwe'
|
|
6
|
-
|
|
7
|
-
export interface SiweSession {
|
|
8
|
-
address: `0x${string}`
|
|
9
|
-
chainId: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface UseSiweOptions {
|
|
13
|
-
getNonce: () => Promise<string>
|
|
14
|
-
verify: (message: string, signature: string) => Promise<boolean>
|
|
15
|
-
domain?: string
|
|
16
|
-
uri?: string
|
|
17
|
-
statement?: string
|
|
18
|
-
expirationTime?: string
|
|
19
|
-
requestId?: string
|
|
20
|
-
resources?: string[]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const _isAuthenticated = ref(false)
|
|
24
|
-
const _session = ref<SiweSession | null>(null)
|
|
25
|
-
|
|
26
|
-
export const useSiwe = () => {
|
|
27
|
-
const config = useConfig()
|
|
28
|
-
const { address, chainId } = useConnection()
|
|
29
|
-
|
|
30
|
-
const setSession = (session: SiweSession) => {
|
|
31
|
-
_isAuthenticated.value = true
|
|
32
|
-
_session.value = session
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const clearSession = () => {
|
|
36
|
-
_isAuthenticated.value = false
|
|
37
|
-
_session.value = null
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const signIn = async (options: UseSiweOptions) => {
|
|
41
|
-
const currentAddress = address.value
|
|
42
|
-
const currentChainId = chainId.value
|
|
43
|
-
|
|
44
|
-
if (!currentAddress || !currentChainId) {
|
|
45
|
-
throw new Error('Wallet not connected')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const nonce = await options.getNonce()
|
|
49
|
-
|
|
50
|
-
const messageParams: SiweMessageParams = {
|
|
51
|
-
domain: options.domain || window.location.host,
|
|
52
|
-
address: currentAddress,
|
|
53
|
-
uri: options.uri || window.location.origin,
|
|
54
|
-
chainId: currentChainId,
|
|
55
|
-
nonce,
|
|
56
|
-
statement: options.statement,
|
|
57
|
-
expirationTime: options.expirationTime,
|
|
58
|
-
requestId: options.requestId,
|
|
59
|
-
resources: options.resources,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const message = createSiweMessage(messageParams)
|
|
63
|
-
const signature = await signMessage(config as Config, { message })
|
|
64
|
-
|
|
65
|
-
const verified = await options.verify(message, signature)
|
|
66
|
-
|
|
67
|
-
if (!verified) {
|
|
68
|
-
throw new Error('Signature verification failed')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
setSession({
|
|
72
|
-
address: currentAddress,
|
|
73
|
-
chainId: currentChainId,
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const signOut = () => {
|
|
78
|
-
clearSession()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
isAuthenticated: readonly(_isAuthenticated),
|
|
83
|
-
session: readonly(_session),
|
|
84
|
-
signIn,
|
|
85
|
-
signOut,
|
|
86
|
-
setSession,
|
|
87
|
-
clearSession,
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useEvmConfig } from '../config'
|
|
2
|
-
import { resolveUri } from '../utils/uri'
|
|
3
|
-
|
|
4
|
-
export const useResolveUri = () => {
|
|
5
|
-
const evmConfig = useEvmConfig()
|
|
6
|
-
|
|
7
|
-
return (uri?: string) =>
|
|
8
|
-
resolveUri(uri, {
|
|
9
|
-
ipfsGateway: evmConfig.ipfsGateway,
|
|
10
|
-
arweaveGateway: evmConfig.arweaveGateway,
|
|
11
|
-
})
|
|
12
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { ref, computed } from 'vue'
|
|
2
|
-
import { useEvmConfig } from '../config'
|
|
3
|
-
|
|
4
|
-
const EXPLORER_API = 'https://explorer-api.walletconnect.com/v3'
|
|
5
|
-
const RECENT_KEY = 'evm:recent-wallets'
|
|
6
|
-
const PAGE_SIZE = 40
|
|
7
|
-
|
|
8
|
-
export interface ExplorerWallet {
|
|
9
|
-
id: string
|
|
10
|
-
name: string
|
|
11
|
-
image_id: string
|
|
12
|
-
homepage: string
|
|
13
|
-
mobile: { native: string; universal: string }
|
|
14
|
-
desktop: { native: string; universal: string }
|
|
15
|
-
injected: { namespace: string; injected_id: string }[] | null
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function useWalletExplorer() {
|
|
19
|
-
const config = useEvmConfig()
|
|
20
|
-
const projectId = computed(() => config.walletConnectProjectId || '')
|
|
21
|
-
|
|
22
|
-
const wallets = ref<ExplorerWallet[]>([])
|
|
23
|
-
const searchResults = ref<ExplorerWallet[]>([])
|
|
24
|
-
const totalCount = ref(0)
|
|
25
|
-
const page = ref(0)
|
|
26
|
-
const loading = ref(false)
|
|
27
|
-
const searching = ref(false)
|
|
28
|
-
const recentIds = ref<string[]>(loadRecent())
|
|
29
|
-
|
|
30
|
-
const recentWallets = computed(() =>
|
|
31
|
-
recentIds.value
|
|
32
|
-
.map(id => wallets.value.find(w => w.id === id))
|
|
33
|
-
.filter((w): w is ExplorerWallet => !!w)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
const hasMore = computed(() => wallets.value.length < totalCount.value)
|
|
37
|
-
|
|
38
|
-
function imageUrl(wallet: ExplorerWallet) {
|
|
39
|
-
return `${EXPLORER_API}/logo/md/${wallet.image_id}?projectId=${projectId.value}`
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function walletHref(wallet: ExplorerWallet, uri: string) {
|
|
43
|
-
const encoded = encodeURIComponent(uri)
|
|
44
|
-
|
|
45
|
-
const universal = wallet.mobile?.universal
|
|
46
|
-
if (universal) {
|
|
47
|
-
const base = universal.endsWith('/') ? universal : universal + '/'
|
|
48
|
-
return `${base}wc?uri=${encoded}`
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const native = wallet.mobile?.native
|
|
52
|
-
if (native) {
|
|
53
|
-
return `${native}wc?uri=${encoded}`
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return null
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function fetchNextPage() {
|
|
60
|
-
if (!projectId.value || loading.value) return
|
|
61
|
-
loading.value = true
|
|
62
|
-
const nextPage = page.value + 1
|
|
63
|
-
try {
|
|
64
|
-
const res = await fetch(
|
|
65
|
-
`${EXPLORER_API}/wallets?projectId=${projectId.value}&entries=${PAGE_SIZE}&page=${nextPage}&sdks=sign_v2`
|
|
66
|
-
)
|
|
67
|
-
const data = await res.json()
|
|
68
|
-
const fetched = Object.values(data.listings || {}) as ExplorerWallet[]
|
|
69
|
-
wallets.value = nextPage === 1 ? fetched : [...wallets.value, ...fetched]
|
|
70
|
-
totalCount.value = data.total || 0
|
|
71
|
-
page.value = nextPage
|
|
72
|
-
} catch (e) {
|
|
73
|
-
console.error('Failed to fetch wallets:', e)
|
|
74
|
-
} finally {
|
|
75
|
-
loading.value = false
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function search(query: string) {
|
|
80
|
-
if (!projectId.value || !query || query.length < 2) {
|
|
81
|
-
searchResults.value = []
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
searching.value = true
|
|
85
|
-
try {
|
|
86
|
-
const res = await fetch(
|
|
87
|
-
`${EXPLORER_API}/wallets?projectId=${projectId.value}&entries=${PAGE_SIZE}&page=1&search=${encodeURIComponent(query)}&sdks=sign_v2`
|
|
88
|
-
)
|
|
89
|
-
const data = await res.json()
|
|
90
|
-
searchResults.value = Object.values(data.listings || {})
|
|
91
|
-
} catch (e) {
|
|
92
|
-
console.error('Failed to search wallets:', e)
|
|
93
|
-
} finally {
|
|
94
|
-
searching.value = false
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function loadRecent(): string[] {
|
|
99
|
-
try {
|
|
100
|
-
return JSON.parse(localStorage.getItem(RECENT_KEY) || '[]')
|
|
101
|
-
} catch {
|
|
102
|
-
return []
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function addRecent(walletId: string) {
|
|
107
|
-
const ids = recentIds.value.filter(id => id !== walletId)
|
|
108
|
-
ids.unshift(walletId)
|
|
109
|
-
recentIds.value = ids.slice(0, 3)
|
|
110
|
-
try {
|
|
111
|
-
localStorage.setItem(RECENT_KEY, JSON.stringify(recentIds.value))
|
|
112
|
-
} catch {}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
wallets,
|
|
117
|
-
searchResults,
|
|
118
|
-
totalCount,
|
|
119
|
-
page,
|
|
120
|
-
loading,
|
|
121
|
-
searching,
|
|
122
|
-
recentWallets,
|
|
123
|
-
hasMore,
|
|
124
|
-
imageUrl,
|
|
125
|
-
walletHref,
|
|
126
|
-
fetchNextPage,
|
|
127
|
-
search,
|
|
128
|
-
addRecent,
|
|
129
|
-
}
|
|
130
|
-
}
|
package/src/evm/config.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { inject, type InjectionKey } from 'vue'
|
|
2
|
-
|
|
3
|
-
export interface EvmChainConfig {
|
|
4
|
-
id: number
|
|
5
|
-
blockExplorer?: string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface EvmConfig {
|
|
9
|
-
title?: string
|
|
10
|
-
defaultChain?: string
|
|
11
|
-
chains: Record<string, EvmChainConfig>
|
|
12
|
-
ens?: {
|
|
13
|
-
mode?: 'indexer' | 'chain'
|
|
14
|
-
indexerUrls?: string[]
|
|
15
|
-
}
|
|
16
|
-
ipfsGateway?: string
|
|
17
|
-
arweaveGateway?: string
|
|
18
|
-
baseURL?: string
|
|
19
|
-
walletConnectProjectId?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const EvmConfigKey: InjectionKey<EvmConfig> = Symbol('EvmConfig')
|
|
23
|
-
|
|
24
|
-
export const defaultEvmConfig: EvmConfig = {
|
|
25
|
-
title: 'EVM Layer',
|
|
26
|
-
defaultChain: 'mainnet',
|
|
27
|
-
chains: {
|
|
28
|
-
mainnet: { id: 1, blockExplorer: 'https://etherscan.io' },
|
|
29
|
-
},
|
|
30
|
-
ens: { mode: 'indexer' },
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const useEvmConfig = (): EvmConfig => {
|
|
34
|
-
return inject(EvmConfigKey, defaultEvmConfig)
|
|
35
|
-
}
|
package/src/evm/index.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Config
|
|
2
|
-
export { EvmConfigKey, defaultEvmConfig, useEvmConfig } from './config'
|
|
3
|
-
export type { EvmConfig, EvmChainConfig } from './config'
|
|
4
|
-
|
|
5
|
-
// Utils
|
|
6
|
-
export { createCache } from './utils/cache'
|
|
7
|
-
export { shortAddress } from './utils/addresses'
|
|
8
|
-
export { resolveChain } from './utils/chains'
|
|
9
|
-
export { formatETH } from './utils/format-eth'
|
|
10
|
-
export {
|
|
11
|
-
ensCache,
|
|
12
|
-
fetchEnsFromIndexer,
|
|
13
|
-
fetchEnsFromChain,
|
|
14
|
-
ENS_KEYS_AVATAR,
|
|
15
|
-
ENS_KEYS_PROFILE,
|
|
16
|
-
} from './utils/ens'
|
|
17
|
-
export type { EnsProfile } from './utils/ens'
|
|
18
|
-
export { stringifyJSON, parseJSON, formatPrice } from './utils/price'
|
|
19
|
-
export { resolveUri } from './utils/uri'
|
|
20
|
-
export type { ResolveUriOptions } from './utils/uri'
|
|
21
|
-
export { createSiweMessage } from './utils/siwe'
|
|
22
|
-
export type { SiweMessageParams } from './utils/siwe'
|
|
23
|
-
|
|
24
|
-
// Composables
|
|
25
|
-
export { useBaseURL } from './composables/base'
|
|
26
|
-
export {
|
|
27
|
-
useChainConfig,
|
|
28
|
-
useMainChainId,
|
|
29
|
-
useBlockExplorer,
|
|
30
|
-
useEnsureChainIdCheck,
|
|
31
|
-
} from './composables/chainId'
|
|
32
|
-
export { useEns, useEnsWithAvatar, useEnsProfile } from './composables/ens'
|
|
33
|
-
export { useResolveUri } from './composables/uri'
|
|
34
|
-
export { useGasPrice } from './composables/gasPrice'
|
|
35
|
-
export { usePriceFeed } from './composables/priceFeed'
|
|
36
|
-
export { useWalletExplorer } from './composables/walletExplorer'
|
|
37
|
-
export type { ExplorerWallet } from './composables/walletExplorer'
|
|
38
|
-
export { useSiwe } from './composables/siwe'
|
|
39
|
-
export type { SiweSession, UseSiweOptions } from './composables/siwe'
|
|
40
|
-
|
|
41
|
-
// Connectors
|
|
42
|
-
export { inAppWallet, prepareInAppWallet } from './connectors/inAppWallet'
|
|
43
|
-
|
|
44
|
-
// Components
|
|
45
|
-
export { default as EvmAccount } from './components/EvmAccount.vue'
|
|
46
|
-
export { default as EvmAvatar } from './components/EvmAvatar.vue'
|
|
47
|
-
export { default as EvmConnect } from './components/EvmConnect.vue'
|
|
48
|
-
export { default as EvmConnectDialog } from './components/EvmConnectDialog.vue'
|
|
49
|
-
export { default as EvmConnectionStatus } from './components/EvmConnectionStatus.vue'
|
|
50
|
-
export { default as EvmProfile } from './components/EvmProfile.vue'
|
|
51
|
-
export { default as EvmSwitchNetwork } from './components/EvmSwitchNetwork.vue'
|
|
52
|
-
export { default as EvmConnectorQR } from './components/EvmConnectorQR.vue'
|
|
53
|
-
export { default as EvmMetaMaskQR } from './components/EvmMetaMaskQR.vue'
|
|
54
|
-
export { default as EvmWalletConnectQR } from './components/EvmWalletConnectQR.vue'
|
|
55
|
-
export { default as EvmWalletConnectWallets } from './components/EvmWalletConnectWallets.vue'
|
|
56
|
-
export { default as EvmTransactionFlow } from './components/EvmTransactionFlow.vue'
|
|
57
|
-
export { default as EvmSeedPhraseInput } from './components/EvmSeedPhraseInput.vue'
|
|
58
|
-
export { default as EvmInAppWalletSetup } from './components/EvmInAppWalletSetup.vue'
|
|
59
|
-
export { default as EvmSiwe } from './components/EvmSiwe.vue'
|
|
60
|
-
export { default as EvmSiweDialog } from './components/EvmSiweDialog.vue'
|
package/src/evm/utils/cache.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
interface CacheEntry<T> {
|
|
2
|
-
data: T
|
|
3
|
-
expiresAt: number
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function createCache<T>(ttl: number, max: number) {
|
|
7
|
-
const entries = new Map<string, CacheEntry<T>>()
|
|
8
|
-
const pending = new Map<string, Promise<T>>()
|
|
9
|
-
|
|
10
|
-
function prune() {
|
|
11
|
-
const now = Date.now()
|
|
12
|
-
for (const [key, entry] of entries) {
|
|
13
|
-
if (entry.expiresAt <= now) entries.delete(key)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (entries.size > max) {
|
|
17
|
-
const excess = entries.size - max
|
|
18
|
-
const keys = entries.keys()
|
|
19
|
-
for (let i = 0; i < excess; i++) {
|
|
20
|
-
entries.delete(keys.next().value!)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function get(key: string): T | undefined {
|
|
26
|
-
const entry = entries.get(key)
|
|
27
|
-
if (!entry) return undefined
|
|
28
|
-
if (entry.expiresAt <= Date.now()) {
|
|
29
|
-
entries.delete(key)
|
|
30
|
-
return undefined
|
|
31
|
-
}
|
|
32
|
-
return entry.data
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function fetch(key: string, fn: () => Promise<T>): Promise<T> {
|
|
36
|
-
const cached = get(key)
|
|
37
|
-
if (cached) return Promise.resolve(cached)
|
|
38
|
-
|
|
39
|
-
const inflight = pending.get(key)
|
|
40
|
-
if (inflight) return inflight
|
|
41
|
-
|
|
42
|
-
const promise = fn()
|
|
43
|
-
.then((result) => {
|
|
44
|
-
entries.set(key, { data: result, expiresAt: Date.now() + ttl })
|
|
45
|
-
pending.delete(key)
|
|
46
|
-
if (entries.size > max) prune()
|
|
47
|
-
return result
|
|
48
|
-
})
|
|
49
|
-
.catch((err) => {
|
|
50
|
-
pending.delete(key)
|
|
51
|
-
throw err
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
pending.set(key, promise)
|
|
55
|
-
return promise
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return { get, fetch }
|
|
59
|
-
}
|
package/src/evm/utils/chains.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { defineChain, type Chain } from 'viem'
|
|
2
|
-
import {
|
|
3
|
-
mainnet,
|
|
4
|
-
sepolia,
|
|
5
|
-
holesky,
|
|
6
|
-
optimism,
|
|
7
|
-
arbitrum,
|
|
8
|
-
base,
|
|
9
|
-
polygon,
|
|
10
|
-
localhost,
|
|
11
|
-
} from 'viem/chains'
|
|
12
|
-
|
|
13
|
-
const KNOWN: Chain[] = [
|
|
14
|
-
mainnet,
|
|
15
|
-
sepolia,
|
|
16
|
-
holesky,
|
|
17
|
-
optimism,
|
|
18
|
-
arbitrum,
|
|
19
|
-
base,
|
|
20
|
-
polygon,
|
|
21
|
-
localhost,
|
|
22
|
-
]
|
|
23
|
-
const byId = new Map<number, Chain>(KNOWN.map((c) => [c.id, c]))
|
|
24
|
-
|
|
25
|
-
export const resolveChain = (id: number): Chain =>
|
|
26
|
-
byId.get(id) ??
|
|
27
|
-
defineChain({
|
|
28
|
-
id,
|
|
29
|
-
name: `Chain ${id}`,
|
|
30
|
-
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
31
|
-
rpcUrls: { default: { http: [] } },
|
|
32
|
-
})
|