@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.
@@ -1,6 +1,6 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  import { Network } from '@0xsequence/wallet-primitives';
3
2
  import { Bytes, Hex } from 'ox';
3
+ export { VALUE_FORWARDER_ADDRESS } from './constants.js';
4
4
  /**
5
5
  * Creates a single JSON replacer by chaining multiple replacers.
6
6
  * The first replacer to transform a value wins.
@@ -114,6 +114,28 @@ const uint8ArrayReviver = (key, value) => {
114
114
  };
115
115
  export const jsonRevivers = chainRevivers([mapReviver, bigIntReviver, uint8ArrayReviver]);
116
116
  export const jsonReplacers = chainReplacers([mapReplacer, bigIntReplacer, uint8ArrayReplacer]);
117
+ export const createExplicitSessionConfig = (params) => {
118
+ const nowInSeconds = BigInt(Math.floor(Date.now() / 1000));
119
+ const { days = 0, hours = 0, minutes = 0 } = params.expiresIn;
120
+ const sessionLifetimeSeconds = days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60;
121
+ const deadline = nowInSeconds + BigInt(sessionLifetimeSeconds);
122
+ if (params.permissions.length === 0) {
123
+ throw new Error('createExplicitSessionConfig: At least one permission is required.');
124
+ }
125
+ const nativeTokenSpending = params.nativeTokenSpending;
126
+ const valueLimit = nativeTokenSpending?.valueLimit ?? 0n;
127
+ const nativeTokenReceivers = [...(nativeTokenSpending?.allowedRecipients || [])];
128
+ const nativeTokenSpendingPermissions = nativeTokenReceivers.map((receiver) => ({
129
+ target: receiver,
130
+ rules: [],
131
+ }));
132
+ return {
133
+ chainId: params.chainId,
134
+ valueLimit,
135
+ deadline,
136
+ permissions: [...params.permissions, ...nativeTokenSpendingPermissions],
137
+ };
138
+ };
117
139
  /**
118
140
  * Apply a template to a string.
119
141
  *
@@ -1,5 +1,5 @@
1
1
  import { Address, Hex } from 'ox';
2
- import { LoginMethod, SignMessagePayload, SignTypedDataPayload, GuardConfig, SendWalletTransactionPayload, ModifyExplicitSessionPayload, CreateNewSessionPayload, AddExplicitSessionPayload } from '../types/index.js';
2
+ import { LoginMethod, SignMessagePayload, SignTypedDataPayload, GuardConfig, ETHAuthProof, SendWalletTransactionPayload, ModifyExplicitSessionPayload, CreateNewSessionPayload, AddExplicitSessionPayload } from '../types/index.js';
3
3
  import { Attestation } from '../index.js';
4
4
  export interface ExplicitSessionData {
5
5
  pk: Hex.Hex;
@@ -48,6 +48,9 @@ export interface SequenceStorage {
48
48
  saveSessionlessConnection(sessionData: SessionlessConnectionData): Promise<void>;
49
49
  getSessionlessConnection(): Promise<SessionlessConnectionData | null>;
50
50
  clearSessionlessConnection(): Promise<void>;
51
+ saveEthAuthProof(proof: ETHAuthProof): Promise<void>;
52
+ getEthAuthProof(): Promise<ETHAuthProof | null>;
53
+ clearEthAuthProof(): Promise<void>;
51
54
  saveSessionlessConnectionSnapshot?(sessionData: SessionlessConnectionData): Promise<void>;
52
55
  getSessionlessConnectionSnapshot?(): Promise<SessionlessConnectionData | null>;
53
56
  clearSessionlessConnectionSnapshot?(): Promise<void>;
@@ -73,8 +76,11 @@ export declare class WebStorage implements SequenceStorage {
73
76
  getImplicitSession(): Promise<ImplicitSessionData | null>;
74
77
  clearImplicitSession(): Promise<void>;
75
78
  saveSessionlessConnection(sessionData: SessionlessConnectionData): Promise<void>;
79
+ saveEthAuthProof(proof: ETHAuthProof): Promise<void>;
76
80
  getSessionlessConnection(): Promise<SessionlessConnectionData | null>;
81
+ getEthAuthProof(): Promise<ETHAuthProof | null>;
77
82
  clearSessionlessConnection(): Promise<void>;
83
+ clearEthAuthProof(): Promise<void>;
78
84
  saveSessionlessConnectionSnapshot(sessionData: SessionlessConnectionData): Promise<void>;
79
85
  getSessionlessConnectionSnapshot(): Promise<SessionlessConnectionData | null>;
80
86
  clearSessionlessConnectionSnapshot(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ const STORE_NAME = 'userKeys';
9
9
  const IMPLICIT_SESSIONS_IDB_KEY = 'SequenceImplicitSession';
10
10
  const EXPLICIT_SESSIONS_IDB_KEY = 'SequenceExplicitSession';
11
11
  const SESSIONLESS_CONNECTION_IDB_KEY = 'SequenceSessionlessConnection';
12
+ const ETH_AUTH_PROOF_IDB_KEY = 'SequenceEthAuthProof';
12
13
  const SESSIONLESS_CONNECTION_SNAPSHOT_IDB_KEY = 'SequenceSessionlessConnectionSnapshot';
13
14
  const PENDING_REDIRECT_REQUEST_KEY = 'SequencePendingRedirect';
14
15
  const TEMP_SESSION_PK_KEY = 'SequencePendingTempSessionPk';
@@ -219,6 +220,15 @@ export class WebStorage {
219
220
  throw error;
220
221
  }
221
222
  }
223
+ async saveEthAuthProof(proof) {
224
+ try {
225
+ await this.setIDBItem(ETH_AUTH_PROOF_IDB_KEY, proof);
226
+ }
227
+ catch (error) {
228
+ console.error('Failed to save ETHAuth proof:', error);
229
+ throw error;
230
+ }
231
+ }
222
232
  async getSessionlessConnection() {
223
233
  try {
224
234
  return (await this.getIDBItem(SESSIONLESS_CONNECTION_IDB_KEY)) ?? null;
@@ -228,6 +238,15 @@ export class WebStorage {
228
238
  return null;
229
239
  }
230
240
  }
241
+ async getEthAuthProof() {
242
+ try {
243
+ return (await this.getIDBItem(ETH_AUTH_PROOF_IDB_KEY)) ?? null;
244
+ }
245
+ catch (error) {
246
+ console.error('Failed to retrieve ETHAuth proof:', error);
247
+ return null;
248
+ }
249
+ }
231
250
  async clearSessionlessConnection() {
232
251
  try {
233
252
  await this.deleteIDBItem(SESSIONLESS_CONNECTION_IDB_KEY);
@@ -237,6 +256,15 @@ export class WebStorage {
237
256
  throw error;
238
257
  }
239
258
  }
259
+ async clearEthAuthProof() {
260
+ try {
261
+ await this.deleteIDBItem(ETH_AUTH_PROOF_IDB_KEY);
262
+ }
263
+ catch (error) {
264
+ console.error('Failed to clear ETHAuth proof:', error);
265
+ throw error;
266
+ }
267
+ }
240
268
  async saveSessionlessConnectionSnapshot(sessionData) {
241
269
  try {
242
270
  await this.setIDBItem(SESSIONLESS_CONNECTION_SNAPSHOT_IDB_KEY, sessionData);
@@ -276,6 +304,7 @@ export class WebStorage {
276
304
  await this.clearExplicitSessions();
277
305
  await this.clearImplicitSession();
278
306
  await this.clearSessionlessConnection();
307
+ await this.clearEthAuthProof();
279
308
  await this.clearSessionlessConnectionSnapshot();
280
309
  }
281
310
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xsequence/dapp-client",
3
- "version": "3.0.0-beta.9",
3
+ "version": "3.0.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -14,26 +14,28 @@
14
14
  }
15
15
  },
16
16
  "devDependencies": {
17
- "@types/node": "^25.0.2",
18
- "@vitest/coverage-v8": "^4.0.15",
19
- "dotenv": "^17.2.3",
17
+ "@types/node": "^25.3.0",
18
+ "@vitest/coverage-v8": "^4.0.18",
19
+ "dotenv": "^17.3.1",
20
20
  "fake-indexeddb": "^6.2.5",
21
- "happy-dom": "^20.0.11",
21
+ "happy-dom": "^20.7.0",
22
22
  "typescript": "^5.9.3",
23
- "vitest": "^4.0.15",
24
- "@repo/typescript-config": "^0.0.1-beta.1"
23
+ "vitest": "^4.0.18",
24
+ "@repo/eslint-config": "^0.0.1",
25
+ "@repo/typescript-config": "^0.0.1"
25
26
  },
26
27
  "dependencies": {
27
28
  "ox": "^0.9.17",
28
- "@0xsequence/guard": "^3.0.0-beta.9",
29
- "@0xsequence/wallet-core": "^3.0.0-beta.9",
30
- "@0xsequence/wallet-primitives": "^3.0.0-beta.9",
31
- "@0xsequence/relayer": "^3.0.0-beta.9"
29
+ "@0xsequence/guard": "^3.0.1",
30
+ "@0xsequence/wallet-core": "^3.0.1",
31
+ "@0xsequence/wallet-primitives": "^3.0.1",
32
+ "@0xsequence/relayer": "^3.0.1"
32
33
  },
33
34
  "scripts": {
34
35
  "build": "tsc",
35
36
  "dev": "tsc --watch",
36
37
  "typecheck": "tsc --noEmit",
37
- "clean": "rimraf dist"
38
+ "clean": "rimraf dist",
39
+ "lint": "eslint . --max-warnings 0"
38
40
  }
39
41
  }
@@ -37,12 +37,14 @@ import {
37
37
  TransportMode,
38
38
  GuardConfig,
39
39
  CreateNewSessionPayload,
40
+ EthAuthSettings,
40
41
  ModifyExplicitSessionPayload,
41
42
  SessionResponse,
42
43
  AddExplicitSessionPayload,
43
44
  FeeOption,
44
45
  OperationFailedStatus,
45
46
  OperationStatus,
47
+ ETHAuthProof,
46
48
  } from './types/index.js'
47
49
  import { CACHE_DB_NAME, VALUE_FORWARDER_ADDRESS } from './utils/constants.js'
48
50
  import { ExplicitSession, ImplicitSession, ExplicitSessionConfig } from './index.js'
@@ -84,6 +86,11 @@ export class ChainSessionManager {
84
86
  public loginMethod: LoginMethod | null = null
85
87
  public userEmail: string | null = null
86
88
  private guard?: GuardConfig
89
+ private lastSignedCallCache?: {
90
+ fingerprint: string
91
+ signedCall: { to: Address.Address; data: Hex.Hex }
92
+ createdAtMs: number
93
+ }
87
94
 
88
95
  /**
89
96
  * @param chainId The ID of the chain this manager is responsible for.
@@ -151,11 +158,11 @@ export class ChainSessionManager {
151
158
  listener: ChainSessionManagerEventMap[K],
152
159
  ): () => void {
153
160
  if (!this.eventListeners[event]) {
154
- this.eventListeners[event] = new Set() as any
161
+ this.eventListeners[event] = new Set<ChainSessionManagerEventMap[K]>()
155
162
  }
156
- ;(this.eventListeners[event] as any).add(listener)
163
+ this.eventListeners[event].add(listener)
157
164
  return () => {
158
- ;(this.eventListeners[event] as any)?.delete(listener)
165
+ this.eventListeners[event]?.delete(listener)
159
166
  }
160
167
  }
161
168
 
@@ -280,6 +287,7 @@ export class ChainSessionManager {
280
287
  preferredLoginMethod?: LoginMethod
281
288
  email?: string
282
289
  includeImplicitSession?: boolean
290
+ ethAuth?: EthAuthSettings
283
291
  } = {},
284
292
  ): Promise<void> {
285
293
  if (this.isInitialized) {
@@ -306,6 +314,7 @@ export class ChainSessionManager {
306
314
  origin,
307
315
  session: completeSession as ExplicitSession | undefined,
308
316
  includeImplicitSession: options.includeImplicitSession ?? false,
317
+ ethAuth: options.ethAuth,
309
318
  preferredLoginMethod: options.preferredLoginMethod,
310
319
  email: options.preferredLoginMethod === 'email' ? options.email : undefined,
311
320
  }
@@ -372,6 +381,10 @@ export class ChainSessionManager {
372
381
  this.guard = guard
373
382
  }
374
383
 
384
+ if (payload.ethAuth) {
385
+ await this._saveEthAuthProofIfProvided(connectResponse.ethAuthProof)
386
+ }
387
+
375
388
  if (this.transport.mode === TransportMode.POPUP) {
376
389
  this.transport.closeWallet()
377
390
  }
@@ -591,6 +604,10 @@ export class ChainSessionManager {
591
604
  this.userEmail = userEmail ?? null
592
605
  this.guard = guard
593
606
  }
607
+
608
+ if (savedPayload?.ethAuth) {
609
+ await this._saveEthAuthProofIfProvided(connectResponse.ethAuthProof)
610
+ }
594
611
  } else if (response.action === RequestActionType.ADD_EXPLICIT_SESSION) {
595
612
  if (!this.walletAddress || !Address.isEqual(receivedAddress, this.walletAddress)) {
596
613
  throw new InitializationError('Received an explicit session for a wallet that is not active.')
@@ -811,19 +828,6 @@ export class ChainSessionManager {
811
828
  await this.sessionManager.findSignersForCalls(this.wallet.address, this.chainId, calls)
812
829
  return true
813
830
  } catch (error) {
814
- if (error instanceof Error && error.message.includes('Signer supporting call is expired')) {
815
- // Extract the expired signer address from the message with address regex
816
- const expiredSignerAddress = error.message.match(/(0x[0-9a-fA-F]{40})/)?.[1]
817
- if (expiredSignerAddress) {
818
- // Refresh the session
819
- await this._refreshExplicitSession(Address.from(expiredSignerAddress))
820
- // Retry the permission check
821
- return this.hasPermission(transactions)
822
- } else {
823
- // Could not parse error message. Rethrow as this shouldn't happen.
824
- throw error
825
- }
826
- }
827
831
  // An error from findSignersForCalls indicates a permission failure.
828
832
  console.warn(
829
833
  `Permission check failed for chain ${this.chainId}:`,
@@ -851,7 +855,17 @@ export class ChainSessionManager {
851
855
  }))
852
856
  try {
853
857
  const signedCall = await this._buildAndSignCalls(callsToSend)
854
- const feeOptions = await this.relayer.feeOptions(signedCall.to, this.chainId, callsToSend)
858
+ const fingerprint = this._fingerprintCalls(callsToSend)
859
+ if (fingerprint) {
860
+ this.lastSignedCallCache = {
861
+ fingerprint,
862
+ signedCall,
863
+ createdAtMs: Date.now(),
864
+ }
865
+ }
866
+ const walletAddress = this.walletAddress
867
+ if (!walletAddress) throw new InitializationError('Wallet is not initialized.')
868
+ const feeOptions = await this.relayer.feeOptions(walletAddress, this.chainId, signedCall.to, callsToSend)
855
869
  return feeOptions.options
856
870
  } catch (err) {
857
871
  throw new FeeOptionError(`Failed to get fee options: ${err instanceof Error ? err.message : String(err)}`)
@@ -907,7 +921,7 @@ export class ChainSessionManager {
907
921
  callsToSend.unshift(transferCall)
908
922
  }
909
923
  }
910
- const signedCalls = await this._buildAndSignCalls(callsToSend)
924
+ const signedCalls = this._getCachedSignedCall(callsToSend) ?? (await this._buildAndSignCalls(callsToSend))
911
925
  const hash = await this.relayer.relay(signedCalls.to, signedCalls.data, this.chainId)
912
926
  const status = await this._waitForTransactionReceipt(hash.opHash, this.chainId)
913
927
  if (status.status === 'confirmed') {
@@ -1101,4 +1115,49 @@ export class ChainSessionManager {
1101
1115
  await this.sequenceStorage.clearExplicitSessions()
1102
1116
  await this.sequenceStorage.clearSessionlessConnection()
1103
1117
  }
1118
+
1119
+ private async _saveEthAuthProofIfProvided(ethAuthProof?: ETHAuthProof): Promise<void> {
1120
+ if (!ethAuthProof) {
1121
+ return
1122
+ }
1123
+ await this.sequenceStorage.saveEthAuthProof(ethAuthProof)
1124
+ }
1125
+
1126
+ private _getCachedSignedCall(calls: Payload.Call[]): { to: Address.Address; data: Hex.Hex } | null {
1127
+ if (!this.lastSignedCallCache) {
1128
+ return null
1129
+ }
1130
+ const ttlMs = 30_000
1131
+ if (Date.now() - this.lastSignedCallCache.createdAtMs > ttlMs) {
1132
+ this.lastSignedCallCache = undefined
1133
+ return null
1134
+ }
1135
+ const fingerprint = this._fingerprintCalls(calls)
1136
+ if (!fingerprint) {
1137
+ return null
1138
+ }
1139
+ if (fingerprint !== this.lastSignedCallCache.fingerprint) {
1140
+ return null
1141
+ }
1142
+ return this.lastSignedCallCache.signedCall
1143
+ }
1144
+
1145
+ private _fingerprintCalls(calls: Payload.Call[]): string | null {
1146
+ try {
1147
+ return JSON.stringify(
1148
+ calls.map((call) => ({
1149
+ to: call.to,
1150
+ value: call.value?.toString() ?? '0',
1151
+ data: call.data ?? '0x',
1152
+ gasLimit: call.gasLimit?.toString() ?? '0',
1153
+ delegateCall: call.delegateCall ?? false,
1154
+ onlyFallback: call.onlyFallback ?? false,
1155
+ behaviorOnError: call.behaviorOnError ?? 'revert',
1156
+ })),
1157
+ )
1158
+ } catch (error) {
1159
+ console.warn('ChainSessionManager._fingerprintCalls failed:', error)
1160
+ return null
1161
+ }
1162
+ }
1104
1163
  }
package/src/DappClient.ts CHANGED
@@ -14,8 +14,10 @@ import {
14
14
  GetFeeTokensResponse,
15
15
  GuardConfig,
16
16
  LoginMethod,
17
+ EthAuthSettings,
17
18
  RandomPrivateKeyFn,
18
19
  RequestActionType,
20
+ ETHAuthProof,
19
21
  SendWalletTransactionPayload,
20
22
  SequenceSessionStorage,
21
23
  SignMessagePayload,
@@ -30,7 +32,7 @@ import { KEYMACHINE_URL, NODES_URL, RELAYER_URL } from './utils/constants.js'
30
32
  import { getRelayerUrl, getRpcUrl } from './utils/index.js'
31
33
  import { Relayer } from '@0xsequence/relayer'
32
34
 
33
- export type DappClientEventListener = (data?: any) => void
35
+ export type DappClientEventListener = (data?: unknown) => void
34
36
 
35
37
  interface DappClientEventMap {
36
38
  sessionsUpdated: () => void
@@ -180,11 +182,12 @@ export class DappClient {
180
182
  */
181
183
  public on<K extends keyof DappClientEventMap>(event: K, listener: DappClientEventMap[K]): () => void {
182
184
  if (!this.eventListeners[event]) {
183
- this.eventListeners[event] = new Set() as any
185
+ // @ts-expect-error - indexing into evenListeners will improperly create a union of all the possible types
186
+ this.eventListeners[event] = new Set<DappClientEventMap[K]>()
184
187
  }
185
- ;(this.eventListeners[event] as any).add(listener)
188
+ this.eventListeners[event].add(listener)
186
189
  return () => {
187
- ;(this.eventListeners[event] as any)?.delete(listener)
190
+ this.eventListeners[event]?.delete(listener)
188
191
  }
189
192
  }
190
193
 
@@ -407,6 +410,13 @@ export class DappClient {
407
410
  }
408
411
  }
409
412
 
413
+ /**
414
+ * Returns the latest persisted ETHAuth proof, if one has been received from the wallet.
415
+ */
416
+ public async getEthAuthProof(): Promise<ETHAuthProof | null> {
417
+ return this.sequenceStorage.getEthAuthProof()
418
+ }
419
+
410
420
  /**
411
421
  * Restores a sessionless connection that was previously persisted via {@link disconnect} or a connect flow.
412
422
  * @returns A promise that resolves to true if a sessionless connection was applied.
@@ -559,6 +569,7 @@ export class DappClient {
559
569
  preferredLoginMethod?: LoginMethod
560
570
  email?: string
561
571
  includeImplicitSession?: boolean
572
+ ethAuth?: EthAuthSettings
562
573
  } = {},
563
574
  ): Promise<void> {
564
575
  if (this.isInitialized) {
@@ -614,6 +625,7 @@ export class DappClient {
614
625
  preferredLoginMethod?: LoginMethod
615
626
  email?: string
616
627
  includeImplicitSession?: boolean
628
+ ethAuth?: EthAuthSettings
617
629
  } = {},
618
630
  ): Promise<void> {
619
631
  if (!this.isInitialized || !this.hasSessionlessConnection || !this.walletAddress) {
@@ -965,8 +977,6 @@ export class DappClient {
965
977
  async disconnect(options?: { keepSessionlessConnection?: boolean }): Promise<void> {
966
978
  const keepSessionlessConnection = options?.keepSessionlessConnection ?? true
967
979
 
968
- const transportMode = this.transportMode
969
-
970
980
  if (this.transport) {
971
981
  this.transport.destroy()
972
982
  }
@@ -378,10 +378,7 @@ export class DappTransport {
378
378
  return
379
379
  }
380
380
 
381
- const isPotentiallyValidSource =
382
- this.walletWindow && (event.source === this.walletWindow || !this.walletWindow.closed)
383
-
384
- if (!isPotentiallyValidSource && event.data?.type !== MessageType.WALLET_OPENED) {
381
+ if (!this.walletWindow || event.source !== this.walletWindow) {
385
382
  return
386
383
  }
387
384
 
package/src/index.ts CHANGED
@@ -24,6 +24,8 @@ export type {
24
24
  FeeToken,
25
25
  FeeOption,
26
26
  TransportMessage,
27
+ EthAuthSettings,
28
+ ETHAuthProof,
27
29
  } from './types/index.js'
28
30
  export { RequestActionType, TransportMode, MessageType } from './types/index.js'
29
31
  export {
@@ -35,7 +37,17 @@ export {
35
37
  SigningError,
36
38
  ModifyExplicitSessionError,
37
39
  } from './utils/errors.js'
38
- export { getExplorerUrl, jsonReplacers, jsonRevivers } from './utils/index.js'
40
+ export {
41
+ createExplicitSessionConfig,
42
+ getExplorerUrl,
43
+ getNetwork,
44
+ getRelayerUrl,
45
+ getRpcUrl,
46
+ jsonReplacers,
47
+ jsonRevivers,
48
+ VALUE_FORWARDER_ADDRESS,
49
+ } from './utils/index.js'
50
+ export type { ExplicitSessionParams, NativeTokenSpending, SessionDuration } from './utils/index.js'
39
51
  export type {
40
52
  SequenceStorage,
41
53
  ExplicitSessionData,
@@ -46,6 +58,14 @@ export type {
46
58
  } from './utils/storage.js'
47
59
  export { WebStorage } from './utils/storage.js'
48
60
 
49
- export { Attestation, Permission, Extensions, SessionConfig, Constants, Payload } from '@0xsequence/wallet-primitives'
61
+ export {
62
+ Attestation,
63
+ Permission,
64
+ Extensions,
65
+ SessionConfig,
66
+ Constants,
67
+ Payload,
68
+ Network,
69
+ } from '@0xsequence/wallet-primitives'
50
70
  export type { ExplicitSessionConfig, ExplicitSession, ImplicitSession, Session } from '@0xsequence/wallet-core'
51
71
  export { Signers, Wallet, Utils, Envelope, State } from '@0xsequence/wallet-core'
@@ -28,12 +28,32 @@ export interface GuardConfig {
28
28
  moduleAddresses: Map<Address.Address, Address.Address>
29
29
  }
30
30
 
31
+ export interface EthAuthSettings {
32
+ app?: string
33
+ /** expiry number (in seconds) that is used for ETHAuth proof. Default is 1 week in seconds. */
34
+ expiry?: number
35
+ /** origin hint of the dapp's host opening the wallet. This value will automatically
36
+ * be determined and verified for integrity, and can be omitted. */
37
+ origin?: string
38
+ /** authorizeNonce is an optional number to be passed as ETHAuth's nonce claim for replay protection. **/
39
+ nonce?: number
40
+ }
41
+
42
+ export interface ETHAuthProof {
43
+ // eip712 typed-data payload for ETHAuth domain as input
44
+ typedData: Payload.TypedDataToSign
45
+
46
+ // signature encoded in an ETHAuth proof string
47
+ ewtString: string
48
+ }
49
+
31
50
  // --- Payloads for Transport ---
32
51
 
33
52
  export interface CreateNewSessionPayload {
34
53
  origin?: string
35
54
  session?: ExplicitSession
36
55
  includeImplicitSession?: boolean
56
+ ethAuth?: EthAuthSettings
37
57
  preferredLoginMethod?: LoginMethod
38
58
  email?: string
39
59
  }
@@ -81,6 +101,7 @@ export interface CreateNewSessionResponse {
81
101
  userEmail?: string
82
102
  loginMethod?: LoginMethod
83
103
  guard?: GuardConfig
104
+ ethAuthProof?: ETHAuthProof
84
105
  }
85
106
 
86
107
  export interface SignatureResponse {
@@ -1,6 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Network } from '@0xsequence/wallet-primitives'
3
- import { Bytes, Hex } from 'ox'
2
+ import type { ExplicitSessionConfig } from '@0xsequence/wallet-core'
3
+ import { Network, Permission } from '@0xsequence/wallet-primitives'
4
+ import { Bytes, Hex, type Address } from 'ox'
5
+ export { VALUE_FORWARDER_ADDRESS } from './constants.js'
4
6
 
5
7
  type JsonReplacer = (key: string, value: any) => any
6
8
  type JsonReviver = (key: string, value: any) => any
@@ -124,6 +126,50 @@ const uint8ArrayReviver: JsonReviver = (key, value) => {
124
126
  export const jsonRevivers = chainRevivers([mapReviver, bigIntReviver, uint8ArrayReviver])
125
127
  export const jsonReplacers = chainReplacers([mapReplacer, bigIntReplacer, uint8ArrayReplacer])
126
128
 
129
+ export type SessionDuration = {
130
+ days?: number
131
+ hours?: number
132
+ minutes?: number
133
+ }
134
+
135
+ export type NativeTokenSpending = {
136
+ valueLimit: bigint
137
+ allowedRecipients?: Address.Address[]
138
+ }
139
+
140
+ export type ExplicitSessionParams = {
141
+ chainId: number
142
+ expiresIn: SessionDuration
143
+ permissions: Permission.Permission[]
144
+ nativeTokenSpending?: NativeTokenSpending
145
+ }
146
+
147
+ export const createExplicitSessionConfig = (params: ExplicitSessionParams): ExplicitSessionConfig => {
148
+ const nowInSeconds = BigInt(Math.floor(Date.now() / 1000))
149
+ const { days = 0, hours = 0, minutes = 0 } = params.expiresIn
150
+ const sessionLifetimeSeconds = days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60
151
+ const deadline = nowInSeconds + BigInt(sessionLifetimeSeconds)
152
+
153
+ if (params.permissions.length === 0) {
154
+ throw new Error('createExplicitSessionConfig: At least one permission is required.')
155
+ }
156
+
157
+ const nativeTokenSpending = params.nativeTokenSpending
158
+ const valueLimit = nativeTokenSpending?.valueLimit ?? 0n
159
+ const nativeTokenReceivers = [...(nativeTokenSpending?.allowedRecipients || [])]
160
+ const nativeTokenSpendingPermissions = nativeTokenReceivers.map((receiver) => ({
161
+ target: receiver,
162
+ rules: [],
163
+ }))
164
+
165
+ return {
166
+ chainId: params.chainId,
167
+ valueLimit,
168
+ deadline,
169
+ permissions: [...params.permissions, ...nativeTokenSpendingPermissions],
170
+ }
171
+ }
172
+
127
173
  /**
128
174
  * Apply a template to a string.
129
175
  *