@0xsequence/provider 0.38.2 → 0.39.2

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.
@@ -22,7 +22,7 @@ export class WindowMessageHandler extends BaseWalletTransport {
22
22
  this._init = InitState.NIL
23
23
  }
24
24
 
25
- register(windowHref?: any) {
25
+ async register(windowHref?: any) {
26
26
  const isPopup = parent.window.opener !== null
27
27
  this._isPopup = isPopup
28
28
  if (isPopup !== true) {
@@ -39,7 +39,7 @@ export class WindowMessageHandler extends BaseWalletTransport {
39
39
 
40
40
  // attempt to restore previous session in the case of a redirect or window reload
41
41
  if (!isNewWindowSession) {
42
- session = this.getCachedTransportSession()
42
+ session = await this.getCachedTransportSession()
43
43
  }
44
44
 
45
45
  if (!session) {
@@ -143,7 +143,8 @@ export class WindowMessageHandler extends BaseWalletTransport {
143
143
  this.parentWindow.postMessage(message, '*')
144
144
  } else {
145
145
  // open message transmission
146
- if (this.appOrigin && this.appOrigin.length > 4) { // just above '.com'
146
+ if (this.appOrigin && this.appOrigin.length > 4) {
147
+ // just above '.com'
147
148
  this.parentWindow.postMessage(message, this.appOrigin)
148
149
  } else {
149
150
  logger.error('unable to postMessage as parentOrigin is invalid')
package/src/types.ts CHANGED
@@ -37,6 +37,7 @@ export interface ProviderMessage<T> {
37
37
  type: string // message type
38
38
  data: T // the ethereum json-rpc payload
39
39
  chainId?: number // chain id which the message is intended
40
+ origin?: string // origin of the message
40
41
  }
41
42
 
42
43
  export type ProviderMessageRequest = ProviderMessage<JsonRpcRequest>
@@ -111,7 +112,7 @@ export interface WalletEventTypes {
111
112
  connect: (connectDetails: ConnectDetails) => void
112
113
  disconnect: (error?: ProviderRpcError) => void
113
114
 
114
- accountsChanged: (accounts: string[]) => void
115
+ accountsChanged: (accounts: string[], origin?: string) => void
115
116
  chainChanged: (chainIdHex: string) => void
116
117
 
117
118
  networks: (networks: NetworkConfig[]) => void
package/src/utils.ts CHANGED
@@ -3,9 +3,9 @@ import { WalletContext } from '@0xsequence/network'
3
3
  import { WalletConfig, addressOf, DecodedSignature, isConfigEqual } from '@0xsequence/config'
4
4
  import { packMessageData, encodeMessageDigest, TypedData, encodeTypedDataDigest } from '@0xsequence/utils'
5
5
  import { Web3Provider } from './provider'
6
- import { isValidSignature as _isValidSignature, recoverConfig, Signer, isValidEIP712Signature, isValidEthSignSignature } from '@0xsequence/wallet'
6
+ import { isValidSignature as _isValidSignature, recoverConfig, Signer } from '@0xsequence/wallet'
7
7
 
8
- const eip191prefix = ethers.utils.toUtf8Bytes("\x19Ethereum Signed Message:\n")
8
+ const eip191prefix = ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n')
9
9
 
10
10
  export const messageToBytes = (message: BytesLike): Uint8Array => {
11
11
  if (ethers.utils.isBytes(message) || ethers.utils.isHexString(message)) {
@@ -17,11 +17,7 @@ export const messageToBytes = (message: BytesLike): Uint8Array => {
17
17
 
18
18
  export const prefixEIP191Message = (message: BytesLike): Uint8Array => {
19
19
  const messageBytes = messageToBytes(message)
20
- return ethers.utils.concat([
21
- eip191prefix,
22
- ethers.utils.toUtf8Bytes(String(messageBytes.length)),
23
- messageBytes
24
- ])
20
+ return ethers.utils.concat([eip191prefix, ethers.utils.toUtf8Bytes(String(messageBytes.length)), messageBytes])
25
21
  }
26
22
 
27
23
  export const isValidSignature = async (
@@ -130,6 +126,33 @@ export const isWalletUpToDate = async (signer: Signer, chainId: number): Promise
130
126
  return isDeployed && isUpToDate
131
127
  }
132
128
 
129
+ export interface ItemStore {
130
+ getItem(key: string): Promise<string | null>
131
+ setItem(key: string, value: string): Promise<void>
132
+ removeItem(key: string): Promise<void>
133
+ }
134
+
135
+ export class LocalStorage {
136
+ private static _instance: ItemStore
137
+
138
+ private constructor() {}
139
+
140
+ static getInstance(): ItemStore {
141
+ if (!LocalStorage._instance) {
142
+ LocalStorage._instance = {
143
+ getItem: (key: string) => Promise.resolve(window.localStorage.getItem(key)),
144
+ setItem: (key: string, value: string) => Promise.resolve(window.localStorage.setItem(key, value)),
145
+ removeItem: (key: string) => Promise.resolve(window.localStorage.removeItem(key))
146
+ }
147
+ }
148
+ return this._instance
149
+ }
150
+
151
+ static use(instance: ItemStore) {
152
+ LocalStorage._instance = instance
153
+ }
154
+ }
155
+
133
156
  // window.localstorage helper
134
157
  export class LocalStore<T extends Object = string> {
135
158
  readonly key: string
@@ -138,8 +161,8 @@ export class LocalStore<T extends Object = string> {
138
161
  this.key = key
139
162
  }
140
163
 
141
- get(): T | undefined {
142
- const val = window.localStorage.getItem(this.key)
164
+ async get(): Promise<T | undefined> {
165
+ const val = await LocalStorage.getInstance().getItem(this.key)
143
166
 
144
167
  if (val === null) {
145
168
  return this.def
@@ -155,10 +178,10 @@ export class LocalStore<T extends Object = string> {
155
178
  }
156
179
 
157
180
  set(val: T | undefined) {
158
- val ? window.localStorage.setItem(this.key, JSON.stringify(val)) : window.localStorage.removeItem(this.key)
181
+ val ? LocalStorage.getInstance().setItem(this.key, JSON.stringify(val)) : LocalStorage.getInstance().removeItem(this.key)
159
182
  }
160
183
 
161
184
  del() {
162
- window.localStorage.removeItem(this.key)
185
+ LocalStorage.getInstance().removeItem(this.key)
163
186
  }
164
187
  }
package/src/wallet.ts CHANGED
@@ -1,25 +1,18 @@
1
1
  import {
2
2
  NetworkConfig,
3
3
  WalletContext,
4
- sequenceContext,
5
4
  ChainIdLike,
6
- getChainId,
7
5
  JsonRpcSender,
8
6
  JsonRpcRouter,
9
7
  JsonRpcMiddleware,
10
8
  allowProviderMiddleware,
11
9
  CachedProvider,
12
- PublicProvider,
13
10
  loggingProviderMiddleware,
14
11
  SigningProvider,
15
12
  EagerProvider,
16
13
  exceptionProviderMiddleware,
17
14
  networkProviderMiddleware,
18
- JsonRpcExternalProvider,
19
- JsonRpcHandlerFunc,
20
15
  JsonRpcRequest,
21
- JsonRpcResponse,
22
- JsonRpcResponseCallback,
23
16
  findNetworkConfig,
24
17
  updateNetworkConfig,
25
18
  ensureValidNetworks
@@ -32,7 +25,7 @@ import { MuxMessageProvider, WindowMessageProvider, ProxyMessageProvider, ProxyM
32
25
  import { WalletSession, ProviderEventTypes, ConnectOptions, OpenWalletIntent, ConnectDetails } from './types'
33
26
  import { ethers } from 'ethers'
34
27
  import { ExtensionMessageProvider } from './transports/extension-transport/extension-message-provider'
35
- import { LocalStore } from './utils'
28
+ import { LocalStore, ItemStore, LocalStorage } from './utils'
36
29
  import { WalletUtils } from './utils/index'
37
30
 
38
31
  import { Runtime } from 'webextension-polyfill-ts'
@@ -111,6 +104,10 @@ export class Wallet implements WalletProvider {
111
104
  this.config.defaultNetworkId = 'mainnet'
112
105
  }
113
106
 
107
+ if (config?.localStorage) {
108
+ LocalStorage.use(config.localStorage)
109
+ }
110
+
114
111
  this.transport = {}
115
112
  this.networks = []
116
113
  this.providers = {}
@@ -213,8 +210,17 @@ export class Wallet implements WalletProvider {
213
210
  }
214
211
  })
215
212
 
216
- // below will update the account upon wallet connect/disconnect (aka, login/logout)
217
- this.transport.messageProvider.on('accountsChanged', (accounts: string[]) => {
213
+ // below will update the account upon wallet connect/disconnect - aka, login/logout.
214
+ // if an origin is provided, this operation should be performed only on that origin
215
+ // and shouldn't affect the session of the wallet.
216
+ this.transport.messageProvider.on('accountsChanged', (accounts: string[], origin?: string) => {
217
+ if (origin) {
218
+ if (accounts.length > 0) {
219
+ this.useSession({ accountAddress: accounts[0] }, true)
220
+ }
221
+ return
222
+ }
223
+
218
224
  if (!accounts || accounts.length === 0 || accounts[0] === '') {
219
225
  this.clearSession()
220
226
  } else {
@@ -233,10 +239,11 @@ export class Wallet implements WalletProvider {
233
239
  })
234
240
 
235
241
  // Load existing session from localStorage
236
- const session = this.loadSession()
237
- if (session) {
238
- this.useSession(session, false)
239
- }
242
+ this.loadSession().then(session => {
243
+ if (session) {
244
+ this.useSession(session, false)
245
+ }
246
+ })
240
247
  }
241
248
 
242
249
  connect = async (options?: ConnectOptions): Promise<ConnectDetails> => {
@@ -246,7 +253,7 @@ export class Wallet implements WalletProvider {
246
253
 
247
254
  if (
248
255
  this.isConnected() &&
249
- this.isSiteConnected(options?.origin) &&
256
+ (await this.isSiteConnected(options?.origin)) &&
250
257
  !!this.session &&
251
258
  !options?.authorize &&
252
259
  !options?.askForEmail
@@ -282,10 +289,10 @@ export class Wallet implements WalletProvider {
282
289
  return connectDetails
283
290
  }
284
291
 
285
- addConnectedSite(origin: string | undefined) {
292
+ async addConnectedSite(origin: string | undefined) {
286
293
  origin = origin || window.location.origin
287
294
 
288
- const connectedSites = this.connectedSites.get()
295
+ const connectedSites = await this.connectedSites.get()
289
296
 
290
297
  if (connectedSites) {
291
298
  if (connectedSites.includes(origin)) {
@@ -297,8 +304,8 @@ export class Wallet implements WalletProvider {
297
304
  }
298
305
  }
299
306
 
300
- removeConnectedSite(origin: string) {
301
- const authorized = this.connectedSites.get()
307
+ async removeConnectedSite(origin: string) {
308
+ const authorized = await this.connectedSites.get()
302
309
 
303
310
  if (authorized) {
304
311
  this.connectedSites.set(authorized.filter(domain => domain !== origin))
@@ -309,8 +316,8 @@ export class Wallet implements WalletProvider {
309
316
  return this.connectedSites.get()
310
317
  }
311
318
 
312
- private isSiteConnected(origin: string | undefined): boolean {
313
- const authorized = this.connectedSites.get()
319
+ async isSiteConnected(origin: string | undefined): Promise<boolean> {
320
+ const authorized = await this.connectedSites.get()
314
321
 
315
322
  return !!authorized && authorized.includes(origin || window.location.origin)
316
323
  }
@@ -538,8 +545,8 @@ export class Wallet implements WalletProvider {
538
545
  this.transport.messageProvider!.once(event, fn)
539
546
  }
540
547
 
541
- private loadSession = (): WalletSession | undefined => {
542
- const data = window.localStorage.getItem('@sequence.session')
548
+ private loadSession = async (): Promise<WalletSession | undefined> => {
549
+ const data = await LocalStorage.getInstance().getItem('@sequence.session')
543
550
  if (!data || data === '') {
544
551
  return undefined
545
552
  }
@@ -555,7 +562,7 @@ export class Wallet implements WalletProvider {
555
562
  private saveSession = (session: WalletSession) => {
556
563
  logger.debug('wallet provider: saving session')
557
564
  const data = JSON.stringify(session)
558
- window.localStorage.setItem('@sequence.session', data)
565
+ LocalStorage.getInstance().setItem('@sequence.session', data)
559
566
  }
560
567
 
561
568
  private useSession = async (session: WalletSession, autoSave: boolean = true) => {
@@ -631,7 +638,7 @@ export class Wallet implements WalletProvider {
631
638
 
632
639
  private clearSession(): void {
633
640
  logger.debug('wallet provider: clearing session')
634
- window.localStorage.removeItem('@sequence.session')
641
+ LocalStorage.getInstance().removeItem('@sequence.session')
635
642
  this.session = undefined
636
643
  this.networks = []
637
644
  this.providers = {}
@@ -640,6 +647,10 @@ export class Wallet implements WalletProvider {
640
647
  }
641
648
 
642
649
  export interface ProviderConfig {
650
+ // The local storage dependency for the wallet provider, defaults to window.localStorage.
651
+ // For example, this option should be used when using React Native since window.localStorage is not available.
652
+ localStorage?: ItemStore
653
+
643
654
  // Sequence Wallet App URL, default: https://sequence.app
644
655
  walletAppURL: string
645
656