@0xsequence/dapp-client 3.0.0-beta.9 → 3.0.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.
@@ -5,6 +5,7 @@ import {
5
5
  SignMessagePayload,
6
6
  SignTypedDataPayload,
7
7
  GuardConfig,
8
+ ETHAuthProof,
8
9
  SendWalletTransactionPayload,
9
10
  ModifyExplicitSessionPayload,
10
11
  CreateNewSessionPayload,
@@ -81,6 +82,10 @@ export interface SequenceStorage {
81
82
  getSessionlessConnection(): Promise<SessionlessConnectionData | null>
82
83
  clearSessionlessConnection(): Promise<void>
83
84
 
85
+ saveEthAuthProof(proof: ETHAuthProof): Promise<void>
86
+ getEthAuthProof(): Promise<ETHAuthProof | null>
87
+ clearEthAuthProof(): Promise<void>
88
+
84
89
  saveSessionlessConnectionSnapshot?(sessionData: SessionlessConnectionData): Promise<void>
85
90
  getSessionlessConnectionSnapshot?(): Promise<SessionlessConnectionData | null>
86
91
  clearSessionlessConnectionSnapshot?(): Promise<void>
@@ -94,6 +99,7 @@ const STORE_NAME = 'userKeys'
94
99
  const IMPLICIT_SESSIONS_IDB_KEY = 'SequenceImplicitSession'
95
100
  const EXPLICIT_SESSIONS_IDB_KEY = 'SequenceExplicitSession'
96
101
  const SESSIONLESS_CONNECTION_IDB_KEY = 'SequenceSessionlessConnection'
102
+ const ETH_AUTH_PROOF_IDB_KEY = 'SequenceEthAuthProof'
97
103
  const SESSIONLESS_CONNECTION_SNAPSHOT_IDB_KEY = 'SequenceSessionlessConnectionSnapshot'
98
104
 
99
105
  const PENDING_REDIRECT_REQUEST_KEY = 'SequencePendingRedirect'
@@ -305,6 +311,15 @@ export class WebStorage implements SequenceStorage {
305
311
  }
306
312
  }
307
313
 
314
+ async saveEthAuthProof(proof: ETHAuthProof): Promise<void> {
315
+ try {
316
+ await this.setIDBItem(ETH_AUTH_PROOF_IDB_KEY, proof)
317
+ } catch (error) {
318
+ console.error('Failed to save ETHAuth proof:', error)
319
+ throw error
320
+ }
321
+ }
322
+
308
323
  async getSessionlessConnection(): Promise<SessionlessConnectionData | null> {
309
324
  try {
310
325
  return (await this.getIDBItem<SessionlessConnectionData>(SESSIONLESS_CONNECTION_IDB_KEY)) ?? null
@@ -314,6 +329,15 @@ export class WebStorage implements SequenceStorage {
314
329
  }
315
330
  }
316
331
 
332
+ async getEthAuthProof(): Promise<ETHAuthProof | null> {
333
+ try {
334
+ return (await this.getIDBItem<ETHAuthProof>(ETH_AUTH_PROOF_IDB_KEY)) ?? null
335
+ } catch (error) {
336
+ console.error('Failed to retrieve ETHAuth proof:', error)
337
+ return null
338
+ }
339
+ }
340
+
317
341
  async clearSessionlessConnection(): Promise<void> {
318
342
  try {
319
343
  await this.deleteIDBItem(SESSIONLESS_CONNECTION_IDB_KEY)
@@ -323,6 +347,15 @@ export class WebStorage implements SequenceStorage {
323
347
  }
324
348
  }
325
349
 
350
+ async clearEthAuthProof(): Promise<void> {
351
+ try {
352
+ await this.deleteIDBItem(ETH_AUTH_PROOF_IDB_KEY)
353
+ } catch (error) {
354
+ console.error('Failed to clear ETHAuth proof:', error)
355
+ throw error
356
+ }
357
+ }
358
+
326
359
  async saveSessionlessConnectionSnapshot(sessionData: SessionlessConnectionData): Promise<void> {
327
360
  try {
328
361
  await this.setIDBItem(SESSIONLESS_CONNECTION_SNAPSHOT_IDB_KEY, sessionData)
@@ -363,6 +396,7 @@ export class WebStorage implements SequenceStorage {
363
396
  await this.clearExplicitSessions()
364
397
  await this.clearImplicitSession()
365
398
  await this.clearSessionlessConnection()
399
+ await this.clearEthAuthProof()
366
400
  await this.clearSessionlessConnectionSnapshot()
367
401
  } catch (error) {
368
402
  console.error('Failed to clear all data:', error)
@@ -0,0 +1,207 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ import { DappClient } from '../src/DappClient.js'
4
+ import { DappTransport } from '../src/DappTransport.js'
5
+ import { RequestActionType, TransportMode } from '../src/types/index.js'
6
+ import { WebStorage } from '../src/utils/storage.js'
7
+
8
+ describe('ETHAuth proof persistence', () => {
9
+ afterEach(() => {
10
+ vi.restoreAllMocks()
11
+ vi.unstubAllGlobals()
12
+ })
13
+
14
+ const createSequenceStorageMock = () => ({
15
+ setPendingRedirectRequest: vi.fn().mockResolvedValue(undefined),
16
+ isRedirectRequestPending: vi.fn().mockResolvedValue(false),
17
+ saveTempSessionPk: vi.fn().mockResolvedValue(undefined),
18
+ getAndClearTempSessionPk: vi.fn().mockResolvedValue(null),
19
+ savePendingRequest: vi.fn().mockResolvedValue(undefined),
20
+ getAndClearPendingRequest: vi.fn().mockResolvedValue(null),
21
+ peekPendingRequest: vi.fn().mockResolvedValue(null),
22
+ saveExplicitSession: vi.fn().mockResolvedValue(undefined),
23
+ getExplicitSessions: vi.fn().mockResolvedValue([]),
24
+ clearExplicitSessions: vi.fn().mockResolvedValue(undefined),
25
+ saveImplicitSession: vi.fn().mockResolvedValue(undefined),
26
+ getImplicitSession: vi.fn().mockResolvedValue(null),
27
+ clearImplicitSession: vi.fn().mockResolvedValue(undefined),
28
+ saveSessionlessConnection: vi.fn().mockResolvedValue(undefined),
29
+ getSessionlessConnection: vi.fn().mockResolvedValue(null),
30
+ clearSessionlessConnection: vi.fn().mockResolvedValue(undefined),
31
+ saveEthAuthProof: vi.fn().mockResolvedValue(undefined),
32
+ getEthAuthProof: vi.fn().mockResolvedValue(null),
33
+ clearEthAuthProof: vi.fn().mockResolvedValue(undefined),
34
+ clearAllData: vi.fn().mockResolvedValue(undefined),
35
+ })
36
+
37
+ it('persists ETHAuth proof when connect requests ethAuth in redirect mode', async () => {
38
+ const fetchMock = vi.fn()
39
+ vi.stubGlobal('fetch', fetchMock)
40
+ vi.stubGlobal('window', { fetch: fetchMock })
41
+
42
+ const ethAuthProof = {
43
+ typedData: {
44
+ domain: {},
45
+ types: {},
46
+ message: {},
47
+ },
48
+ ewtString: 'proof-string',
49
+ }
50
+
51
+ const sequenceStorage = createSequenceStorageMock()
52
+ const sendRequestMock = vi.spyOn(DappTransport.prototype, 'sendRequest').mockResolvedValue({
53
+ walletAddress: '0x1111111111111111111111111111111111111111',
54
+ ethAuthProof,
55
+ })
56
+
57
+ const client = new DappClient('https://wallet.example', 'https://dapp.example', 'test-project-access-key', {
58
+ sequenceStorage,
59
+ transportMode: TransportMode.REDIRECT,
60
+ canUseIndexedDb: false,
61
+ redirectActionHandler: vi.fn(),
62
+ })
63
+
64
+ await client.connect(1, undefined, {
65
+ ethAuth: {
66
+ app: 'app-name',
67
+ },
68
+ })
69
+
70
+ expect(sendRequestMock).toHaveBeenCalledWith(
71
+ RequestActionType.CREATE_NEW_SESSION,
72
+ 'https://dapp.example',
73
+ expect.objectContaining({
74
+ ethAuth: {
75
+ app: 'app-name',
76
+ },
77
+ }),
78
+ expect.any(Object),
79
+ )
80
+ expect(sequenceStorage.saveEthAuthProof).toHaveBeenCalledWith(ethAuthProof)
81
+ })
82
+
83
+ it('persists ETHAuth proof when connect requests ethAuth in popup mode', async () => {
84
+ const fetchMock = vi.fn()
85
+ vi.stubGlobal('fetch', fetchMock)
86
+ vi.stubGlobal('window', { fetch: fetchMock })
87
+ vi.stubGlobal('document', {})
88
+
89
+ const ethAuthProof = {
90
+ typedData: {
91
+ domain: {},
92
+ types: {},
93
+ message: {},
94
+ },
95
+ ewtString: 'proof-string',
96
+ }
97
+
98
+ const sequenceStorage = createSequenceStorageMock()
99
+ const sendRequestMock = vi.spyOn(DappTransport.prototype, 'sendRequest').mockResolvedValue({
100
+ walletAddress: '0x1111111111111111111111111111111111111111',
101
+ ethAuthProof,
102
+ })
103
+
104
+ const client = new DappClient('https://wallet.example', 'https://dapp.example', 'test-project-access-key', {
105
+ sequenceStorage,
106
+ transportMode: TransportMode.POPUP,
107
+ canUseIndexedDb: false,
108
+ })
109
+
110
+ await client.connect(1, undefined, {
111
+ ethAuth: {
112
+ app: 'app-name',
113
+ },
114
+ })
115
+
116
+ expect(sendRequestMock).toHaveBeenCalledWith(
117
+ RequestActionType.CREATE_NEW_SESSION,
118
+ 'https://dapp.example',
119
+ expect.objectContaining({
120
+ ethAuth: {
121
+ app: 'app-name',
122
+ },
123
+ }),
124
+ expect.any(Object),
125
+ )
126
+ expect(sequenceStorage.saveEthAuthProof).toHaveBeenCalledWith(ethAuthProof)
127
+ })
128
+
129
+ it('does not persist ETHAuth proof when connect does not request ethAuth', async () => {
130
+ const fetchMock = vi.fn()
131
+ vi.stubGlobal('fetch', fetchMock)
132
+ vi.stubGlobal('window', { fetch: fetchMock })
133
+
134
+ const ethAuthProof = {
135
+ typedData: {
136
+ domain: {},
137
+ types: {},
138
+ message: {},
139
+ },
140
+ ewtString: 'proof-string',
141
+ }
142
+
143
+ const sequenceStorage = createSequenceStorageMock()
144
+ const sendRequestMock = vi.spyOn(DappTransport.prototype, 'sendRequest').mockResolvedValue({
145
+ walletAddress: '0x1111111111111111111111111111111111111111',
146
+ ethAuthProof,
147
+ })
148
+
149
+ const client = new DappClient('https://wallet.example', 'https://dapp.example', 'test-project-access-key', {
150
+ sequenceStorage,
151
+ transportMode: TransportMode.REDIRECT,
152
+ canUseIndexedDb: false,
153
+ redirectActionHandler: vi.fn(),
154
+ })
155
+
156
+ await client.connect(1)
157
+
158
+ expect(sendRequestMock).toHaveBeenCalledWith(
159
+ RequestActionType.CREATE_NEW_SESSION,
160
+ 'https://dapp.example',
161
+ expect.not.objectContaining({
162
+ ethAuth: expect.anything(),
163
+ }),
164
+ expect.any(Object),
165
+ )
166
+ expect(sequenceStorage.saveEthAuthProof).not.toHaveBeenCalled()
167
+ })
168
+
169
+ it('clears ETHAuth proof on disconnect', async () => {
170
+ const fetchMock = vi.fn()
171
+ vi.stubGlobal('fetch', fetchMock)
172
+ vi.stubGlobal('window', { fetch: fetchMock })
173
+
174
+ const ethAuthProof = {
175
+ typedData: {
176
+ domain: {},
177
+ types: {},
178
+ message: {},
179
+ },
180
+ ewtString: 'proof-string',
181
+ }
182
+
183
+ vi.spyOn(DappTransport.prototype, 'sendRequest').mockResolvedValue({
184
+ walletAddress: '0x1111111111111111111111111111111111111111',
185
+ ethAuthProof,
186
+ })
187
+
188
+ const client = new DappClient('https://wallet.example', 'https://dapp.example', 'test-project-access-key', {
189
+ sequenceStorage: new WebStorage(),
190
+ transportMode: TransportMode.REDIRECT,
191
+ canUseIndexedDb: false,
192
+ redirectActionHandler: vi.fn(),
193
+ })
194
+
195
+ await client.connect(1, undefined, {
196
+ ethAuth: {
197
+ app: 'app-name',
198
+ },
199
+ })
200
+
201
+ expect(await client.getEthAuthProof()).toEqual(ethAuthProof)
202
+
203
+ await client.disconnect()
204
+
205
+ expect(await client.getEthAuthProof()).toBeNull()
206
+ })
207
+ })
File without changes