Skip to content

Commit 93da52e

Browse files
committed
feat: Implement dedicated wallet/extension connections
1 parent eb86be7 commit 93da52e

File tree

4 files changed

+57
-59
lines changed

4 files changed

+57
-59
lines changed

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
"peerDependencies": {
3939
"@polkadot/api": ">=9.14.0",
4040
"@polkadot/api-contract": ">=9.14.0",
41-
"@polkadot/extension-dapp": ">=0.44.0",
4241
"@polkadot/extension-inject": ">=0.44.0",
4342
"@polkadot/types": ">=9.14.0",
4443
"@polkadot/util": ">=10.4.0",

src/helpers/accountsAreEqual.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { InjectedAccountWithMeta } from '@polkadot/extension-inject/types'
1+
import { InjectedAccount } from '@polkadot/extension-inject/types'
22

33
/**
44
* Returns true if both given injected accounts have the same address.
55
*/
66
export const accountsAreEqual = (
7-
a1?: InjectedAccountWithMeta,
8-
a2?: InjectedAccountWithMeta,
7+
a1?: InjectedAccount,
8+
a2?: InjectedAccount,
99
) => {
1010
return (a1?.address || '').toLowerCase() === (a2?.address || '').toLowerCase()
1111
}
@@ -15,8 +15,8 @@ export const accountsAreEqual = (
1515
* same objects with the same addresses in the same order.
1616
*/
1717
export const accountArraysAreEqual = (
18-
a1: InjectedAccountWithMeta[],
19-
a2: InjectedAccountWithMeta[],
18+
a1: InjectedAccount[],
19+
a2: InjectedAccount[],
2020
) => {
2121
if (a1.length !== a2.length) return false
2222
return a1.every((a, i) => accountsAreEqual(a, a2[i]))

src/helpers/contractCall.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ export const contractTx = async (
127127
}
128128
})
129129
} catch (e) {
130-
// Reject if user cancelled with `UserCancelled`
130+
console.error('Error while performing transaction:', e)
131+
// Assume transaction was cancelled by user
131132
reject({ errorMessage: 'UserCancelled' })
132133
}
133134
})

src/provider.tsx

+50-52
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,30 @@ import { initPolkadotJs } from '@helpers/initPolkadotJs'
33
import { ApiPromise, HttpProvider, WsProvider } from '@polkadot/api'
44
import { ApiOptions } from '@polkadot/api/types'
55
import {
6-
InjectedAccountWithMeta,
6+
InjectedAccount,
7+
InjectedExtension,
78
Unsubcall,
89
} from '@polkadot/extension-inject/types'
910
import { Signer } from '@polkadot/types/types'
10-
import { registerDeployments, SubstrateDeployment } from '@registry'
11+
import { SubstrateDeployment, registerDeployments } from '@registry'
12+
import {
13+
SubstrateWallet,
14+
allSubstrateWallets,
15+
enableWallet,
16+
getSubstrateWallet,
17+
isWalletInstalled,
18+
} from '@wallets'
1119
import {
12-
createContext,
1320
Dispatch,
1421
FC,
1522
PropsWithChildren,
1623
SetStateAction,
24+
createContext,
1725
useContext,
1826
useEffect,
1927
useState,
2028
} from 'react'
21-
import { getSubstrateChain, SubstrateChain } from './chains'
29+
import { SubstrateChain, getSubstrateChain } from './chains'
2230

2331
/**
2432
* Helper Types
@@ -44,14 +52,13 @@ export type UseInkathonProviderContextType = {
4452
switchActiveChain?: (chain: SubstrateChain) => Promise<void>
4553
api?: ApiPromise
4654
provider?: WsProvider | HttpProvider
47-
connect?: () => Promise<void>
55+
connect?: (chain?: SubstrateChain, wallet?: SubstrateWallet) => Promise<void>
4856
disconnect?: () => void
49-
accounts?: InjectedAccountWithMeta[]
50-
activeAccount?: InjectedAccountWithMeta
57+
accounts?: InjectedAccount[]
58+
activeAccount?: InjectedAccount
59+
activeExtension?: InjectedExtension
5160
activeSigner?: Signer
52-
setActiveAccount?: Dispatch<
53-
SetStateAction<InjectedAccountWithMeta | undefined>
54-
>
61+
setActiveAccount?: Dispatch<SetStateAction<InjectedAccount | undefined>>
5562
deployments?: SubstrateDeployment[]
5663
}
5764
export const UseInkathonProviderContext =
@@ -110,10 +117,11 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
110117
)
111118
const [api, setApi] = useState<ApiPromise>()
112119
const [provider, setProvider] = useState<WsProvider | HttpProvider>()
113-
const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>([])
114-
const [activeAccount, setActiveAccount] = useState<InjectedAccountWithMeta>()
120+
const [accounts, setAccounts] = useState<InjectedAccount[]>([])
121+
const [activeAccount, setActiveAccount] = useState<InjectedAccount>()
122+
const [activeExtension, setActiveExtension] = useState<InjectedExtension>()
115123
const [latestActiveAccount, setLatestActiveAccount] =
116-
useState<InjectedAccountWithMeta>()
124+
useState<InjectedAccount>()
117125
const [activeSigner, setActiveSigner] = useState<Signer>()
118126
const [unsubscribeAccounts, setUnsubscribeAccounts] = useState<Unsubcall>()
119127
const [deployments, setDeployments] = useState<SubstrateDeployment[]>([])
@@ -150,34 +158,8 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
150158
}
151159
}
152160

153-
// Update signer when account changes
154-
const udpateSigner = async () => {
155-
await api?.isReadyOrError
156-
if (!activeAccount?.meta?.source || !api) {
157-
setActiveSigner(undefined)
158-
api?.setSigner(undefined as any)
159-
return
160-
}
161-
162-
try {
163-
// NOTE: Dynamic import to prevent hydration error in SSR environments
164-
const { web3FromSource } = await import('@polkadot/extension-dapp')
165-
const injector = await web3FromSource(activeAccount.meta.source)
166-
const signer = injector?.signer
167-
setActiveSigner(signer)
168-
api.setSigner(signer)
169-
} catch (e) {
170-
console.error('Error while setting signer:', e)
171-
setActiveSigner(undefined)
172-
api.setSigner(undefined as any)
173-
}
174-
}
175-
useEffect(() => {
176-
udpateSigner()
177-
}, [api, activeAccount])
178-
179161
// Updates account list and active account
180-
const updateAccounts = (injectedAccounts: InjectedAccountWithMeta[]) => {
162+
const updateAccounts = (injectedAccounts: InjectedAccount[]) => {
181163
const newAccounts = injectedAccounts || []
182164
// Find active account in new accounts or fallback to first account
183165
const newAccount =
@@ -202,8 +184,8 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
202184
}
203185
}, [activeAccount])
204186

205-
// Connect to injected wallets via polkadot-js/extension-dapp
206-
const connect = async (chain?: SubstrateChain) => {
187+
// Connect to injected wallet
188+
const connect = async (chain?: SubstrateChain, wallet?: SubstrateWallet) => {
207189
setError(undefined)
208190
setIsConnecting(true)
209191
setIsConnected(false)
@@ -214,14 +196,9 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
214196
}
215197

216198
try {
217-
// NOTE: Dynamic import to prevent hydration error in SSR environments
218-
const { web3AccountsSubscribe, web3Enable } = await import(
219-
'@polkadot/extension-dapp'
220-
)
221-
222-
// Initialize web3 extension
223-
const extensions = await web3Enable(appName)
224-
if (!extensions?.length) {
199+
// Determine installed wallets
200+
const wallets = allSubstrateWallets.filter((w) => isWalletInstalled(w))
201+
if (!wallets?.length) {
225202
const message = 'No Substrate-compatible extension detected'
226203
setError({
227204
code: UseInkathonErrorCode.NoSubstrateExtensionDetected,
@@ -230,17 +207,34 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
230207
throw new Error(message)
231208
}
232209

210+
// Determine wallet to use
211+
const preferredWallet = wallet && wallets.find((w) => w.id === wallet.id)
212+
const _wallet = preferredWallet || wallets[0]
213+
214+
// Enable wallet
215+
const extension = await enableWallet(_wallet, appName)
216+
const signer = extension?.signer as Signer
217+
setActiveExtension(extension)
218+
setActiveSigner(signer)
219+
233220
// Query & keep listening to injected accounts
234221
unsubscribeAccounts?.()
235-
const unsubscribe = await web3AccountsSubscribe(updateAccounts)
222+
const unsubscribe = extension?.accounts.subscribe(updateAccounts)
236223
setUnsubscribeAccounts(unsubscribe)
237224
} catch (e: any) {
238225
console.error('Error while connecting wallet:', e)
226+
setActiveExtension(undefined)
227+
setActiveSigner(undefined)
239228
} finally {
240229
setIsConnecting(false)
241230
}
242231
}
243232

233+
// Keep active signer up to date
234+
useEffect(() => {
235+
api?.setSigner(activeSigner as Signer)
236+
}, [api, activeSigner])
237+
244238
// Disconnect
245239
const disconnect = async () => {
246240
await api?.disconnect()
@@ -249,6 +243,7 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
249243
updateAccounts([])
250244
unsubscribeAccounts?.()
251245
setUnsubscribeAccounts(undefined)
246+
setActiveExtension(undefined)
252247
}
253248

254249
// Initialze
@@ -261,7 +256,9 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
261256

262257
// Switch active chain
263258
const switchActiveChain = async (chain: SubstrateChain) => {
264-
await connect(chain)
259+
const activeWallet =
260+
activeExtension && getSubstrateWallet(activeExtension.name)
261+
await connect(chain, activeWallet)
265262
}
266263

267264
return (
@@ -278,6 +275,7 @@ export const UseInkathonProvider: FC<UseInkathonProviderProps> = ({
278275
disconnect,
279276
accounts,
280277
activeAccount,
278+
activeExtension,
281279
activeSigner,
282280
setActiveAccount,
283281
deployments,

0 commit comments

Comments
 (0)