@0xsequence/provider 1.0.5 → 1.1.1
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/dist/0xsequence-provider.cjs.dev.js +1763 -1678
- package/dist/0xsequence-provider.cjs.prod.js +1763 -1678
- package/dist/0xsequence-provider.esm.js +1756 -1676
- package/dist/declarations/src/client.d.ts +74 -0
- package/dist/declarations/src/index.d.ts +3 -1
- package/dist/declarations/src/init.d.ts +25 -0
- package/dist/declarations/src/provider.d.ts +127 -63
- package/dist/declarations/src/signer.d.ts +87 -0
- package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +21 -0
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +0 -1
- package/dist/declarations/src/types.d.ts +25 -9
- package/dist/declarations/src/utils/index.d.ts +10 -7
- package/dist/declarations/src/utils.d.ts +21 -15
- package/package.json +19 -12
- package/src/client.ts +423 -0
- package/src/extended.ts +4 -0
- package/src/index.ts +3 -1
- package/src/init.ts +134 -0
- package/src/provider.ts +447 -424
- package/src/signer.ts +316 -0
- package/src/transactions.ts +23 -0
- package/src/transports/base-wallet-transport.ts +3 -8
- package/src/transports/mux-transport/mux-message-provider.ts +86 -2
- package/src/transports/proxy-transport/proxy-message-provider.ts +1 -1
- package/src/transports/wallet-request-handler.ts +8 -33
- package/src/transports/window-transport/window-message-provider.ts +4 -2
- package/src/types.ts +41 -10
- package/src/utils/index.ts +16 -76
- package/src/utils.ts +81 -51
- package/dist/declarations/src/extended.d.ts +0 -6
- package/dist/declarations/src/wallet.d.ts +0 -105
- package/src/wallet.ts +0 -770
package/src/wallet.ts
DELETED
|
@@ -1,770 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NetworkConfig,
|
|
3
|
-
ChainIdLike,
|
|
4
|
-
JsonRpcSender,
|
|
5
|
-
JsonRpcRouter,
|
|
6
|
-
JsonRpcMiddleware,
|
|
7
|
-
allowProviderMiddleware,
|
|
8
|
-
CachedProvider,
|
|
9
|
-
loggingProviderMiddleware,
|
|
10
|
-
SigningProvider,
|
|
11
|
-
EagerProvider,
|
|
12
|
-
exceptionProviderMiddleware,
|
|
13
|
-
networkProviderMiddleware,
|
|
14
|
-
JsonRpcRequest,
|
|
15
|
-
findNetworkConfig,
|
|
16
|
-
updateNetworkConfig,
|
|
17
|
-
ensureValidNetworks,
|
|
18
|
-
sortNetworks,
|
|
19
|
-
findSupportedNetwork
|
|
20
|
-
} from '@0xsequence/network'
|
|
21
|
-
import { getDefaultConnectionInfo, logger } from '@0xsequence/utils'
|
|
22
|
-
import { Web3Provider, Web3Signer } from './provider'
|
|
23
|
-
import {
|
|
24
|
-
MuxMessageProvider,
|
|
25
|
-
WindowMessageProvider,
|
|
26
|
-
ProxyMessageProvider,
|
|
27
|
-
ProxyMessageChannelPort,
|
|
28
|
-
UnrealMessageProvider
|
|
29
|
-
} from './transports'
|
|
30
|
-
import { WalletSession, ProviderEventTypes, ConnectOptions, OpenWalletIntent, ConnectDetails } from './types'
|
|
31
|
-
import { ethers, providers } from 'ethers'
|
|
32
|
-
import { ExtensionMessageProvider } from './transports/extension-transport/extension-message-provider'
|
|
33
|
-
import { LocalStore, ItemStore, LocalStorage } from './utils'
|
|
34
|
-
import { WalletUtils } from './utils/index'
|
|
35
|
-
|
|
36
|
-
import { Runtime } from 'webextension-polyfill'
|
|
37
|
-
import { commons } from '@0xsequence/core'
|
|
38
|
-
import { AccountStatus } from '@0xsequence/account'
|
|
39
|
-
|
|
40
|
-
export const SESSION_LOCALSTORE_KEY = '@sequence.session'
|
|
41
|
-
|
|
42
|
-
export interface WalletProvider {
|
|
43
|
-
connect(options?: ConnectOptions): Promise<ConnectDetails>
|
|
44
|
-
disconnect(): void
|
|
45
|
-
|
|
46
|
-
isConnected(): boolean
|
|
47
|
-
getSession(): WalletSession | undefined
|
|
48
|
-
|
|
49
|
-
getAddress(): Promise<string>
|
|
50
|
-
getNetworks(chainId?: ChainIdLike): Promise<NetworkConfig[]>
|
|
51
|
-
getChainId(): Promise<number>
|
|
52
|
-
|
|
53
|
-
isOpened(): boolean
|
|
54
|
-
openWallet(path?: string, intent?: OpenWalletIntent, networkId?: string | number): Promise<boolean>
|
|
55
|
-
closeWallet(): void
|
|
56
|
-
|
|
57
|
-
getProvider(chainId?: ChainIdLike): Web3Provider | undefined
|
|
58
|
-
getSigner(chainId?: ChainIdLike): Web3Signer
|
|
59
|
-
|
|
60
|
-
getWalletContext(): Promise<commons.context.VersionedContext>
|
|
61
|
-
getWalletConfig(chainId?: ChainIdLike): Promise<commons.config.Config>
|
|
62
|
-
getWalletState(chainId?: ChainIdLike): Promise<AccountStatus>
|
|
63
|
-
isDeployed(chainId?: ChainIdLike): Promise<boolean>
|
|
64
|
-
|
|
65
|
-
getProviderConfig(): ProviderConfig
|
|
66
|
-
|
|
67
|
-
on<K extends keyof ProviderEventTypes>(event: K, fn: ProviderEventTypes[K]): void
|
|
68
|
-
once<K extends keyof ProviderEventTypes>(event: K, fn: ProviderEventTypes[K]): void
|
|
69
|
-
|
|
70
|
-
utils: WalletUtils
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export class Wallet implements WalletProvider {
|
|
74
|
-
public utils: WalletUtils
|
|
75
|
-
|
|
76
|
-
private config: ProviderConfig
|
|
77
|
-
private session?: WalletSession
|
|
78
|
-
|
|
79
|
-
private connectedSites: LocalStore<string[]>
|
|
80
|
-
|
|
81
|
-
private transport: {
|
|
82
|
-
// top-level provider which connects all transport layers
|
|
83
|
-
provider?: Web3Provider
|
|
84
|
-
|
|
85
|
-
// middleware stack for provider
|
|
86
|
-
router?: JsonRpcRouter
|
|
87
|
-
networkProvider?: JsonRpcMiddleware
|
|
88
|
-
allowProvider?: JsonRpcMiddleware
|
|
89
|
-
cachedProvider?: CachedProvider
|
|
90
|
-
|
|
91
|
-
// message communication
|
|
92
|
-
messageProvider?: MuxMessageProvider
|
|
93
|
-
windowMessageProvider?: WindowMessageProvider
|
|
94
|
-
proxyMessageProvider?: ProxyMessageProvider
|
|
95
|
-
extensionMessageProvider?: ExtensionMessageProvider
|
|
96
|
-
unrealMessageProvider?: UnrealMessageProvider
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private networks: NetworkConfig[]
|
|
100
|
-
private providers: { [chainId: number]: Web3Provider }
|
|
101
|
-
|
|
102
|
-
constructor(network?: string | number, config?: Partial<ProviderConfig>) {
|
|
103
|
-
// config is a Partial, so that we may intersect it with the DefaultProviderConfig,
|
|
104
|
-
// which allows easy overriding and control of the config.
|
|
105
|
-
this.config = { ...DefaultProviderConfig }
|
|
106
|
-
if (config) {
|
|
107
|
-
this.config = { ...this.config, ...config }
|
|
108
|
-
}
|
|
109
|
-
if (network) {
|
|
110
|
-
this.config.defaultNetworkId = network
|
|
111
|
-
} else if (!this.config.defaultNetworkId) {
|
|
112
|
-
this.config.defaultNetworkId = 'mainnet'
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (config?.localStorage) {
|
|
116
|
-
LocalStorage.use(config.localStorage)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.transport = {}
|
|
120
|
-
this.networks = []
|
|
121
|
-
this.providers = {}
|
|
122
|
-
this.connectedSites = new LocalStore('@sequence.connectedSites', [])
|
|
123
|
-
this.utils = new WalletUtils(this)
|
|
124
|
-
this.init()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private init = () => {
|
|
128
|
-
if (this.transport.provider) {
|
|
129
|
-
// init must have already been called
|
|
130
|
-
return
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Setup provider
|
|
134
|
-
|
|
135
|
-
this.transport.messageProvider = new MuxMessageProvider()
|
|
136
|
-
|
|
137
|
-
// multiple message provider setup, first one to connect will be the main transport
|
|
138
|
-
if (this.config.transports?.windowTransport?.enabled && typeof window === 'object') {
|
|
139
|
-
this.transport.windowMessageProvider = new WindowMessageProvider(this.config.walletAppURL)
|
|
140
|
-
this.transport.messageProvider.add(this.transport.windowMessageProvider)
|
|
141
|
-
}
|
|
142
|
-
if (this.config.transports?.proxyTransport?.enabled) {
|
|
143
|
-
this.transport.proxyMessageProvider = new ProxyMessageProvider(this.config.transports.proxyTransport.appPort!)
|
|
144
|
-
this.transport.messageProvider.add(this.transport.proxyMessageProvider)
|
|
145
|
-
}
|
|
146
|
-
if (this.config.transports?.extensionTransport?.enabled) {
|
|
147
|
-
this.transport.extensionMessageProvider = new ExtensionMessageProvider(this.config.transports.extensionTransport.runtime)
|
|
148
|
-
// this.transport.extensionMessageProvider.register()
|
|
149
|
-
this.transport.messageProvider.add(this.transport.extensionMessageProvider)
|
|
150
|
-
|
|
151
|
-
// NOTE/REVIEW: see note in mux-message-provider
|
|
152
|
-
//
|
|
153
|
-
// We don't add the extensionMessageProvider here because we don't send requests to it anyways, we seem to
|
|
154
|
-
// send all requests to the WindowMessageProvider anyways. By allowing it, if browser restarts, it will break
|
|
155
|
-
// the entire extension because messageProvider.provider will be undefined. So this is a hack to fix it.
|
|
156
|
-
//
|
|
157
|
-
// this.transport.messageProvider.add(this.transport.extensionMessageProvider)
|
|
158
|
-
}
|
|
159
|
-
if (this.config.transports?.unrealTransport?.enabled) {
|
|
160
|
-
this.transport.unrealMessageProvider = new UnrealMessageProvider(this.config.walletAppURL)
|
|
161
|
-
this.transport.messageProvider.add(this.transport.unrealMessageProvider)
|
|
162
|
-
}
|
|
163
|
-
this.transport.messageProvider.register()
|
|
164
|
-
|
|
165
|
-
// .....
|
|
166
|
-
this.transport.allowProvider = allowProviderMiddleware((request: JsonRpcRequest): boolean => {
|
|
167
|
-
if (request.method === 'sequence_setDefaultNetwork') return true
|
|
168
|
-
|
|
169
|
-
const isConnected = this.isConnected()
|
|
170
|
-
if (!isConnected) {
|
|
171
|
-
throw new Error('Sequence: wallet not connected')
|
|
172
|
-
}
|
|
173
|
-
return isConnected
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// ...
|
|
177
|
-
this.transport.networkProvider = networkProviderMiddleware((request: JsonRpcRequest): number => {
|
|
178
|
-
// return stub chainId of 0 when not connected to any
|
|
179
|
-
if (!this.networks || this.networks.length === 0) return 0
|
|
180
|
-
|
|
181
|
-
// return the default chainId as we're connected
|
|
182
|
-
return findNetworkConfig(this.networks, this.config.defaultNetworkId!)!.chainId
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// Provider proxy to support middleware stack of logging, caching and read-only rpc calls
|
|
186
|
-
this.transport.cachedProvider = new CachedProvider()
|
|
187
|
-
this.transport.cachedProvider.onUpdate(() => {
|
|
188
|
-
if (!this.session) this.session = { providerCache: {} }
|
|
189
|
-
this.session.providerCache = this.transport.cachedProvider!.getCache()
|
|
190
|
-
this.saveSession(this.session)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
// ..
|
|
194
|
-
this.transport.router = new JsonRpcRouter(
|
|
195
|
-
[
|
|
196
|
-
loggingProviderMiddleware,
|
|
197
|
-
this.transport.networkProvider,
|
|
198
|
-
this.transport.allowProvider,
|
|
199
|
-
exceptionProviderMiddleware,
|
|
200
|
-
this.transport.cachedProvider
|
|
201
|
-
],
|
|
202
|
-
this.transport.messageProvider
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
// TODO: Move finding this config to upper in the stack
|
|
206
|
-
this.transport.provider = new Web3Provider(
|
|
207
|
-
this.transport.router,
|
|
208
|
-
findSupportedNetwork(this.config.defaultNetworkId!)?.chainId
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
// NOTE: we don't listen on 'connect' even here as we handle it within connect() method
|
|
212
|
-
// in more synchronous flow.
|
|
213
|
-
|
|
214
|
-
// below will update the wallet session object and persist it. In case the session
|
|
215
|
-
// is undefined, we consider the session to have been removed by the user, so we clear it.
|
|
216
|
-
this.transport.messageProvider.on('open', (openInfo: { session?: WalletSession }) => {
|
|
217
|
-
const { session } = openInfo
|
|
218
|
-
if (!session) {
|
|
219
|
-
if (this.session && this.session.accountAddress) {
|
|
220
|
-
// emit disconnect even if previously we had a session, and now we don't.
|
|
221
|
-
this.transport.messageProvider!.emit('disconnect')
|
|
222
|
-
}
|
|
223
|
-
this.clearSession()
|
|
224
|
-
} else {
|
|
225
|
-
this.useSession(session, true)
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
// below will update the account upon wallet connect/disconnect - aka, login/logout.
|
|
230
|
-
// if an origin is provided, this operation should be performed only on that origin
|
|
231
|
-
// and shouldn't affect the session of the wallet.
|
|
232
|
-
this.transport.messageProvider.on('accountsChanged', (accounts: string[], origin?: string) => {
|
|
233
|
-
if (origin) {
|
|
234
|
-
if (accounts.length > 0) {
|
|
235
|
-
this.useSession({ accountAddress: accounts[0] }, true)
|
|
236
|
-
}
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (!accounts || accounts.length === 0 || accounts[0] === '') {
|
|
241
|
-
this.clearSession()
|
|
242
|
-
} else {
|
|
243
|
-
this.useSession({ accountAddress: accounts[0] }, true)
|
|
244
|
-
}
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
// below will update the networks automatically when the wallet networks change
|
|
248
|
-
this.transport.messageProvider.on('networks', (networks: NetworkConfig[]) => {
|
|
249
|
-
this.useSession({ networks: networks }, true)
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
// below will update the wallet context automatically
|
|
253
|
-
this.transport.messageProvider.on('walletContext', (walletContext: commons.context.VersionedContext) => {
|
|
254
|
-
this.useSession({ walletContext: walletContext }, true)
|
|
255
|
-
})
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
loadSession = async (preferredNetwork?: string | number): Promise<WalletSession | undefined> => {
|
|
259
|
-
const data = await LocalStorage.getInstance().getItem(SESSION_LOCALSTORE_KEY)
|
|
260
|
-
if (!data || data === '') {
|
|
261
|
-
return undefined
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
const session = JSON.parse(data) as WalletSession
|
|
266
|
-
if (session) {
|
|
267
|
-
// Setting preferredNetwork as default network if it's in session.networks
|
|
268
|
-
if (preferredNetwork !== undefined) {
|
|
269
|
-
const preferredNetworkIdNum = typeof preferredNetwork === 'string' ? parseInt(preferredNetwork) : preferredNetwork
|
|
270
|
-
const isPreferredNetwork = (n: NetworkConfig) => n.name === preferredNetwork || n.chainId === preferredNetworkIdNum
|
|
271
|
-
const preferredNetworkInConfig = session.networks?.find(isPreferredNetwork)
|
|
272
|
-
const isAlreadyDefaultChain = preferredNetworkInConfig?.isDefaultChain
|
|
273
|
-
|
|
274
|
-
if (session.networks && preferredNetworkInConfig && !isAlreadyDefaultChain) {
|
|
275
|
-
const updatedNetworks = session.networks.map(n => ({ ...n, isDefaultChain: isPreferredNetwork(n) }))
|
|
276
|
-
session.networks = sortNetworks(updatedNetworks)
|
|
277
|
-
session.providerCache = undefined
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this.useSession(session, true)
|
|
282
|
-
}
|
|
283
|
-
return session
|
|
284
|
-
} catch (err) {
|
|
285
|
-
logger.warn('loadSession failed, unable to parse session payload from storage.')
|
|
286
|
-
return undefined
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
connect = async (options?: ConnectOptions): Promise<ConnectDetails> => {
|
|
291
|
-
if (options && options?.authorizeVersion === undefined) {
|
|
292
|
-
// Populate default authorize version if not provided
|
|
293
|
-
options.authorizeVersion = 2
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (options?.refresh === true) {
|
|
297
|
-
this.disconnect()
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (
|
|
301
|
-
this.isConnected() &&
|
|
302
|
-
(await this.isSiteConnected(options?.origin)) &&
|
|
303
|
-
!!this.session &&
|
|
304
|
-
!options?.authorize &&
|
|
305
|
-
!options?.askForEmail
|
|
306
|
-
) {
|
|
307
|
-
return {
|
|
308
|
-
connected: true,
|
|
309
|
-
session: this.session,
|
|
310
|
-
chainId: ethers.utils.hexlify(await this.getChainId())
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (options) {
|
|
315
|
-
if (options.authorize) {
|
|
316
|
-
if (!options.app) {
|
|
317
|
-
throw new Error(`connecting with 'authorize' option also requires 'app' to be set`)
|
|
318
|
-
}
|
|
319
|
-
if (options.authorizeVersion === undefined) {
|
|
320
|
-
options.authorizeVersion = 2
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
await this.openWallet(undefined, { type: 'connect', options })
|
|
326
|
-
|
|
327
|
-
const connectDetails = await this.transport.messageProvider!.waitUntilConnected().catch((error): ConnectDetails => {
|
|
328
|
-
if (error instanceof Error) {
|
|
329
|
-
return { connected: false, error: error.message }
|
|
330
|
-
} else {
|
|
331
|
-
return { connected: false, error: JSON.stringify(error) }
|
|
332
|
-
}
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
if (connectDetails.connected) {
|
|
336
|
-
if (!!connectDetails.session) {
|
|
337
|
-
this.useSession(connectDetails.session, true)
|
|
338
|
-
|
|
339
|
-
this.addConnectedSite(options?.origin)
|
|
340
|
-
} else {
|
|
341
|
-
throw new Error('impossible state, connect response is missing session')
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return connectDetails
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
async addConnectedSite(origin: string | undefined) {
|
|
349
|
-
origin = origin || window.location.origin
|
|
350
|
-
|
|
351
|
-
const connectedSites = await this.connectedSites.get()
|
|
352
|
-
|
|
353
|
-
if (connectedSites) {
|
|
354
|
-
if (connectedSites.includes(origin)) {
|
|
355
|
-
return
|
|
356
|
-
}
|
|
357
|
-
this.connectedSites.set([...connectedSites, origin])
|
|
358
|
-
} else {
|
|
359
|
-
this.connectedSites.set([origin])
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
async removeConnectedSite(origin: string) {
|
|
364
|
-
const authorized = await this.connectedSites.get()
|
|
365
|
-
|
|
366
|
-
if (authorized) {
|
|
367
|
-
this.connectedSites.set(authorized.filter(domain => domain !== origin))
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
getConnectedSites() {
|
|
372
|
-
return this.connectedSites.get()
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
async isSiteConnected(origin: string | undefined): Promise<boolean> {
|
|
376
|
-
const authorized = await this.connectedSites.get()
|
|
377
|
-
|
|
378
|
-
return !!authorized && authorized.includes(origin || window.location.origin)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
authorize = async (options?: ConnectOptions): Promise<ConnectDetails> => {
|
|
382
|
-
return this.connect({ ...options, authorize: true })
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
disconnect(): Promise<void> {
|
|
386
|
-
if (this.isOpened()) {
|
|
387
|
-
this.closeWallet()
|
|
388
|
-
}
|
|
389
|
-
return this.clearSession()
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// TODO: add switchNetwork(network: string | number) which will call wallet_switchEthereumChain
|
|
393
|
-
// and on successful response, will update the provider info here, etc.
|
|
394
|
-
|
|
395
|
-
getProviderConfig(): ProviderConfig {
|
|
396
|
-
return this.config
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
isOpened(): boolean {
|
|
400
|
-
return this.transport.messageProvider!.isOpened()
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
isConnected(): boolean {
|
|
404
|
-
return (
|
|
405
|
-
this.session !== undefined &&
|
|
406
|
-
this.session.networks !== undefined &&
|
|
407
|
-
this.session.networks.length > 0 &&
|
|
408
|
-
this.networks !== undefined &&
|
|
409
|
-
this.networks.length > 0 &&
|
|
410
|
-
!!this.session.accountAddress &&
|
|
411
|
-
this.session.accountAddress.startsWith('0x')
|
|
412
|
-
)
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
getSession = (): WalletSession | undefined => {
|
|
416
|
-
if (!this.isConnected()) {
|
|
417
|
-
return undefined
|
|
418
|
-
}
|
|
419
|
-
return this.session
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
getAddress = async (): Promise<string> => {
|
|
423
|
-
if (!this.isConnected()) {
|
|
424
|
-
throw new Error('connect first')
|
|
425
|
-
}
|
|
426
|
-
const session = this.getSession()
|
|
427
|
-
return session!.accountAddress!
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
getNetworks = async (chainId?: ChainIdLike): Promise<NetworkConfig[]> => {
|
|
431
|
-
if (!this.isConnected() || !this.networks) {
|
|
432
|
-
throw new Error('connect first')
|
|
433
|
-
}
|
|
434
|
-
if (chainId) {
|
|
435
|
-
// filter list to just the specific chain requested
|
|
436
|
-
const network = findNetworkConfig(this.networks, chainId)
|
|
437
|
-
return network ? [network] : []
|
|
438
|
-
}
|
|
439
|
-
return this.networks
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// getChainId returns the default chain id
|
|
443
|
-
getChainId = async (): Promise<number> => {
|
|
444
|
-
if (!this.networks || this.networks.length < 1) {
|
|
445
|
-
throw new Error('networks have not been set by session. connect first.')
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
const network = findNetworkConfig(this.networks, this.config.defaultNetworkId!)
|
|
449
|
-
|
|
450
|
-
if (!network) {
|
|
451
|
-
throw new Error('networks must have a default chain specified')
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return network.chainId
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
openWallet = async (path?: string, intent?: OpenWalletIntent, networkId?: string | number): Promise<boolean> => {
|
|
458
|
-
if (intent?.type !== 'connect' && !this.isConnected()) {
|
|
459
|
-
throw new Error('connect first')
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
let currentNetworkId
|
|
463
|
-
|
|
464
|
-
if (!this.networks || this.networks.length < 1) {
|
|
465
|
-
currentNetworkId = this.config.defaultNetworkId
|
|
466
|
-
} else {
|
|
467
|
-
currentNetworkId = await this.getChainId()
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
this.transport.messageProvider!.openWallet(path, intent, networkId || currentNetworkId)
|
|
471
|
-
await this.transport.messageProvider!.waitUntilOpened()
|
|
472
|
-
|
|
473
|
-
return true
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
closeWallet = (): void => {
|
|
477
|
-
this.transport.messageProvider!.closeWallet()
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
getProvider(chainId?: ChainIdLike): Web3Provider | undefined {
|
|
481
|
-
// return the top-level provider message transport when chainId is unspecified
|
|
482
|
-
// and user has not logged in
|
|
483
|
-
if (!this.isConnected()) {
|
|
484
|
-
if (chainId) {
|
|
485
|
-
throw new Error(`session is empty. connect and try again.`)
|
|
486
|
-
} else {
|
|
487
|
-
return this.transport.provider
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
let network: NetworkConfig | undefined = findNetworkConfig(this.networks, this.config.defaultNetworkId!)!
|
|
492
|
-
if (chainId) {
|
|
493
|
-
network = findNetworkConfig(this.networks, chainId)
|
|
494
|
-
if (!network) {
|
|
495
|
-
throw new Error(`network ${chainId} is not in the network list`)
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// return memoized network provider
|
|
500
|
-
if (this.providers[network.chainId]) {
|
|
501
|
-
return this.providers[network.chainId]
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// builder web3 provider stack
|
|
505
|
-
let provider: Web3Provider
|
|
506
|
-
|
|
507
|
-
// network.provider may be set by the ProviderConfig override
|
|
508
|
-
const rpcProvider = new providers.JsonRpcProvider(getDefaultConnectionInfo(network.rpcUrl), network.chainId)
|
|
509
|
-
|
|
510
|
-
if (network.isDefaultChain) {
|
|
511
|
-
// communicating with defaultChain will prioritize the wallet message transport
|
|
512
|
-
const router = new JsonRpcRouter(
|
|
513
|
-
[
|
|
514
|
-
loggingProviderMiddleware,
|
|
515
|
-
exceptionProviderMiddleware,
|
|
516
|
-
new EagerProvider({ accountAddress: this.session!.accountAddress, walletContext: this.session!.walletContext }),
|
|
517
|
-
new SigningProvider(this.transport!.provider!),
|
|
518
|
-
this.transport.cachedProvider!
|
|
519
|
-
],
|
|
520
|
-
new JsonRpcSender(rpcProvider)
|
|
521
|
-
)
|
|
522
|
-
|
|
523
|
-
provider = new Web3Provider(router, network.chainId)
|
|
524
|
-
} else {
|
|
525
|
-
// communicating with another chain will bind to that network, but will forward
|
|
526
|
-
// any signing-related requests to the wallet message transport
|
|
527
|
-
const router = new JsonRpcRouter(
|
|
528
|
-
[
|
|
529
|
-
loggingProviderMiddleware,
|
|
530
|
-
exceptionProviderMiddleware,
|
|
531
|
-
new EagerProvider({
|
|
532
|
-
accountAddress: this.session!.accountAddress,
|
|
533
|
-
walletContext: this.session!.walletContext,
|
|
534
|
-
chainId: network.chainId
|
|
535
|
-
}),
|
|
536
|
-
new SigningProvider(this.transport.provider!),
|
|
537
|
-
new CachedProvider({ defaultChainId: network.chainId })
|
|
538
|
-
],
|
|
539
|
-
new JsonRpcSender(rpcProvider)
|
|
540
|
-
)
|
|
541
|
-
|
|
542
|
-
provider = new Web3Provider(router, network.chainId)
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
this.providers[network.chainId] = provider
|
|
546
|
-
return provider
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
getAllProviders(): { [chainId: number]: Web3Provider } {
|
|
550
|
-
return this.providers
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
getSigner(chainId?: ChainIdLike): Web3Signer {
|
|
554
|
-
return this.getProvider(chainId)!.getSigner()
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
getWalletConfig(chainId?: ChainIdLike): Promise<commons.config.Config> {
|
|
558
|
-
return this.getSigner().getWalletConfig(chainId)
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
getWalletState(chainId?: ChainIdLike): Promise<AccountStatus> {
|
|
562
|
-
return this.getSigner().getWalletState(chainId)
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
getWalletContext(): Promise<commons.context.VersionedContext> {
|
|
566
|
-
return this.getSigner().getWalletContext()
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
isDeployed(chainId?: ChainIdLike): Promise<boolean> {
|
|
570
|
-
return this.getSigner(chainId).isDeployed()
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
on<K extends keyof ProviderEventTypes>(event: K, fn: ProviderEventTypes[K]) {
|
|
574
|
-
this.transport.messageProvider!.on(event, fn)
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
once<K extends keyof ProviderEventTypes>(event: K, fn: ProviderEventTypes[K]) {
|
|
578
|
-
this.transport.messageProvider!.once(event, fn)
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
unregister = () => {
|
|
582
|
-
this.disconnect()
|
|
583
|
-
this.transport.messageProvider?.unregister()
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
private saveSession = async (session: WalletSession) => {
|
|
587
|
-
logger.debug('wallet provider: saving session')
|
|
588
|
-
const data = JSON.stringify(session)
|
|
589
|
-
await LocalStorage.getInstance().setItem(SESSION_LOCALSTORE_KEY, data)
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
private useSession = async (session: WalletSession, autoSave: boolean = true) => {
|
|
593
|
-
if (!this.session) this.session = {}
|
|
594
|
-
|
|
595
|
-
// setup wallet context
|
|
596
|
-
if (this.config.walletContext) {
|
|
597
|
-
this.session.walletContext = this.config.walletContext
|
|
598
|
-
} else if (session.walletContext) {
|
|
599
|
-
this.session.walletContext = session.walletContext
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
// setup account
|
|
603
|
-
if (session.accountAddress) {
|
|
604
|
-
this.useAccountAddress(session.accountAddress)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// setup networks
|
|
608
|
-
if (session.networks) {
|
|
609
|
-
this.useNetworks(session.networks)
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// setup provider cache
|
|
613
|
-
if (session.providerCache) {
|
|
614
|
-
this.transport.cachedProvider!.setCache(session.providerCache)
|
|
615
|
-
} else {
|
|
616
|
-
this.transport.cachedProvider!.clearCache()
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// persist
|
|
620
|
-
if (autoSave) {
|
|
621
|
-
this.saveSession(this.session)
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
private useAccountAddress(accountAddress: string) {
|
|
626
|
-
if (!this.session) this.session = {}
|
|
627
|
-
this.session.accountAddress = ethers.utils.getAddress(accountAddress)
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
private useNetworks(networks: NetworkConfig[]) {
|
|
631
|
-
// set networks in the session
|
|
632
|
-
if (!this.session) this.session = {}
|
|
633
|
-
|
|
634
|
-
// set networks on session object
|
|
635
|
-
this.session.networks = networks
|
|
636
|
-
|
|
637
|
-
// short-circuit if setting empty network list (aka logged out state)
|
|
638
|
-
if (!this.session.networks || this.session.networks.length === 0) {
|
|
639
|
-
return
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// check if any custom network settings, otherwise return early
|
|
643
|
-
if (!this.config.networks && !this.config.networkRpcUrl) {
|
|
644
|
-
this.networks = networks
|
|
645
|
-
return
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// init networks
|
|
649
|
-
this.networks = networks
|
|
650
|
-
|
|
651
|
-
// combine custom network config with networks in the session
|
|
652
|
-
if (this.config.networks) {
|
|
653
|
-
this.networks = networks.map(n => ({ ...n })) // copy
|
|
654
|
-
this.config.networks.forEach(n => {
|
|
655
|
-
const network = findNetworkConfig(this.networks, n.chainId || n.name!)
|
|
656
|
-
if (!network) return
|
|
657
|
-
updateNetworkConfig(n, network)
|
|
658
|
-
})
|
|
659
|
-
ensureValidNetworks(this.networks, true)
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// an extra override for convenience
|
|
663
|
-
if (this.config.networkRpcUrl) {
|
|
664
|
-
const network = this.networks.find(network => network.isDefaultChain)
|
|
665
|
-
if (network) {
|
|
666
|
-
network.rpcUrl = this.config.networkRpcUrl
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
private async clearSession(): Promise<void> {
|
|
672
|
-
logger.debug('wallet provider: clearing session')
|
|
673
|
-
await LocalStorage.getInstance().removeItem(SESSION_LOCALSTORE_KEY)
|
|
674
|
-
this.session = undefined
|
|
675
|
-
this.networks = []
|
|
676
|
-
this.providers = {}
|
|
677
|
-
this.transport.cachedProvider?.clearCache()
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
export interface ProviderConfig {
|
|
682
|
-
// The local storage dependency for the wallet provider, defaults to window.localStorage.
|
|
683
|
-
// For example, this option should be used when using React Native since window.localStorage is not available.
|
|
684
|
-
localStorage?: ItemStore
|
|
685
|
-
|
|
686
|
-
// Sequence Wallet App URL, default: https://sequence.app
|
|
687
|
-
walletAppURL: string
|
|
688
|
-
|
|
689
|
-
// Sequence Wallet Session URL, default: https://session.sequence.app
|
|
690
|
-
// walletSessionURL: string
|
|
691
|
-
|
|
692
|
-
// networks is a configuration list of networks used by the wallet. This list
|
|
693
|
-
// is combined with the network list supplied from the wallet upon login,
|
|
694
|
-
// and settings here take precedence such as overriding a relayer setting, or rpcUrl.
|
|
695
|
-
networks?: Partial<NetworkConfig>[]
|
|
696
|
-
|
|
697
|
-
// networkRpcUrl will set the provider rpcUrl of the default network
|
|
698
|
-
networkRpcUrl?: string
|
|
699
|
-
|
|
700
|
-
// defaultNetworkId is the primary network of a dapp and the default network a
|
|
701
|
-
// provider will communicate. Note: this setting is also configurable from the
|
|
702
|
-
// Wallet constructor's first argument.
|
|
703
|
-
defaultNetworkId?: string | number
|
|
704
|
-
|
|
705
|
-
// transports for dapp to wallet jron-rpc communication
|
|
706
|
-
transports?: {
|
|
707
|
-
// WindowMessage transport (optional)
|
|
708
|
-
windowTransport?: {
|
|
709
|
-
enabled: boolean
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
// ProxyMessage transport (optional)
|
|
713
|
-
proxyTransport?: {
|
|
714
|
-
enabled: boolean
|
|
715
|
-
appPort?: ProxyMessageChannelPort
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// Extension transport (optional)
|
|
719
|
-
extensionTransport?: {
|
|
720
|
-
enabled: boolean
|
|
721
|
-
runtime: Runtime.Static
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// Unreal Engine transport (optional)
|
|
725
|
-
unrealTransport?: {
|
|
726
|
-
enabled: boolean
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Sequence Wallet Modules Context override. By default (and recommended), the
|
|
731
|
-
// WalletContext used the one returned by the wallet app upon login.
|
|
732
|
-
//
|
|
733
|
-
// NOTE: do not use this option unless you know what you're doing
|
|
734
|
-
walletContext?: commons.context.VersionedContext
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
export const DefaultProviderConfig: ProviderConfig = {
|
|
738
|
-
walletAppURL: 'https://sequence.app',
|
|
739
|
-
|
|
740
|
-
// walletSessionURL: 'https://session.sequence.app',
|
|
741
|
-
|
|
742
|
-
transports: {
|
|
743
|
-
windowTransport: { enabled: true },
|
|
744
|
-
proxyTransport: { enabled: false }
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
let walletInstance: Wallet | undefined
|
|
749
|
-
|
|
750
|
-
export const initWallet = async (network?: string | number, config?: Partial<ProviderConfig>) => {
|
|
751
|
-
if (walletInstance) {
|
|
752
|
-
return walletInstance
|
|
753
|
-
}
|
|
754
|
-
walletInstance = new Wallet(network, config)
|
|
755
|
-
await walletInstance.loadSession(network)
|
|
756
|
-
return walletInstance
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
export const unregisterWallet = () => {
|
|
760
|
-
if (!walletInstance) return
|
|
761
|
-
walletInstance.closeWallet()
|
|
762
|
-
walletInstance.unregister()
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
export const getWallet = () => {
|
|
766
|
-
if (!walletInstance) {
|
|
767
|
-
throw new Error('Wallet has not been initialized, call sequence.initWallet(network, config) first.')
|
|
768
|
-
}
|
|
769
|
-
return walletInstance
|
|
770
|
-
}
|