@imtbl/wallet 2.12.6 → 2.12.7-alpha.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,5 @@
1
1
  import {
2
2
  Auth,
3
- IAuthConfiguration,
4
3
  TypedEventEmitter,
5
4
  } from '@imtbl/auth';
6
5
  import {
@@ -12,7 +11,7 @@ import {
12
11
  import { ZkEvmProvider } from './zkEvm/zkEvmProvider';
13
12
  import { SequenceProvider } from './sequence/sequenceProvider';
14
13
  import {
15
- ConnectWalletOptions, PassportEventMap, ChainConfig, Provider,
14
+ ConnectWalletOptions, PassportEventMap, ChainConfig, Provider, GetUserFunction,
16
15
  } from './types';
17
16
  import { WalletConfiguration } from './config';
18
17
  import GuardianClient from './guardian';
@@ -121,13 +120,22 @@ function getDefaultClientId(chain: ChainConfig): string {
121
120
  return isSandboxChain(chain) ? DEFAULT_SANDBOX_CLIENT_ID : DEFAULT_PRODUCTION_CLIENT_ID;
122
121
  }
123
122
 
124
- function createDefaultAuth(initialChain: ChainConfig, options: ConnectWalletOptions): Auth {
123
+ /**
124
+ * Create a default getUser function using internal Auth instance.
125
+ * This is used when no external getUser is provided.
126
+ * @internal
127
+ */
128
+ function createDefaultGetUser(initialChain: ChainConfig, options: ConnectWalletOptions): {
129
+ getUser: GetUserFunction;
130
+ clientId: string;
131
+ } {
125
132
  const passportDomain = derivePassportDomain(initialChain);
126
133
  const authenticationDomain = deriveAuthenticationDomain();
127
134
  const redirectUri = deriveRedirectUri();
135
+ const clientId = options.clientId || getDefaultClientId(initialChain);
128
136
 
129
- return new Auth({
130
- clientId: getDefaultClientId(initialChain),
137
+ const auth = new Auth({
138
+ clientId,
131
139
  redirectUri,
132
140
  popupRedirectUri: redirectUri,
133
141
  logoutRedirectUri: redirectUri,
@@ -138,6 +146,29 @@ function createDefaultAuth(initialChain: ChainConfig, options: ConnectWalletOpti
138
146
  popupOverlayOptions: options.popupOverlayOptions,
139
147
  crossSdkBridgeEnabled: options.crossSdkBridgeEnabled,
140
148
  });
149
+
150
+ // Set up message listener for popup login callback
151
+ if (typeof window !== 'undefined') {
152
+ window.addEventListener('message', async (event) => {
153
+ if (event.data.code && event.data.state) {
154
+ const currentQueryString = window.location.search;
155
+ const newQueryString = new URLSearchParams(currentQueryString);
156
+ newQueryString.set('code', event.data.code);
157
+ newQueryString.set('state', event.data.state);
158
+ window.history.replaceState(null, '', `?${newQueryString.toString()}`);
159
+ await auth.loginCallback();
160
+ newQueryString.delete('code');
161
+ newQueryString.delete('state');
162
+ window.history.replaceState(null, '', `?${newQueryString.toString()}`);
163
+ }
164
+ });
165
+ }
166
+
167
+ // Return getUser function that wraps Auth.getUserOrLogin
168
+ return {
169
+ getUser: async () => auth.getUserOrLogin(),
170
+ clientId,
171
+ };
141
172
  }
142
173
 
143
174
  /**
@@ -146,30 +177,24 @@ function createDefaultAuth(initialChain: ChainConfig, options: ConnectWalletOpti
146
177
  * @param config - Wallet configuration
147
178
  * @returns EIP-1193 compliant provider with multi-chain support
148
179
  *
149
- * If no Auth instance is provided, a default Immutable-hosted client id will be used.
180
+ * If getUser is not provided, a default implementation using @imtbl/auth will be created.
150
181
  *
151
- * @example
182
+ * @example Using external auth (e.g., NextAuth)
152
183
  * ```typescript
153
- * import { Auth } from '@imtbl/auth';
154
- * import { connectWallet, IMMUTABLE_ZKEVM_MAINNET_CHAIN } from '@imtbl/wallet';
184
+ * import { connectWallet } from '@imtbl/wallet';
185
+ * import { useImmutableSession } from '@imtbl/auth-next-client';
155
186
  *
156
- * // Create auth
157
- * const auth = new Auth({
158
- * authenticationDomain: 'https://auth.immutable.com',
159
- * passportDomain: 'https://passport.immutable.com',
160
- * clientId: 'your-client-id',
161
- * redirectUri: 'https://your-app.com/callback',
162
- * scope: 'openid profile email offline_access transact',
163
- * });
187
+ * const { getUser } = useImmutableSession();
188
+ * const provider = await connectWallet({ getUser });
189
+ * ```
164
190
  *
165
- * // Connect wallet (defaults to testnet + mainnet, starts on testnet)
166
- * const provider = await connectWallet({ auth });
191
+ * @example Using default auth (simplest setup)
192
+ * ```typescript
193
+ * import { connectWallet } from '@imtbl/wallet';
167
194
  *
168
- * // Or specify a single chain
169
- * const provider = await connectWallet({
170
- * auth,
171
- * chains: [IMMUTABLE_ZKEVM_MAINNET_CHAIN],
172
- * });
195
+ * // Uses default Immutable-hosted authentication
196
+ * const provider = await connectWallet();
197
+ * const accounts = await provider.request({ method: 'eth_requestAccounts' });
173
198
  * ```
174
199
  */
175
200
  export async function connectWallet(
@@ -198,33 +223,28 @@ export async function connectWallet(
198
223
  passport: apiConfig,
199
224
  });
200
225
 
201
- // 3. Resolve Auth (use provided instance or create a default)
202
- const auth = config.auth ?? createDefaultAuth(initialChain, config);
203
- if (!config.auth && typeof window !== 'undefined') {
204
- window.addEventListener('message', async (event) => {
205
- if (event.data.code && event.data.state) {
206
- // append to the current querystring making sure both cases of no existing and having existing params are handled
207
- const currentQueryString = window.location.search;
208
- const newQueryString = new URLSearchParams(currentQueryString);
209
- newQueryString.set('code', event.data.code);
210
- newQueryString.set('state', event.data.state);
211
- window.history.replaceState(null, '', `?${newQueryString.toString()}`);
212
- await auth.loginCallback();
213
- // remove the code and state from the querystring
214
- newQueryString.delete('code');
215
- newQueryString.delete('state');
216
- window.history.replaceState(null, '', `?${newQueryString.toString()}`);
217
- }
218
- });
226
+ // 3. Resolve getUser function
227
+ // If not provided, create a default implementation using internal Auth
228
+ let getUser: GetUserFunction;
229
+ let clientId: string;
230
+
231
+ if (config.getUser) {
232
+ getUser = config.getUser;
233
+ clientId = config.clientId || getDefaultClientId(initialChain);
234
+ } else {
235
+ // Create default getUser using internal Auth
236
+ const defaultAuth = createDefaultGetUser(initialChain, config);
237
+ getUser = defaultAuth.getUser;
238
+ clientId = defaultAuth.clientId;
219
239
  }
220
240
 
221
- // 4. Extract Auth configuration and current user
222
- const authConfig: IAuthConfiguration = auth.getConfig();
223
- const user = await auth.getUser();
241
+ // 4. Get current user (may be null if not logged in)
242
+ const user = await getUser().catch(() => null);
224
243
 
225
244
  // 5. Create wallet configuration with concrete URLs
245
+ const passportDomain = initialChain.passportDomain || initialChain.apiUrl.replace('api.', 'passport.');
226
246
  const walletConfig = new WalletConfiguration({
227
- passportDomain: initialChain.passportDomain || initialChain.apiUrl.replace('api.', 'passport.'),
247
+ passportDomain,
228
248
  zkEvmRpcUrl: initialChain.rpcUrl,
229
249
  relayerUrl: initialChain.relayerUrl,
230
250
  indexerMrBasePath: initialChain.apiUrl,
@@ -242,9 +262,10 @@ export async function connectWallet(
242
262
 
243
263
  const guardianClient = new GuardianClient({
244
264
  config: walletConfig,
245
- auth,
265
+ getUser,
246
266
  guardianApi,
247
- authConfig,
267
+ passportDomain,
268
+ clientId,
248
269
  });
249
270
 
250
271
  // 8. Create provider based on chain type
@@ -262,7 +283,7 @@ export async function connectWallet(
262
283
  magicPublishableApiKey: magicConfig.magicPublishableApiKey,
263
284
  magicProviderId: magicConfig.magicProviderId,
264
285
  });
265
- const ethSigner = new MagicTEESigner(auth, magicTeeApiClients);
286
+ const ethSigner = new MagicTEESigner(getUser, magicTeeApiClients);
266
287
 
267
288
  // 11. Determine session activity API URL (only for mainnet, testnet, devnet)
268
289
  let sessionActivityApiUrl: string | null = null;
@@ -280,24 +301,29 @@ export async function connectWallet(
280
301
 
281
302
  // 12. Create ZkEvmProvider
282
303
  provider = new ZkEvmProvider({
283
- auth,
304
+ getUser,
305
+ clientId,
284
306
  config: walletConfig,
285
307
  multiRollupApiClients,
286
- passportEventEmitter,
308
+ walletEventEmitter: passportEventEmitter,
287
309
  guardianClient,
288
310
  ethSigner,
289
311
  user,
290
312
  sessionActivityApiUrl,
291
313
  });
292
314
  } else {
315
+ // Determine if this is a dev environment based on domain
316
+ const isDevEnvironment = passportDomain.includes('.dev.') || initialChain.apiUrl.includes('.dev.');
317
+
293
318
  // Create Sequence signer based on environment
294
- const sequenceSigner = createSequenceSigner(auth, authConfig, {
319
+ const sequenceSigner = createSequenceSigner(getUser, {
295
320
  identityInstrumentEndpoint: initialChain.sequenceIdentityInstrumentEndpoint,
321
+ isDevEnvironment,
296
322
  });
297
323
 
298
324
  // Non-zkEVM chain - use SequenceProvider
299
325
  provider = new SequenceProvider({
300
- auth,
326
+ getUser,
301
327
  chainConfig: initialChain,
302
328
  multiRollupApiClients,
303
329
  guardianClient,
@@ -1,6 +1,6 @@
1
1
  import * as GeneratedClients from '@imtbl/generated-clients';
2
2
  import { zeroAddress } from 'viem';
3
- import { Auth, IAuthConfiguration } from '@imtbl/auth';
3
+ import { isUserZkEvm, type UserZkEvm } from '@imtbl/auth';
4
4
  import ConfirmationScreen from '../confirmation/confirmation';
5
5
  import { JsonRpcError, ProviderErrorCode, RpcErrorCode } from '../zkEvm/JsonRpcError';
6
6
  import { MetaTransaction, TypedDataPayload } from '../zkEvm/types';
@@ -8,12 +8,14 @@ import { WalletConfiguration } from '../config';
8
8
  import { getEip155ChainId } from '../zkEvm/walletHelpers';
9
9
  import { WalletError, WalletErrorType } from '../errors';
10
10
  import { isAxiosError } from '../utils/http';
11
+ import type { GetUserFunction } from '../types';
11
12
 
12
13
  export type GuardianClientParams = {
13
14
  config: WalletConfiguration;
14
- auth: Auth;
15
+ getUser: GetUserFunction;
15
16
  guardianApi: GeneratedClients.mr.GuardianApi;
16
- authConfig: IAuthConfiguration;
17
+ passportDomain: string;
18
+ clientId: string;
17
19
  };
18
20
 
19
21
  type GuardianEVMTxnEvaluationParams = {
@@ -68,15 +70,40 @@ export default class GuardianClient {
68
70
 
69
71
  private readonly crossSdkBridgeEnabled: boolean;
70
72
 
71
- private readonly auth: Auth;
73
+ private readonly getUser: GetUserFunction;
72
74
 
73
75
  constructor({
74
- config, auth, guardianApi, authConfig,
76
+ config, getUser, guardianApi, passportDomain, clientId,
75
77
  }: GuardianClientParams) {
76
- this.confirmationScreen = new ConfirmationScreen(authConfig);
78
+ // Create a minimal auth config for ConfirmationScreen
79
+ this.confirmationScreen = new ConfirmationScreen({
80
+ authenticationDomain: 'https://auth.immutable.com',
81
+ passportDomain,
82
+ oidcConfiguration: {
83
+ clientId,
84
+ redirectUri: 'https://auth.immutable.com/im-logged-in',
85
+ },
86
+ crossSdkBridgeEnabled: config.crossSdkBridgeEnabled,
87
+ });
77
88
  this.crossSdkBridgeEnabled = config.crossSdkBridgeEnabled;
78
89
  this.guardianApi = guardianApi;
79
- this.auth = auth;
90
+ this.getUser = getUser;
91
+ }
92
+
93
+ /**
94
+ * Get zkEvm user using getUser function.
95
+ */
96
+ private async getUserZkEvm(): Promise<UserZkEvm> {
97
+ const user = await this.getUser();
98
+
99
+ if (!user || !isUserZkEvm(user)) {
100
+ throw new JsonRpcError(
101
+ ProviderErrorCode.UNAUTHORIZED,
102
+ 'User not authenticated or missing zkEvm data',
103
+ );
104
+ }
105
+
106
+ return user;
80
107
  }
81
108
 
82
109
  /**
@@ -120,7 +147,7 @@ export default class GuardianClient {
120
147
  nonce,
121
148
  metaTransactions,
122
149
  }: GuardianEVMTxnEvaluationParams): Promise<GeneratedClients.mr.TransactionEvaluationResponse> {
123
- const user = await this.auth.getUserZkEvm();
150
+ const user = await this.getUserZkEvm();
124
151
  const headers = { Authorization: `Bearer ${user.accessToken}` };
125
152
  const guardianTransactions = transformGuardianTransactions(metaTransactions);
126
153
  try {
@@ -175,7 +202,7 @@ export default class GuardianClient {
175
202
  }
176
203
 
177
204
  if (confirmationRequired && !!transactionId) {
178
- const user = await this.auth.getUserZkEvm();
205
+ const user = await this.getUserZkEvm();
179
206
  const confirmationResult = await this.confirmationScreen.requestConfirmation(
180
207
  transactionId,
181
208
  user.zkEvm.ethAddress,
@@ -200,13 +227,7 @@ export default class GuardianClient {
200
227
  { chainID, payload }: GuardianEIP712MessageEvaluationParams,
201
228
  ): Promise<GeneratedClients.mr.MessageEvaluationResponse> {
202
229
  try {
203
- const user = await this.auth.getUserZkEvm();
204
- if (user === null) {
205
- throw new JsonRpcError(
206
- ProviderErrorCode.UNAUTHORIZED,
207
- 'User not logged in. Please log in first.',
208
- );
209
- }
230
+ const user = await this.getUserZkEvm();
210
231
  const messageEvalResponse = await this.guardianApi.evaluateMessage(
211
232
  { messageEvaluationRequest: { chainID, payload } },
212
233
  { headers: { Authorization: `Bearer ${user.accessToken}` } },
@@ -227,7 +248,7 @@ export default class GuardianClient {
227
248
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
228
249
  }
229
250
  if (confirmationRequired && !!messageId) {
230
- const user = await this.auth.getUserZkEvm();
251
+ const user = await this.getUserZkEvm();
231
252
  const confirmationResult = await this.confirmationScreen.requestMessageConfirmation(
232
253
  messageId,
233
254
  user.zkEvm.ethAddress,
@@ -250,13 +271,7 @@ export default class GuardianClient {
250
271
  { chainID, payload }: GuardianERC191MessageEvaluationParams,
251
272
  ): Promise<GeneratedClients.mr.MessageEvaluationResponse> {
252
273
  try {
253
- const user = await this.auth.getUserZkEvm();
254
- if (user === null) {
255
- throw new JsonRpcError(
256
- ProviderErrorCode.UNAUTHORIZED,
257
- 'User not logged in. Please log in first.',
258
- );
259
- }
274
+ const user = await this.getUserZkEvm();
260
275
  const messageEvalResponse = await this.guardianApi.evaluateErc191Message(
261
276
  {
262
277
  eRC191MessageEvaluationRequest: {
@@ -282,7 +297,7 @@ export default class GuardianClient {
282
297
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
283
298
  }
284
299
  if (confirmationRequired && !!messageId) {
285
- const user = await this.auth.getUserZkEvm();
300
+ const user = await this.getUserZkEvm();
286
301
  const confirmationResult = await this.confirmationScreen.requestMessageConfirmation(
287
302
  messageId,
288
303
  user.zkEvm.ethAddress,
@@ -2,9 +2,10 @@
2
2
  import { MagicTeeApiClients } from '@imtbl/generated-clients';
3
3
  import { Flow, trackDuration } from '@imtbl/metrics';
4
4
  import { WalletError, WalletErrorType } from '../errors';
5
- import { Auth } from '@imtbl/auth';
6
5
  import { withMetricsAsync } from '../utils/metrics';
7
- import { isUserZkEvm, User, WalletSigner } from '../types';
6
+ import {
7
+ isUserZkEvm, User, WalletSigner, GetUserFunction,
8
+ } from '../types';
8
9
  import { isAxiosError } from '../utils/http';
9
10
 
10
11
  const CHAIN_IDENTIFIER = 'ETH';
@@ -62,7 +63,7 @@ const toBase64 = (value: string): string => {
62
63
  * This signer delegates cryptographic operations to the Magic TEE service.
63
64
  */
64
65
  export default class MagicTEESigner implements WalletSigner {
65
- private readonly auth: Auth;
66
+ private readonly getUser: GetUserFunction;
66
67
 
67
68
  private readonly magicTeeApiClient: MagicTeeApiClients;
68
69
 
@@ -70,8 +71,8 @@ export default class MagicTEESigner implements WalletSigner {
70
71
 
71
72
  private createWalletPromise: Promise<UserWallet> | null = null;
72
73
 
73
- constructor(auth: Auth, magicTeeApiClient: MagicTeeApiClients) {
74
- this.auth = auth;
74
+ constructor(getUser: GetUserFunction, magicTeeApiClient: MagicTeeApiClients) {
75
+ this.getUser = getUser;
75
76
  this.magicTeeApiClient = magicTeeApiClient;
76
77
  }
77
78
 
@@ -164,7 +165,8 @@ export default class MagicTEESigner implements WalletSigner {
164
165
  }
165
166
 
166
167
  private async getUserOrThrow(): Promise<User> {
167
- const user = await this.auth.getUser();
168
+ const user = await this.getUser();
169
+
168
170
  if (!user) {
169
171
  throw new WalletError(
170
172
  'User has been logged out',
@@ -5,7 +5,7 @@ import {
5
5
  type PublicClient,
6
6
  } from 'viem';
7
7
  import { MultiRollupApiClients } from '@imtbl/generated-clients';
8
- import { Auth, TypedEventEmitter, User } from '@imtbl/auth';
8
+ import { TypedEventEmitter, User } from '@imtbl/auth';
9
9
  import { trackFlow, trackError, identify } from '@imtbl/metrics';
10
10
  import {
11
11
  Provider,
@@ -14,6 +14,7 @@ import {
14
14
  RequestArguments,
15
15
  ChainConfig,
16
16
  EvmChain,
17
+ GetUserFunction,
17
18
  } from '../types';
18
19
  import { JsonRpcError, ProviderErrorCode, RpcErrorCode } from '../zkEvm/JsonRpcError';
19
20
  import GuardianClient from '../guardian';
@@ -22,7 +23,7 @@ import { registerUser } from './user';
22
23
  import { getEvmChainFromChainId } from '../network/chainRegistry';
23
24
 
24
25
  export type SequenceProviderInput = {
25
- auth: Auth;
26
+ getUser: GetUserFunction;
26
27
  chainConfig: ChainConfig;
27
28
  multiRollupApiClients: MultiRollupApiClients;
28
29
  guardianClient: GuardianClient;
@@ -50,7 +51,7 @@ function getUserChainAddress(user: User, chain: SequenceChain): string | undefin
50
51
  }
51
52
 
52
53
  export class SequenceProvider implements Provider {
53
- readonly #auth: Auth;
54
+ readonly #getUser: GetUserFunction;
54
55
 
55
56
  readonly #chainConfig: ChainConfig;
56
57
 
@@ -69,7 +70,7 @@ export class SequenceProvider implements Provider {
69
70
  public readonly isPassport: boolean = true;
70
71
 
71
72
  constructor({
72
- auth,
73
+ getUser,
73
74
  chainConfig,
74
75
  multiRollupApiClients,
75
76
  guardianClient,
@@ -83,7 +84,7 @@ export class SequenceProvider implements Provider {
83
84
  }
84
85
  this.#evmChain = evmChain;
85
86
 
86
- this.#auth = auth;
87
+ this.#getUser = getUser;
87
88
  this.#chainConfig = chainConfig;
88
89
  this.#multiRollupApiClients = multiRollupApiClients;
89
90
  this.#guardianClient = guardianClient;
@@ -100,7 +101,7 @@ export class SequenceProvider implements Provider {
100
101
  * Get the user's address for this chain if already registered.
101
102
  */
102
103
  async #getChainAddress(): Promise<string | undefined> {
103
- const user = await this.#auth.getUser();
104
+ const user = await this.#getUser();
104
105
  if (user && isUserRegisteredForChain(user, this.#evmChain)) {
105
106
  return getUserChainAddress(user, this.#evmChain);
106
107
  }
@@ -117,8 +118,15 @@ export class SequenceProvider implements Provider {
117
118
  const flow = trackFlow('passport', 'ethRequestAccounts');
118
119
 
119
120
  try {
120
- const user = await this.#auth.getUserOrLogin();
121
- flow.addEvent('endGetUserOrLogin');
121
+ const user = await this.#getUser();
122
+ flow.addEvent('endGetUser');
123
+
124
+ if (!user) {
125
+ throw new JsonRpcError(
126
+ RpcErrorCode.INTERNAL_ERROR,
127
+ 'User not authenticated',
128
+ );
129
+ }
122
130
 
123
131
  let userEthAddress: string | undefined;
124
132
 
@@ -126,7 +134,7 @@ export class SequenceProvider implements Provider {
126
134
  flow.addEvent('startUserRegistration');
127
135
 
128
136
  userEthAddress = await registerUser({
129
- auth: this.#auth,
137
+ getUser: this.#getUser,
130
138
  ethSigner: this.#ethSigner,
131
139
  multiRollupApiClients: this.#multiRollupApiClients,
132
140
  accessToken: user.accessToken,
@@ -2,13 +2,14 @@ import { hashMessage, toHex, concat } from 'viem';
2
2
  import { Identity } from '@0xsequence/wallet-wdk';
3
3
  import { IdentityInstrument, IdTokenChallenge } from '@0xsequence/identity-instrument';
4
4
  import { WalletError, WalletErrorType } from '../../errors';
5
- import { Auth, User, decodeJwtPayload } from '@imtbl/auth';
5
+ import { User, decodeJwtPayload } from '@imtbl/auth';
6
6
  import { Hex, Address } from 'ox';
7
7
  import {
8
8
  Payload,
9
9
  Signature as SequenceSignature,
10
10
  } from '@0xsequence/wallet-primitives';
11
11
  import { SequenceSigner } from './types';
12
+ import { GetUserFunction } from '../../types';
12
13
 
13
14
  interface IdTokenPayload {
14
15
  iss: string;
@@ -36,7 +37,7 @@ export interface IdentityInstrumentSignerConfig {
36
37
  }
37
38
 
38
39
  export class IdentityInstrumentSigner implements SequenceSigner {
39
- readonly #auth: Auth;
40
+ readonly #getUser: GetUserFunction;
40
41
 
41
42
  readonly #config: IdentityInstrumentSignerConfig;
42
43
 
@@ -44,13 +45,13 @@ export class IdentityInstrumentSigner implements SequenceSigner {
44
45
 
45
46
  #createWalletPromise: Promise<UserWallet> | null = null;
46
47
 
47
- constructor(auth: Auth, config: IdentityInstrumentSignerConfig) {
48
- this.#auth = auth;
48
+ constructor(getUser: GetUserFunction, config: IdentityInstrumentSignerConfig) {
49
+ this.#getUser = getUser;
49
50
  this.#config = config;
50
51
  }
51
52
 
52
53
  async #getUserOrThrow(): Promise<User> {
53
- const user = await this.#auth.getUser();
54
+ const user = await this.#getUser();
54
55
  if (!user) {
55
56
  throw new WalletError(
56
57
  'User not authenticated',
@@ -80,7 +81,8 @@ export class IdentityInstrumentSigner implements SequenceSigner {
80
81
  this.#createWalletPromise = (async () => {
81
82
  try {
82
83
  this.#userWallet = null;
83
- await this.#auth.forceUserRefresh(); // TODO shouldn't have to refresh all the time
84
+ // Force refresh to get latest user data including idToken
85
+ await this.#getUser(true);
84
86
 
85
87
  const authenticatedUser = user || await this.#getUserOrThrow();
86
88
 
@@ -1,18 +1,18 @@
1
- import { Auth, IAuthConfiguration } from '@imtbl/auth';
2
1
  import { SequenceSigner } from './types';
3
2
  import { IdentityInstrumentSigner } from './identityInstrumentSigner';
4
3
  import { PrivateKeySigner } from './privateKeySigner';
4
+ import { GetUserFunction } from '../../types';
5
5
 
6
6
  export type { SequenceSigner } from './types';
7
7
  export { IdentityInstrumentSigner } from './identityInstrumentSigner';
8
8
  export type { IdentityInstrumentSignerConfig } from './identityInstrumentSigner';
9
9
  export { PrivateKeySigner } from './privateKeySigner';
10
10
 
11
- const DEV_AUTH_DOMAIN = 'https://auth.dev.immutable.com';
12
-
13
11
  export interface CreateSequenceSignerConfig {
14
12
  /** Identity Instrument endpoint (required for prod/sandbox) */
15
13
  identityInstrumentEndpoint?: string;
14
+ /** Whether this is a dev environment (uses PrivateKeySigner instead of IdentityInstrumentSigner) */
15
+ isDevEnvironment?: boolean;
16
16
  }
17
17
 
18
18
  /**
@@ -20,26 +20,22 @@ export interface CreateSequenceSignerConfig {
20
20
  * - Dev environment (behind VPN): uses PrivateKeySigner
21
21
  * - Prod/Sandbox: uses IdentityInstrumentSigner
22
22
  *
23
- * @param auth - Auth instance
24
- * @param authConfig - Auth configuration (to determine environment)
23
+ * @param getUser - Function to get the current user
25
24
  * @param config - Signer configuration
26
25
  */
27
26
  export function createSequenceSigner(
28
- auth: Auth,
29
- authConfig: IAuthConfiguration,
27
+ getUser: GetUserFunction,
30
28
  config: CreateSequenceSignerConfig = {},
31
29
  ): SequenceSigner {
32
- const isDevEnvironment = authConfig.authenticationDomain === DEV_AUTH_DOMAIN;
33
-
34
- if (isDevEnvironment) {
35
- return new PrivateKeySigner(auth);
30
+ if (config.isDevEnvironment) {
31
+ return new PrivateKeySigner(getUser);
36
32
  }
37
33
 
38
34
  if (!config.identityInstrumentEndpoint) {
39
35
  throw new Error('identityInstrumentEndpoint is required for non-dev environments');
40
36
  }
41
37
 
42
- return new IdentityInstrumentSigner(auth, {
38
+ return new IdentityInstrumentSigner(getUser, {
43
39
  identityInstrumentEndpoint: config.identityInstrumentEndpoint,
44
40
  });
45
41
  }
@@ -1,7 +1,7 @@
1
1
  import { keccak256, toBytes } from 'viem';
2
2
  import { privateKeyToAccount } from 'viem/accounts';
3
3
  import { WalletError, WalletErrorType } from '../../errors';
4
- import { Auth, User } from '@imtbl/auth';
4
+ import { User } from '@imtbl/auth';
5
5
  import { Signers } from '@0xsequence/wallet-core';
6
6
  import {
7
7
  Payload,
@@ -9,6 +9,7 @@ import {
9
9
  } from '@0xsequence/wallet-primitives';
10
10
  import { SequenceSigner } from './types';
11
11
  import { Address } from 'ox';
12
+ import { GetUserFunction } from '../../types';
12
13
 
13
14
  interface PrivateKeyWallet {
14
15
  userIdentifier: string;
@@ -22,18 +23,18 @@ interface PrivateKeyWallet {
22
23
  * Uses a deterministic private key derived from the user's sub.
23
24
  */
24
25
  export class PrivateKeySigner implements SequenceSigner {
25
- readonly #auth: Auth;
26
+ readonly #getUser: GetUserFunction;
26
27
 
27
28
  #privateKeyWallet: PrivateKeyWallet | null = null;
28
29
 
29
30
  #createWalletPromise: Promise<PrivateKeyWallet> | null = null;
30
31
 
31
- constructor(auth: Auth) {
32
- this.#auth = auth;
32
+ constructor(getUser: GetUserFunction) {
33
+ this.#getUser = getUser;
33
34
  }
34
35
 
35
36
  async #getUserOrThrow(): Promise<User> {
36
- const user = await this.#auth.getUser();
37
+ const user = await this.#getUser();
37
38
  if (!user) {
38
39
  throw new WalletError('User not authenticated', WalletErrorType.NOT_LOGGED_IN_ERROR);
39
40
  }
@@ -2,12 +2,12 @@ import { MultiRollupApiClients } from '@imtbl/generated-clients';
2
2
  import { Flow } from '@imtbl/metrics';
3
3
  import type { PublicClient } from 'viem';
4
4
  import { getEip155ChainId } from '../../zkEvm/walletHelpers';
5
- import { Auth } from '@imtbl/auth';
6
5
  import { JsonRpcError, RpcErrorCode } from '../../zkEvm/JsonRpcError';
7
6
  import { SequenceSigner } from '../signer';
7
+ import { GetUserFunction } from '../../types';
8
8
 
9
9
  export type RegisterUserInput = {
10
- auth: Auth;
10
+ getUser: GetUserFunction;
11
11
  ethSigner: SequenceSigner;
12
12
  multiRollupApiClients: MultiRollupApiClients;
13
13
  accessToken: string;
@@ -39,7 +39,7 @@ function formatSignature(signature: string): string {
39
39
  * Creates a counterfactual address for the user on the specified chain.
40
40
  */
41
41
  export async function registerUser({
42
- auth,
42
+ getUser,
43
43
  ethSigner,
44
44
  multiRollupApiClients,
45
45
  accessToken,
@@ -87,7 +87,8 @@ export async function registerUser({
87
87
  });
88
88
  flow.addEvent('endCreateCounterfactualAddress');
89
89
 
90
- auth.forceUserRefreshInBackground();
90
+ // Trigger background refresh to get updated user data with the new chain registration
91
+ getUser(true).catch(() => {});
91
92
 
92
93
  return registrationResponse.data.counterfactual_address;
93
94
  } catch (error) {