@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.
- package/README.md +688 -0
- package/dist/browser/index.js +47 -47
- package/dist/node/index.cjs +65 -69
- package/dist/node/index.js +50 -50
- package/dist/types/connectWallet.d.ts +13 -19
- package/dist/types/guardian/index.d.ts +10 -5
- package/dist/types/magic/magicTEESigner.d.ts +3 -4
- package/dist/types/sequence/sequenceProvider.d.ts +4 -4
- package/dist/types/sequence/signer/identityInstrumentSigner.d.ts +2 -2
- package/dist/types/sequence/signer/index.d.ts +5 -4
- package/dist/types/sequence/signer/privateKeySigner.d.ts +2 -2
- package/dist/types/sequence/user/registerUser.d.ts +3 -3
- package/dist/types/types.d.ts +39 -9
- package/dist/types/zkEvm/relayerClient.d.ts +8 -4
- package/dist/types/zkEvm/user/registerZkEvmUser.d.ts +7 -4
- package/dist/types/zkEvm/zkEvmProvider.d.ts +13 -5
- package/package.json +7 -7
- package/src/connectWallet.test.ts +16 -22
- package/src/connectWallet.ts +79 -53
- package/src/guardian/index.ts +40 -25
- package/src/magic/magicTEESigner.ts +8 -6
- package/src/sequence/sequenceProvider.ts +17 -9
- package/src/sequence/signer/identityInstrumentSigner.ts +8 -6
- package/src/sequence/signer/index.ts +8 -12
- package/src/sequence/signer/privateKeySigner.ts +6 -5
- package/src/sequence/user/registerUser.ts +5 -4
- package/src/types.ts +44 -12
- package/src/zkEvm/relayerClient.ts +22 -6
- package/src/zkEvm/user/registerZkEvmUser.ts +16 -5
- package/src/zkEvm/zkEvmProvider.ts +56 -29
package/src/types.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Flow } from '@imtbl/metrics';
|
|
2
|
-
import {
|
|
3
|
-
Auth, TypedEventEmitter, type AuthEventMap,
|
|
4
|
-
} from '@imtbl/auth';
|
|
2
|
+
import { TypedEventEmitter, User } from '@imtbl/auth';
|
|
5
3
|
import { JsonRpcError } from './zkEvm/JsonRpcError';
|
|
6
4
|
|
|
7
5
|
export enum EvmChain {
|
|
@@ -22,15 +20,15 @@ export interface WalletSigner {
|
|
|
22
20
|
|
|
23
21
|
// Re-export auth types for convenience
|
|
24
22
|
export type {
|
|
25
|
-
User, UserProfile, UserZkEvm, DirectLoginMethod,
|
|
23
|
+
User, UserProfile, UserZkEvm, DirectLoginMethod,
|
|
26
24
|
} from '@imtbl/auth';
|
|
27
25
|
export { isUserZkEvm } from '@imtbl/auth';
|
|
28
26
|
export type { RollupType } from '@imtbl/auth';
|
|
29
|
-
export { AuthEvents } from '@imtbl/auth';
|
|
30
27
|
|
|
31
|
-
// Wallet
|
|
28
|
+
// Wallet events
|
|
32
29
|
export enum WalletEvents {
|
|
33
30
|
ACCOUNTS_REQUESTED = 'accountsRequested',
|
|
31
|
+
LOGGED_OUT = 'loggedOut',
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
export type AccountsRequestedEvent = {
|
|
@@ -41,11 +39,15 @@ export type AccountsRequestedEvent = {
|
|
|
41
39
|
flow?: Flow;
|
|
42
40
|
};
|
|
43
41
|
|
|
44
|
-
//
|
|
45
|
-
export interface
|
|
42
|
+
// WalletEventMap for internal wallet events
|
|
43
|
+
export interface WalletEventMap extends Record<string, any> {
|
|
46
44
|
[WalletEvents.ACCOUNTS_REQUESTED]: [AccountsRequestedEvent];
|
|
45
|
+
[WalletEvents.LOGGED_OUT]: [];
|
|
47
46
|
}
|
|
48
47
|
|
|
48
|
+
// Legacy alias for backwards compatibility with Passport
|
|
49
|
+
export type PassportEventMap = WalletEventMap;
|
|
50
|
+
|
|
49
51
|
/**
|
|
50
52
|
* EIP-1193 Provider Interface
|
|
51
53
|
* Standard Ethereum provider interface for all chain types
|
|
@@ -228,16 +230,46 @@ export interface PopupOverlayOptions {
|
|
|
228
230
|
disableBlockedPopupOverlay?: boolean;
|
|
229
231
|
}
|
|
230
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Function type for getting the current user.
|
|
235
|
+
* Used as an alternative to passing an Auth instance.
|
|
236
|
+
* This function should return fresh tokens from the session manager.
|
|
237
|
+
*
|
|
238
|
+
* @param forceRefresh - When true, the auth layer should trigger a server-side
|
|
239
|
+
* token refresh to get updated claims (e.g., after zkEVM registration).
|
|
240
|
+
* This ensures the returned user has the latest data from the identity provider.
|
|
241
|
+
*/
|
|
242
|
+
export type GetUserFunction = (forceRefresh?: boolean) => Promise<User | null>;
|
|
243
|
+
|
|
231
244
|
/**
|
|
232
245
|
* Options for connecting a wallet via connectWallet()
|
|
233
246
|
* High-level configuration that gets transformed into internal WalletConfiguration
|
|
234
247
|
*/
|
|
235
248
|
export interface ConnectWalletOptions {
|
|
236
249
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
250
|
+
* Function that returns the current user with fresh tokens.
|
|
251
|
+
* This is the primary way to provide authentication to the wallet.
|
|
252
|
+
*
|
|
253
|
+
* For NextAuth integration:
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* import { connectWallet } from '@imtbl/wallet';
|
|
257
|
+
* import { useImmutableSession } from '@imtbl/auth-next-client';
|
|
258
|
+
*
|
|
259
|
+
* const { getUser } = useImmutableSession();
|
|
260
|
+
* const provider = await connectWallet({ getUser });
|
|
261
|
+
* ```
|
|
262
|
+
*
|
|
263
|
+
* If not provided, a default implementation using @imtbl/auth will be created.
|
|
264
|
+
*/
|
|
265
|
+
getUser?: GetUserFunction;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Client ID for Immutable authentication.
|
|
269
|
+
* Required when getUser is not provided (for default auth).
|
|
270
|
+
* Also used for session activity tracking.
|
|
239
271
|
*/
|
|
240
|
-
|
|
272
|
+
clientId?: string;
|
|
241
273
|
|
|
242
274
|
/**
|
|
243
275
|
* Chain configurations (supports multi-chain)
|
|
@@ -272,5 +304,5 @@ export interface ConnectWalletOptions {
|
|
|
272
304
|
/**
|
|
273
305
|
* @internal - Only used by Passport for internal event communication
|
|
274
306
|
*/
|
|
275
|
-
passportEventEmitter?: TypedEventEmitter<
|
|
307
|
+
passportEventEmitter?: TypedEventEmitter<WalletEventMap>;
|
|
276
308
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { PublicClient, Hex } from 'viem';
|
|
2
|
-
import {
|
|
2
|
+
import { isUserZkEvm, type UserZkEvm } from '@imtbl/auth';
|
|
3
3
|
import { WalletConfiguration } from '../config';
|
|
4
4
|
import { FeeOption, RelayerTransaction, TypedDataPayload } from './types';
|
|
5
|
+
import type { GetUserFunction } from '../types';
|
|
5
6
|
import { getEip155ChainId } from './walletHelpers';
|
|
6
7
|
|
|
7
8
|
export type RelayerClientInput = {
|
|
8
9
|
config: WalletConfiguration,
|
|
9
10
|
rpcProvider: PublicClient,
|
|
10
|
-
|
|
11
|
+
getUser: GetUserFunction,
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
// JsonRpc base Types
|
|
@@ -94,12 +95,14 @@ export class RelayerClient {
|
|
|
94
95
|
|
|
95
96
|
private readonly rpcProvider: PublicClient;
|
|
96
97
|
|
|
97
|
-
private readonly
|
|
98
|
+
private readonly getUser: GetUserFunction;
|
|
98
99
|
|
|
99
|
-
constructor({
|
|
100
|
+
constructor({
|
|
101
|
+
config, rpcProvider, getUser,
|
|
102
|
+
}: RelayerClientInput) {
|
|
100
103
|
this.config = config;
|
|
101
104
|
this.rpcProvider = rpcProvider;
|
|
102
|
-
this.
|
|
105
|
+
this.getUser = getUser;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
private static getResponsePreview(text: string): string {
|
|
@@ -108,6 +111,19 @@ export class RelayerClient {
|
|
|
108
111
|
: text;
|
|
109
112
|
}
|
|
110
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Get zkEvm user using getUser function.
|
|
116
|
+
*/
|
|
117
|
+
private async getUserZkEvm(): Promise<UserZkEvm> {
|
|
118
|
+
const user = await this.getUser();
|
|
119
|
+
|
|
120
|
+
if (!user || !isUserZkEvm(user)) {
|
|
121
|
+
throw new Error('User not authenticated or missing zkEvm data');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return user;
|
|
125
|
+
}
|
|
126
|
+
|
|
111
127
|
private async postToRelayer<T>(request: RelayerTransactionRequest): Promise<T> {
|
|
112
128
|
const body: RelayerTransactionRequest & JsonRpc = {
|
|
113
129
|
id: 1,
|
|
@@ -115,7 +131,7 @@ export class RelayerClient {
|
|
|
115
131
|
...request,
|
|
116
132
|
};
|
|
117
133
|
|
|
118
|
-
const user = await this.
|
|
134
|
+
const user = await this.getUserZkEvm();
|
|
119
135
|
|
|
120
136
|
const response = await fetch(`${this.config.relayerUrl}/v1/transactions`, {
|
|
121
137
|
method: 'POST',
|
|
@@ -2,13 +2,16 @@ 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 '../walletHelpers';
|
|
5
|
-
import { Auth } from '@imtbl/auth';
|
|
6
5
|
import { JsonRpcError, RpcErrorCode } from '../JsonRpcError';
|
|
7
6
|
import { signRaw } from '../../utils/crypto';
|
|
8
|
-
import type { WalletSigner } from '../../types';
|
|
7
|
+
import type { WalletSigner, GetUserFunction } from '../../types';
|
|
9
8
|
|
|
10
9
|
export type RegisterZkEvmUserInput = {
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Function to get fresh user tokens. Used for triggering background refresh after registration.
|
|
12
|
+
* If not provided, no background refresh is performed.
|
|
13
|
+
*/
|
|
14
|
+
getUser?: GetUserFunction;
|
|
12
15
|
ethSigner: WalletSigner,
|
|
13
16
|
multiRollupApiClients: MultiRollupApiClients,
|
|
14
17
|
accessToken: string;
|
|
@@ -19,7 +22,7 @@ export type RegisterZkEvmUserInput = {
|
|
|
19
22
|
const MESSAGE_TO_SIGN = 'Only sign this message from Immutable Passport';
|
|
20
23
|
|
|
21
24
|
export async function registerZkEvmUser({
|
|
22
|
-
|
|
25
|
+
getUser,
|
|
23
26
|
ethSigner,
|
|
24
27
|
multiRollupApiClients,
|
|
25
28
|
accessToken,
|
|
@@ -67,7 +70,15 @@ export async function registerZkEvmUser({
|
|
|
67
70
|
});
|
|
68
71
|
flow.addEvent('endCreateCounterfactualAddress');
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
// Trigger a background refresh to get the updated user with zkEvm info.
|
|
74
|
+
// This is a best-effort operation - the caller will need to get updated
|
|
75
|
+
// user data from their session manager (e.g., NextAuth session callback
|
|
76
|
+
// will refresh tokens and return updated user).
|
|
77
|
+
if (getUser) {
|
|
78
|
+
getUser().catch(() => {
|
|
79
|
+
// Ignore errors - this is a best-effort refresh
|
|
80
|
+
});
|
|
81
|
+
}
|
|
71
82
|
|
|
72
83
|
return registrationResponse.data.counterfactual_address;
|
|
73
84
|
} catch (error) {
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
ProviderEventMap,
|
|
15
15
|
RequestArguments,
|
|
16
16
|
} from './types';
|
|
17
|
-
import {
|
|
17
|
+
import { TypedEventEmitter } from '@imtbl/auth';
|
|
18
18
|
import { WalletConfiguration } from '../config';
|
|
19
19
|
import {
|
|
20
|
-
|
|
20
|
+
WalletEventMap, WalletEvents, User, UserZkEvm, WalletSigner, GetUserFunction,
|
|
21
21
|
} from '../types';
|
|
22
22
|
import { RelayerClient } from './relayerClient';
|
|
23
23
|
import { JsonRpcError, ProviderErrorCode, RpcErrorCode } from './JsonRpcError';
|
|
@@ -32,20 +32,28 @@ import { sendDeployTransactionAndPersonalSign } from './sendDeployTransactionAnd
|
|
|
32
32
|
import { signEjectionTransaction } from './signEjectionTransaction';
|
|
33
33
|
|
|
34
34
|
export type ZkEvmProviderInput = {
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Function that returns the current user with fresh tokens.
|
|
37
|
+
* This is the primary way to provide authentication to the wallet.
|
|
38
|
+
*/
|
|
39
|
+
getUser: GetUserFunction;
|
|
40
|
+
/**
|
|
41
|
+
* Client ID for session activity tracking.
|
|
42
|
+
*/
|
|
43
|
+
clientId: string;
|
|
36
44
|
config: WalletConfiguration;
|
|
37
45
|
multiRollupApiClients: MultiRollupApiClients;
|
|
38
|
-
|
|
46
|
+
walletEventEmitter: TypedEventEmitter<WalletEventMap>;
|
|
39
47
|
guardianClient: GuardianClient;
|
|
40
48
|
ethSigner: WalletSigner;
|
|
41
49
|
user: User | null;
|
|
42
50
|
sessionActivityApiUrl: string | null;
|
|
43
51
|
};
|
|
44
52
|
|
|
45
|
-
const isZkEvmUser = (user: User): user is UserZkEvm =>
|
|
53
|
+
const isZkEvmUser = (user: User): user is UserZkEvm => !!user.zkEvm;
|
|
46
54
|
|
|
47
55
|
export class ZkEvmProvider implements Provider {
|
|
48
|
-
readonly #
|
|
56
|
+
readonly #getUser: GetUserFunction;
|
|
49
57
|
|
|
50
58
|
readonly #config: WalletConfiguration;
|
|
51
59
|
|
|
@@ -57,9 +65,9 @@ export class ZkEvmProvider implements Provider {
|
|
|
57
65
|
readonly #providerEventEmitter: TypedEventEmitter<ProviderEventMap>;
|
|
58
66
|
|
|
59
67
|
/**
|
|
60
|
-
* intended to emit internal
|
|
68
|
+
* intended to emit internal wallet events
|
|
61
69
|
*/
|
|
62
|
-
readonly #
|
|
70
|
+
readonly #walletEventEmitter: TypedEventEmitter<WalletEventMap>;
|
|
63
71
|
|
|
64
72
|
readonly #guardianClient: GuardianClient;
|
|
65
73
|
|
|
@@ -71,22 +79,26 @@ export class ZkEvmProvider implements Provider {
|
|
|
71
79
|
|
|
72
80
|
readonly #ethSigner: WalletSigner;
|
|
73
81
|
|
|
82
|
+
readonly #clientId: string;
|
|
83
|
+
|
|
74
84
|
public readonly isPassport: boolean = true;
|
|
75
85
|
|
|
76
86
|
constructor({
|
|
77
|
-
|
|
87
|
+
getUser,
|
|
88
|
+
clientId,
|
|
78
89
|
config,
|
|
79
90
|
multiRollupApiClients,
|
|
80
|
-
|
|
91
|
+
walletEventEmitter,
|
|
81
92
|
guardianClient,
|
|
82
93
|
ethSigner,
|
|
83
94
|
user,
|
|
84
95
|
sessionActivityApiUrl,
|
|
85
96
|
}: ZkEvmProviderInput) {
|
|
86
|
-
this.#
|
|
97
|
+
this.#getUser = getUser;
|
|
98
|
+
this.#clientId = clientId;
|
|
87
99
|
this.#config = config;
|
|
88
100
|
this.#guardianClient = guardianClient;
|
|
89
|
-
this.#
|
|
101
|
+
this.#walletEventEmitter = walletEventEmitter;
|
|
90
102
|
this.#sessionActivityApiUrl = sessionActivityApiUrl;
|
|
91
103
|
this.#ethSigner = ethSigner;
|
|
92
104
|
|
|
@@ -99,7 +111,7 @@ export class ZkEvmProvider implements Provider {
|
|
|
99
111
|
this.#relayerClient = new RelayerClient({
|
|
100
112
|
config: this.#config,
|
|
101
113
|
rpcProvider: this.#rpcProvider,
|
|
102
|
-
|
|
114
|
+
getUser: this.#getUser,
|
|
103
115
|
});
|
|
104
116
|
|
|
105
117
|
this.#multiRollupApiClients = multiRollupApiClients;
|
|
@@ -109,13 +121,9 @@ export class ZkEvmProvider implements Provider {
|
|
|
109
121
|
this.#callSessionActivity(user.zkEvm.ethAddress);
|
|
110
122
|
}
|
|
111
123
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
passportEventEmitter.on(AuthEvents.LOGGED_OUT, this.#handleLogout);
|
|
118
|
-
passportEventEmitter.on(
|
|
124
|
+
// Listen for logout events
|
|
125
|
+
walletEventEmitter.on(WalletEvents.LOGGED_OUT, this.#handleLogout);
|
|
126
|
+
walletEventEmitter.on(
|
|
119
127
|
WalletEvents.ACCOUNTS_REQUESTED,
|
|
120
128
|
trackSessionActivity,
|
|
121
129
|
);
|
|
@@ -125,7 +133,14 @@ export class ZkEvmProvider implements Provider {
|
|
|
125
133
|
this.#providerEventEmitter.emit(ProviderEvent.ACCOUNTS_CHANGED, []);
|
|
126
134
|
};
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Get the current user using getUser function.
|
|
138
|
+
*/
|
|
139
|
+
async #getCurrentUser(): Promise<User | null> {
|
|
140
|
+
return this.#getUser();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async #callSessionActivity(zkEvmAddress: string) {
|
|
129
144
|
// Only emit session activity event for supported chains (mainnet, testnet, devnet)
|
|
130
145
|
if (!this.#sessionActivityApiUrl) {
|
|
131
146
|
return;
|
|
@@ -147,18 +162,19 @@ export class ZkEvmProvider implements Provider {
|
|
|
147
162
|
nonceSpace,
|
|
148
163
|
isBackgroundTransaction: true,
|
|
149
164
|
});
|
|
150
|
-
|
|
165
|
+
|
|
166
|
+
this.#walletEventEmitter.emit(WalletEvents.ACCOUNTS_REQUESTED, {
|
|
151
167
|
sessionActivityApiUrl: this.#sessionActivityApiUrl,
|
|
152
168
|
sendTransaction: sendTransactionClosure,
|
|
153
169
|
walletAddress: zkEvmAddress,
|
|
154
|
-
passportClient:
|
|
170
|
+
passportClient: this.#clientId,
|
|
155
171
|
});
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
// Used to get the registered zkEvm address from the User session
|
|
159
175
|
async #getZkEvmAddress() {
|
|
160
176
|
try {
|
|
161
|
-
const user = await this.#
|
|
177
|
+
const user = await this.#getCurrentUser();
|
|
162
178
|
if (user && isZkEvmUser(user)) {
|
|
163
179
|
return user.zkEvm.ethAddress;
|
|
164
180
|
}
|
|
@@ -179,8 +195,15 @@ export class ZkEvmProvider implements Provider {
|
|
|
179
195
|
const flow = trackFlow('passport', 'ethRequestAccounts');
|
|
180
196
|
|
|
181
197
|
try {
|
|
182
|
-
|
|
183
|
-
|
|
198
|
+
// Get user via getUser function
|
|
199
|
+
const user = await this.#getUser();
|
|
200
|
+
if (!user) {
|
|
201
|
+
throw new JsonRpcError(
|
|
202
|
+
ProviderErrorCode.UNAUTHORIZED,
|
|
203
|
+
'User not authenticated. Please log in first.',
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
flow.addEvent('endGetUser');
|
|
184
207
|
|
|
185
208
|
let userZkEvmEthAddress: string | undefined;
|
|
186
209
|
|
|
@@ -189,13 +212,18 @@ export class ZkEvmProvider implements Provider {
|
|
|
189
212
|
|
|
190
213
|
userZkEvmEthAddress = await registerZkEvmUser({
|
|
191
214
|
ethSigner: this.#ethSigner,
|
|
192
|
-
|
|
215
|
+
getUser: this.#getUser,
|
|
193
216
|
multiRollupApiClients: this.#multiRollupApiClients,
|
|
194
217
|
accessToken: user.accessToken,
|
|
195
218
|
rpcProvider: this.#rpcProvider,
|
|
196
219
|
flow,
|
|
197
220
|
});
|
|
198
221
|
flow.addEvent('endUserRegistration');
|
|
222
|
+
|
|
223
|
+
// Force refresh to update session with zkEvm claims from IDP
|
|
224
|
+
// This ensures subsequent getUser() calls return the updated user
|
|
225
|
+
await this.#getUser(true);
|
|
226
|
+
flow.addEvent('endForceRefresh');
|
|
199
227
|
} else {
|
|
200
228
|
userZkEvmEthAddress = user.zkEvm.ethAddress;
|
|
201
229
|
}
|
|
@@ -420,10 +448,9 @@ export class ZkEvmProvider implements Provider {
|
|
|
420
448
|
}
|
|
421
449
|
}
|
|
422
450
|
case 'im_addSessionActivity': {
|
|
423
|
-
const [clientId] = request.params || [];
|
|
424
451
|
const zkEvmAddress = await this.#getZkEvmAddress();
|
|
425
452
|
if (zkEvmAddress) {
|
|
426
|
-
this.#callSessionActivity(zkEvmAddress
|
|
453
|
+
this.#callSessionActivity(zkEvmAddress);
|
|
427
454
|
}
|
|
428
455
|
return null;
|
|
429
456
|
}
|