@injectivelabs/wallet-turnkey 1.16.6-alpha.0 → 1.16.6
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 +34 -32
- package/dist/cjs/strategy/strategy.d.ts +9 -8
- package/dist/cjs/strategy/strategy.js +37 -23
- package/dist/cjs/strategy/turnkey/oauth.d.ts +3 -3
- package/dist/cjs/strategy/turnkey/oauth.js +4 -5
- package/dist/cjs/strategy/turnkey/otp.d.ts +3 -4
- package/dist/cjs/strategy/turnkey/otp.js +10 -10
- package/dist/cjs/strategy/turnkey/turnkey.d.ts +12 -8
- package/dist/cjs/strategy/turnkey/turnkey.js +119 -73
- package/dist/cjs/strategy/types.d.ts +1 -1
- package/dist/esm/strategy/strategy.d.ts +9 -8
- package/dist/esm/strategy/strategy.js +34 -20
- package/dist/esm/strategy/turnkey/oauth.d.ts +3 -3
- package/dist/esm/strategy/turnkey/oauth.js +4 -5
- package/dist/esm/strategy/turnkey/otp.d.ts +3 -4
- package/dist/esm/strategy/turnkey/otp.js +10 -10
- package/dist/esm/strategy/turnkey/turnkey.d.ts +12 -8
- package/dist/esm/strategy/turnkey/turnkey.js +121 -75
- package/dist/esm/strategy/types.d.ts +1 -1
- package/package.json +11 -11
|
@@ -15,66 +15,76 @@ const utils_js_1 = require("../../utils.js");
|
|
|
15
15
|
class TurnkeyWallet {
|
|
16
16
|
otpId;
|
|
17
17
|
turnkey;
|
|
18
|
-
|
|
18
|
+
organizationId;
|
|
19
19
|
client;
|
|
20
20
|
metadata;
|
|
21
|
-
|
|
21
|
+
iframeClient;
|
|
22
22
|
accountMap = {};
|
|
23
23
|
setMetadata(metadata) {
|
|
24
24
|
this.metadata = { ...this.metadata, ...metadata };
|
|
25
25
|
}
|
|
26
26
|
constructor(metadata) {
|
|
27
27
|
this.metadata = metadata;
|
|
28
|
+
this.organizationId = metadata.organizationId;
|
|
28
29
|
this.client = new utils_1.HttpRestClient(metadata.apiServerEndpoint);
|
|
29
30
|
}
|
|
30
31
|
static async getTurnkeyInstance(metadata) {
|
|
31
|
-
const { turnkey,
|
|
32
|
+
const { turnkey, iframeClient } = await createTurnkeyIFrame(metadata);
|
|
32
33
|
return {
|
|
33
34
|
turnkey,
|
|
34
|
-
|
|
35
|
+
iframeClient,
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
async getTurnkey() {
|
|
38
|
-
if (!this.
|
|
39
|
-
await this.
|
|
39
|
+
if (!this.iframeClient) {
|
|
40
|
+
await this.initFrame();
|
|
40
41
|
}
|
|
41
42
|
if (!this.turnkey) {
|
|
42
43
|
this.turnkey = new sdk_browser_1.Turnkey(this.metadata);
|
|
43
44
|
}
|
|
44
45
|
return this.turnkey;
|
|
45
46
|
}
|
|
46
|
-
async
|
|
47
|
-
if (!this.
|
|
48
|
-
await this.
|
|
47
|
+
async getIframeClient() {
|
|
48
|
+
if (!this.iframeClient) {
|
|
49
|
+
await this.initFrame();
|
|
49
50
|
}
|
|
50
|
-
if (!this.
|
|
51
|
-
throw new exceptions_1.WalletException(new Error('
|
|
51
|
+
if (!this.iframeClient) {
|
|
52
|
+
throw new exceptions_1.WalletException(new Error('Iframe client not initialized'));
|
|
52
53
|
}
|
|
53
|
-
return this.
|
|
54
|
+
return this.iframeClient;
|
|
54
55
|
}
|
|
55
56
|
async getSession(existingCredentialBundle) {
|
|
57
|
+
const { metadata } = this;
|
|
58
|
+
const iframeClient = await this.getIframeClient();
|
|
59
|
+
const turnkey = await this.getTurnkey();
|
|
60
|
+
const currentSession = await turnkey.getSession();
|
|
61
|
+
const organizationId = currentSession?.organizationId || metadata.defaultOrganizationId;
|
|
62
|
+
const credentialBundle = existingCredentialBundle || currentSession?.token;
|
|
63
|
+
if (!credentialBundle) {
|
|
64
|
+
return {
|
|
65
|
+
session: undefined,
|
|
66
|
+
organizationId,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
56
69
|
try {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
const user = await indexedDbClient.getWhoami();
|
|
70
|
+
const loginResult = await iframeClient.injectCredentialBundle(credentialBundle);
|
|
71
|
+
// If there is no session, we want to force a refresh to enable to browser SDK to handle key storage and proper session management.
|
|
72
|
+
await iframeClient.refreshSession({
|
|
73
|
+
sessionType: sdk_browser_1.SessionType.READ_WRITE,
|
|
74
|
+
targetPublicKey: iframeClient.iframePublicKey,
|
|
75
|
+
expirationSeconds: this.metadata.expirationSeconds,
|
|
76
|
+
});
|
|
77
|
+
const [session, user] = await Promise.all([
|
|
78
|
+
turnkey.getSession(),
|
|
79
|
+
iframeClient.getWhoami(),
|
|
80
|
+
]);
|
|
70
81
|
const actualOrganizationId = user?.organizationId || session?.organizationId || organizationId;
|
|
71
|
-
if (!
|
|
82
|
+
if (!loginResult) {
|
|
72
83
|
return {
|
|
73
84
|
session: undefined,
|
|
74
85
|
organizationId: actualOrganizationId,
|
|
75
86
|
};
|
|
76
87
|
}
|
|
77
|
-
this.userOrganizationId = actualOrganizationId;
|
|
78
88
|
return {
|
|
79
89
|
session,
|
|
80
90
|
organizationId: actualOrganizationId,
|
|
@@ -85,17 +95,17 @@ class TurnkeyWallet {
|
|
|
85
95
|
}
|
|
86
96
|
}
|
|
87
97
|
async getAccounts() {
|
|
88
|
-
const
|
|
89
|
-
if (!this.
|
|
98
|
+
const iframeClient = await this.getIframeClient();
|
|
99
|
+
if (!this.organizationId) {
|
|
90
100
|
return [];
|
|
91
101
|
}
|
|
92
102
|
try {
|
|
93
|
-
const response = await
|
|
94
|
-
organizationId: this.
|
|
103
|
+
const response = await iframeClient.getWallets({
|
|
104
|
+
organizationId: this.organizationId,
|
|
95
105
|
});
|
|
96
|
-
const accounts = await Promise.allSettled(response.wallets.map((wallet) =>
|
|
106
|
+
const accounts = await Promise.allSettled(response.wallets.map((wallet) => iframeClient.getWalletAccounts({
|
|
97
107
|
walletId: wallet.walletId,
|
|
98
|
-
organizationId: this.
|
|
108
|
+
organizationId: this.organizationId,
|
|
99
109
|
})));
|
|
100
110
|
const filteredAccounts = accounts
|
|
101
111
|
.filter((account) => account.status === 'fulfilled')
|
|
@@ -121,33 +131,61 @@ class TurnkeyWallet {
|
|
|
121
131
|
});
|
|
122
132
|
}
|
|
123
133
|
}
|
|
124
|
-
async getOrCreateAndGetAccount(address) {
|
|
134
|
+
async getOrCreateAndGetAccount(address, organizationId) {
|
|
125
135
|
const { accountMap } = this;
|
|
126
|
-
const
|
|
127
|
-
const organizationId = this.userOrganizationId;
|
|
136
|
+
const iframeClient = await this.getIframeClient();
|
|
128
137
|
if (accountMap[address] || accountMap[address.toLowerCase()]) {
|
|
129
138
|
return accountMap[address] || accountMap[address.toLowerCase()];
|
|
130
139
|
}
|
|
131
140
|
if (!organizationId) {
|
|
132
141
|
throw new exceptions_1.WalletException(new Error('Organization ID is required'));
|
|
133
142
|
}
|
|
134
|
-
|
|
143
|
+
iframeClient.config.organizationId = organizationId;
|
|
135
144
|
if (!address) {
|
|
136
145
|
throw new exceptions_1.WalletException(new Error('Account address not found'));
|
|
137
146
|
}
|
|
138
147
|
const turnkeyAccount = await (0, viem_1.createAccount)({
|
|
139
148
|
organizationId,
|
|
140
149
|
signWith: address,
|
|
141
|
-
client:
|
|
150
|
+
client: iframeClient,
|
|
142
151
|
});
|
|
143
152
|
this.accountMap[address] = turnkeyAccount;
|
|
144
153
|
return turnkeyAccount;
|
|
145
154
|
}
|
|
155
|
+
async injectAndRefresh(credentialBundle, options) {
|
|
156
|
+
const expirationSeconds = options.expirationSeconds || consts_js_1.DEFAULT_TURNKEY_REFRESH_SECONDS;
|
|
157
|
+
const iframeClient = await this.getIframeClient();
|
|
158
|
+
await iframeClient.injectCredentialBundle(credentialBundle);
|
|
159
|
+
await iframeClient.loginWithBundle({
|
|
160
|
+
bundle: credentialBundle,
|
|
161
|
+
expirationSeconds,
|
|
162
|
+
});
|
|
163
|
+
await iframeClient.refreshSession({
|
|
164
|
+
sessionType: sdk_browser_1.SessionType.READ_WRITE,
|
|
165
|
+
targetPublicKey: iframeClient.iframePublicKey,
|
|
166
|
+
expirationSeconds,
|
|
167
|
+
});
|
|
168
|
+
const session = await this.turnkey?.getSession();
|
|
169
|
+
if (!session) {
|
|
170
|
+
throw new exceptions_1.TurnkeyWalletSessionException(new Error('Session expired. Please login again.'));
|
|
171
|
+
}
|
|
172
|
+
this.organizationId = session.organizationId;
|
|
173
|
+
this.metadata.organizationId = session.organizationId;
|
|
174
|
+
// Refresh the session 2 minutes before it expires
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
iframeClient.refreshSession({
|
|
177
|
+
expirationSeconds: session?.expiry,
|
|
178
|
+
sessionType: sdk_browser_1.SessionType.READ_WRITE,
|
|
179
|
+
targetPublicKey: iframeClient.iframePublicKey,
|
|
180
|
+
});
|
|
181
|
+
}, (parseInt(expirationSeconds) - 120) * 1000);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
146
184
|
async initOTP(email) {
|
|
147
|
-
const
|
|
185
|
+
const iframeClient = await this.getIframeClient();
|
|
148
186
|
const result = await otp_js_1.TurnkeyOtpWallet.initEmailOTP({
|
|
149
187
|
client: this.client,
|
|
150
|
-
|
|
188
|
+
iframeClient,
|
|
151
189
|
email,
|
|
152
190
|
otpInitPath: this.metadata.otpInitPath || consts_js_1.TURNKEY_OTP_INIT_PATH,
|
|
153
191
|
});
|
|
@@ -155,7 +193,7 @@ class TurnkeyWallet {
|
|
|
155
193
|
throw new exceptions_1.WalletException(new Error('Failed to initialize OTP'));
|
|
156
194
|
}
|
|
157
195
|
if (result?.organizationId) {
|
|
158
|
-
this.
|
|
196
|
+
this.organizationId = result.organizationId;
|
|
159
197
|
}
|
|
160
198
|
if (result?.otpId) {
|
|
161
199
|
this.otpId = result.otpId;
|
|
@@ -163,35 +201,30 @@ class TurnkeyWallet {
|
|
|
163
201
|
return result;
|
|
164
202
|
}
|
|
165
203
|
async confirmOTP(otpCode) {
|
|
166
|
-
const
|
|
167
|
-
const targetPublicKey = await indexedDbClient.getPublicKey();
|
|
204
|
+
const iframeClient = await this.getIframeClient();
|
|
168
205
|
if (!this.otpId) {
|
|
169
206
|
throw new exceptions_1.WalletException(new Error('OTP ID is required'));
|
|
170
207
|
}
|
|
171
|
-
if (!targetPublicKey) {
|
|
172
|
-
throw new exceptions_1.WalletException(new Error('Target public key not found'));
|
|
173
|
-
}
|
|
174
|
-
if (!this.userOrganizationId) {
|
|
175
|
-
throw new exceptions_1.WalletException(new Error('Organization ID is required'));
|
|
176
|
-
}
|
|
177
208
|
const result = await otp_js_1.TurnkeyOtpWallet.confirmEmailOTP({
|
|
178
209
|
otpCode,
|
|
210
|
+
iframeClient,
|
|
179
211
|
client: this.client,
|
|
180
212
|
emailOTPId: this.otpId,
|
|
181
|
-
organizationId: this.
|
|
182
|
-
targetPublicKey,
|
|
213
|
+
organizationId: this.organizationId,
|
|
183
214
|
otpVerifyPath: this.metadata.otpVerifyPath || consts_js_1.TURNKEY_OTP_VERIFY_PATH,
|
|
184
215
|
});
|
|
185
|
-
if (!result || !result.
|
|
216
|
+
if (!result || !result.credentialBundle) {
|
|
186
217
|
throw new exceptions_1.WalletException(new Error('Failed to confirm OTP'));
|
|
187
218
|
}
|
|
188
|
-
await
|
|
189
|
-
|
|
219
|
+
await this.injectAndRefresh(result.credentialBundle, {
|
|
220
|
+
organizationId: result.organizationId,
|
|
221
|
+
expirationSeconds: this.metadata.expirationSeconds,
|
|
222
|
+
});
|
|
190
223
|
return result;
|
|
191
224
|
}
|
|
192
225
|
async initOAuth(provider) {
|
|
193
|
-
const
|
|
194
|
-
const nonce = await oauth_js_1.TurnkeyOauthWallet.generateOAuthNonce(
|
|
226
|
+
const iframeClient = await this.getIframeClient();
|
|
227
|
+
const nonce = await oauth_js_1.TurnkeyOauthWallet.generateOAuthNonce(iframeClient);
|
|
195
228
|
if (provider === wallet_base_1.TurnkeyProvider.Apple) {
|
|
196
229
|
// TODO: implement the ability to generate Apple OAuth URL
|
|
197
230
|
return nonce;
|
|
@@ -206,10 +239,10 @@ class TurnkeyWallet {
|
|
|
206
239
|
});
|
|
207
240
|
}
|
|
208
241
|
async confirmOAuth(provider, oidcToken) {
|
|
209
|
-
const
|
|
242
|
+
const iframeClient = await this.getIframeClient();
|
|
210
243
|
const oauthResult = await oauth_js_1.TurnkeyOauthWallet.oauthLogin({
|
|
211
244
|
oidcToken,
|
|
212
|
-
|
|
245
|
+
iframeClient,
|
|
213
246
|
client: this.client,
|
|
214
247
|
providerName: provider.toString(),
|
|
215
248
|
oauthLoginPath: this.metadata.oauthLoginPath || consts_js_1.TURNKEY_OAUTH_PATH,
|
|
@@ -217,41 +250,54 @@ class TurnkeyWallet {
|
|
|
217
250
|
if (!oauthResult || !oauthResult.credentialBundle) {
|
|
218
251
|
throw new exceptions_1.WalletException(new Error('Unexpected OAuth result'));
|
|
219
252
|
}
|
|
220
|
-
await
|
|
221
|
-
|
|
253
|
+
await this.injectAndRefresh(oauthResult.credentialBundle, {
|
|
254
|
+
organizationId: oauthResult.organizationId,
|
|
255
|
+
expirationSeconds: this.metadata.expirationSeconds,
|
|
256
|
+
});
|
|
222
257
|
return oauthResult.credentialBundle;
|
|
223
258
|
}
|
|
224
259
|
async refreshSession() {
|
|
225
260
|
const session = await this.getSession();
|
|
226
|
-
const indexedDbClient = await this.getIndexedDbClient();
|
|
227
261
|
if (session.session?.token) {
|
|
228
|
-
await
|
|
229
|
-
|
|
230
|
-
expirationSeconds: this.metadata.expirationSeconds,
|
|
262
|
+
await this.injectAndRefresh(session.session.token, {
|
|
263
|
+
expirationSeconds: this.metadata.expirationSeconds || consts_js_1.DEFAULT_TURNKEY_REFRESH_SECONDS,
|
|
231
264
|
});
|
|
232
|
-
this.userOrganizationId = session.organizationId;
|
|
233
265
|
return session.session.token;
|
|
234
266
|
}
|
|
235
267
|
throw new exceptions_1.TurnkeyWalletSessionException(new Error('Session expired. Please login again.'));
|
|
236
268
|
}
|
|
237
|
-
async
|
|
269
|
+
async initFrame() {
|
|
238
270
|
const { metadata } = this;
|
|
239
|
-
const { turnkey,
|
|
271
|
+
const { turnkey, iframeClient } = await createTurnkeyIFrame(metadata);
|
|
240
272
|
this.turnkey = turnkey;
|
|
241
|
-
this.
|
|
242
|
-
return { turnkey, indexedDbClient };
|
|
273
|
+
this.iframeClient = iframeClient;
|
|
243
274
|
}
|
|
244
275
|
}
|
|
245
276
|
exports.TurnkeyWallet = TurnkeyWallet;
|
|
246
|
-
async function
|
|
277
|
+
async function createTurnkeyIFrame(metadata) {
|
|
247
278
|
const turnkey = new sdk_browser_1.Turnkey(metadata);
|
|
248
|
-
const
|
|
249
|
-
|
|
279
|
+
const turnkeyAuthIframeElementId = metadata.iframeElementId || 'turnkey-auth-iframe-element-id';
|
|
280
|
+
if (!metadata.iframeContainerId) {
|
|
281
|
+
throw new exceptions_1.GeneralException(new Error('iframeContainerId is required'));
|
|
282
|
+
}
|
|
250
283
|
if (!turnkey) {
|
|
251
284
|
throw new exceptions_1.GeneralException(new Error('Turnkey is not initialized'));
|
|
252
285
|
}
|
|
286
|
+
const iframe = document.getElementById(metadata.iframeContainerId);
|
|
287
|
+
if (!iframe) {
|
|
288
|
+
throw new exceptions_1.GeneralException(new Error('iframe is null'));
|
|
289
|
+
}
|
|
290
|
+
const existingIframeClient = document.getElementById(turnkeyAuthIframeElementId);
|
|
291
|
+
if (existingIframeClient) {
|
|
292
|
+
existingIframeClient.remove();
|
|
293
|
+
}
|
|
294
|
+
const iframeClient = await turnkey.iframeClient({
|
|
295
|
+
iframeContainer: iframe,
|
|
296
|
+
iframeElementId: turnkeyAuthIframeElementId,
|
|
297
|
+
iframeUrl: metadata?.iframeUrl || 'https://auth.turnkey.com',
|
|
298
|
+
});
|
|
253
299
|
return {
|
|
254
300
|
turnkey,
|
|
255
|
-
|
|
301
|
+
iframeClient,
|
|
256
302
|
};
|
|
257
303
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { TxRaw, AminoSignResponse, DirectSignResponse } from '@injectivelabs/sdk-ts';
|
|
2
|
-
import { StdSignDoc, WalletDeviceType, type WalletMetadata, BaseConcreteStrategy, ConcreteWalletStrategy, SendTransactionOptions, WalletStrategyEvmOptions, ConcreteEvmWalletStrategyArgs } from '@injectivelabs/wallet-base';
|
|
3
2
|
import { HttpRestClient } from '@injectivelabs/utils';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { AccountAddress, EthereumChainId } from '@injectivelabs/ts-types';
|
|
4
|
+
import { TurnkeyIframeClient } from '@turnkey/sdk-browser';
|
|
5
|
+
import { StdSignDoc, WalletDeviceType, type WalletMetadata, BaseConcreteStrategy, ConcreteWalletStrategy, SendTransactionOptions, WalletStrategyEthereumOptions, ConcreteEthereumWalletStrategyArgs } from '@injectivelabs/wallet-base';
|
|
6
6
|
import { TurnkeyWallet } from './turnkey/turnkey.js';
|
|
7
7
|
export declare class TurnkeyWalletStrategy extends BaseConcreteStrategy implements ConcreteWalletStrategy {
|
|
8
8
|
turnkeyWallet?: TurnkeyWallet;
|
|
9
|
-
|
|
9
|
+
ethereumOptions: WalletStrategyEthereumOptions;
|
|
10
10
|
client: HttpRestClient;
|
|
11
|
-
constructor(args:
|
|
11
|
+
constructor(args: ConcreteEthereumWalletStrategyArgs & {
|
|
12
12
|
apiServerEndpoint?: string;
|
|
13
13
|
});
|
|
14
14
|
getWalletDeviceType(): Promise<WalletDeviceType>;
|
|
@@ -22,7 +22,7 @@ export declare class TurnkeyWalletStrategy extends BaseConcreteStrategy implemen
|
|
|
22
22
|
getWalletClient<TurnkeyWallet>(): Promise<TurnkeyWallet>;
|
|
23
23
|
sendEvmTransaction(transaction: unknown, args: {
|
|
24
24
|
address: AccountAddress;
|
|
25
|
-
|
|
25
|
+
ethereumChainId: EthereumChainId;
|
|
26
26
|
}): Promise<string>;
|
|
27
27
|
sendTransaction(transaction: TxRaw, options: SendTransactionOptions): Promise<any>;
|
|
28
28
|
signEip712TypedData(eip712json: string, address: AccountAddress): Promise<string>;
|
|
@@ -38,8 +38,9 @@ export declare class TurnkeyWalletStrategy extends BaseConcreteStrategy implemen
|
|
|
38
38
|
}): Promise<AminoSignResponse>;
|
|
39
39
|
signArbitrary(_signer: AccountAddress, _data: string | Uint8Array): Promise<string>;
|
|
40
40
|
getEthereumChainId(): Promise<string>;
|
|
41
|
-
getEvmTransactionReceipt(txHash: string,
|
|
41
|
+
getEvmTransactionReceipt(txHash: string, ethereumChainId?: EthereumChainId): Promise<Record<string, any>>;
|
|
42
42
|
getPubKey(): Promise<string>;
|
|
43
|
-
|
|
43
|
+
getIframeClient(): Promise<TurnkeyIframeClient>;
|
|
44
44
|
private getTurnkeyWallet;
|
|
45
|
+
private getOrganizationId;
|
|
45
46
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/* eslint-disable class-methods-use-this */
|
|
2
2
|
import { TxGrpcApi, } from '@injectivelabs/sdk-ts';
|
|
3
3
|
import { ErrorType, WalletException, UnspecifiedErrorCode, TransactionException, CosmosWalletException, } from '@injectivelabs/exceptions';
|
|
4
|
-
import {
|
|
5
|
-
import { WalletAction, WalletDeviceType, BaseConcreteStrategy, } from '@injectivelabs/wallet-base';
|
|
4
|
+
import { getAddress } from 'viem';
|
|
6
5
|
import { sleep, HttpRestClient } from '@injectivelabs/utils';
|
|
6
|
+
import { http, createPublicClient, createWalletClient, } from 'viem';
|
|
7
|
+
import { WalletAction, WalletDeviceType, BaseConcreteStrategy, } from '@injectivelabs/wallet-base';
|
|
7
8
|
import { TurnkeyErrorCodes } from './types.js';
|
|
8
9
|
import { TurnkeyWallet } from './turnkey/turnkey.js';
|
|
9
10
|
import { DEFAULT_EVM_CHAIN_CONFIG } from './consts.js';
|
|
10
11
|
export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
11
12
|
turnkeyWallet;
|
|
12
|
-
|
|
13
|
+
ethereumOptions;
|
|
13
14
|
client;
|
|
14
15
|
constructor(args) {
|
|
15
16
|
super(args);
|
|
@@ -18,7 +19,7 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
18
19
|
throw new WalletException(new Error('apiServerEndpoint is required'));
|
|
19
20
|
}
|
|
20
21
|
this.client = new HttpRestClient(endpoint);
|
|
21
|
-
this.
|
|
22
|
+
this.ethereumOptions = args.ethereumOptions;
|
|
22
23
|
}
|
|
23
24
|
async getWalletDeviceType() {
|
|
24
25
|
return Promise.resolve(WalletDeviceType.Browser);
|
|
@@ -46,7 +47,7 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
46
47
|
}
|
|
47
48
|
return true;
|
|
48
49
|
}
|
|
49
|
-
return !!(await turnkeyWallet.
|
|
50
|
+
return !!(await turnkeyWallet.getIframeClient());
|
|
50
51
|
}
|
|
51
52
|
catch (e) {
|
|
52
53
|
return false;
|
|
@@ -55,15 +56,15 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
55
56
|
async disconnect() {
|
|
56
57
|
const turnkeyWallet = await this.getTurnkeyWallet();
|
|
57
58
|
const turnkey = await turnkeyWallet.getTurnkey();
|
|
58
|
-
const indexedDbClient = await turnkeyWallet.getIndexedDbClient();
|
|
59
59
|
const isUserLoggedIn = await turnkey.getSession();
|
|
60
60
|
if (!isUserLoggedIn) {
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
await
|
|
63
|
+
await turnkey.logout();
|
|
64
64
|
}
|
|
65
65
|
async getAddresses() {
|
|
66
66
|
const turnkeyWallet = await this.getTurnkeyWallet();
|
|
67
|
+
await turnkeyWallet.getSession();
|
|
67
68
|
try {
|
|
68
69
|
return await turnkeyWallet.getAccounts();
|
|
69
70
|
}
|
|
@@ -88,17 +89,18 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
88
89
|
}
|
|
89
90
|
async sendEvmTransaction(transaction, args) {
|
|
90
91
|
try {
|
|
91
|
-
const options = this.
|
|
92
|
+
const options = this.ethereumOptions;
|
|
92
93
|
const turnkeyWallet = await this.getTurnkeyWallet();
|
|
93
|
-
const
|
|
94
|
-
const
|
|
94
|
+
const organizationId = await this.getOrganizationId();
|
|
95
|
+
const chainId = args.ethereumChainId || options.ethereumChainId;
|
|
96
|
+
const url = options.rpcUrl || options.rpcUrls?.[args.ethereumChainId];
|
|
95
97
|
if (!url) {
|
|
96
|
-
throw new WalletException(new Error('Please pass rpcUrl within the
|
|
98
|
+
throw new WalletException(new Error('Please pass rpcUrl within the ethereumOptions'), {
|
|
97
99
|
code: UnspecifiedErrorCode,
|
|
98
100
|
context: WalletAction.SendEvmTransaction,
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
|
-
const account = await turnkeyWallet.getOrCreateAndGetAccount(getAddress(args.address));
|
|
103
|
+
const account = await turnkeyWallet.getOrCreateAndGetAccount(getAddress(args.address), organizationId);
|
|
102
104
|
const accountClient = createWalletClient({
|
|
103
105
|
account: account,
|
|
104
106
|
chain: {
|
|
@@ -145,9 +147,10 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
145
147
|
}
|
|
146
148
|
async signEip712TypedData(eip712json, address) {
|
|
147
149
|
const turnkeyWallet = await this.getTurnkeyWallet();
|
|
150
|
+
const organizationId = await this.getOrganizationId();
|
|
148
151
|
//? Turnkey expects the case sensitive address and the current impl of getChecksumAddress from sdk-ts doesn't play nice with browser envs
|
|
149
152
|
const checksumAddress = getAddress(address);
|
|
150
|
-
const account = await turnkeyWallet.getOrCreateAndGetAccount(checksumAddress);
|
|
153
|
+
const account = await turnkeyWallet.getOrCreateAndGetAccount(checksumAddress, organizationId);
|
|
151
154
|
if (!account) {
|
|
152
155
|
throw new WalletException(new Error('Turnkey account not found'));
|
|
153
156
|
}
|
|
@@ -193,14 +196,14 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
193
196
|
context: WalletAction.GetChainId,
|
|
194
197
|
});
|
|
195
198
|
}
|
|
196
|
-
async getEvmTransactionReceipt(txHash,
|
|
197
|
-
const options = this.
|
|
199
|
+
async getEvmTransactionReceipt(txHash, ethereumChainId) {
|
|
200
|
+
const options = this.ethereumOptions;
|
|
198
201
|
const maxAttempts = 10;
|
|
199
202
|
const interval = 3000;
|
|
200
|
-
const chainId =
|
|
203
|
+
const chainId = ethereumChainId || options.ethereumChainId;
|
|
201
204
|
const url = options.rpcUrl || options.rpcUrls?.[chainId];
|
|
202
205
|
if (!url) {
|
|
203
|
-
throw new WalletException(new Error('Please pass rpcUrl within the
|
|
206
|
+
throw new WalletException(new Error('Please pass rpcUrl within the ethereumOptions'), {
|
|
204
207
|
code: UnspecifiedErrorCode,
|
|
205
208
|
context: WalletAction.GetEvmTransactionReceipt,
|
|
206
209
|
});
|
|
@@ -237,10 +240,9 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
237
240
|
async getPubKey() {
|
|
238
241
|
throw new WalletException(new Error('You can only fetch PubKey from Cosmos native wallets'));
|
|
239
242
|
}
|
|
240
|
-
async
|
|
243
|
+
async getIframeClient() {
|
|
241
244
|
const turnkeyWallet = await this.getTurnkeyWallet();
|
|
242
|
-
|
|
243
|
-
return indexedDbClient;
|
|
245
|
+
return turnkeyWallet.getIframeClient();
|
|
244
246
|
}
|
|
245
247
|
async getTurnkeyWallet() {
|
|
246
248
|
const { metadata } = this;
|
|
@@ -254,8 +256,20 @@ export class TurnkeyWalletStrategy extends BaseConcreteStrategy {
|
|
|
254
256
|
if (!metadata.turnkey.apiServerEndpoint) {
|
|
255
257
|
throw new WalletException(new Error('Turnkey apiServerEndpoint is required'));
|
|
256
258
|
}
|
|
259
|
+
if (!metadata.turnkey.defaultOrganizationId) {
|
|
260
|
+
throw new WalletException(new Error('Turnkey defaultOrganizationId is required'));
|
|
261
|
+
}
|
|
257
262
|
this.turnkeyWallet = new TurnkeyWallet(metadata.turnkey);
|
|
258
263
|
}
|
|
259
264
|
return this.turnkeyWallet;
|
|
260
265
|
}
|
|
266
|
+
async getOrganizationId() {
|
|
267
|
+
const { metadata } = this;
|
|
268
|
+
const organizationId = metadata?.turnkey?.organizationId ||
|
|
269
|
+
metadata?.turnkey?.defaultOrganizationId;
|
|
270
|
+
if (!organizationId) {
|
|
271
|
+
throw new WalletException(new Error('Organization ID is required'));
|
|
272
|
+
}
|
|
273
|
+
return organizationId;
|
|
274
|
+
}
|
|
261
275
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TurnkeyIframeClient } from '@turnkey/sdk-browser';
|
|
2
2
|
import { type HttpRestClient } from '@injectivelabs/utils';
|
|
3
3
|
export declare class TurnkeyOauthWallet {
|
|
4
|
-
static generateOAuthNonce(
|
|
4
|
+
static generateOAuthNonce(iframeClient: TurnkeyIframeClient): Promise<string>;
|
|
5
5
|
static oauthLogin(args: {
|
|
6
6
|
oidcToken: string;
|
|
7
7
|
client: HttpRestClient;
|
|
8
8
|
oauthLoginPath?: string;
|
|
9
9
|
providerName: 'google' | 'apple';
|
|
10
|
-
|
|
10
|
+
iframeClient: TurnkeyIframeClient;
|
|
11
11
|
expirationSeconds?: number;
|
|
12
12
|
}): Promise<{
|
|
13
13
|
organizationId: string;
|
|
@@ -2,10 +2,9 @@ import { ErrorType, WalletException, UnspecifiedErrorCode, } from '@injectivelab
|
|
|
2
2
|
import { sha256 } from '@injectivelabs/sdk-ts';
|
|
3
3
|
import { DEFAULT_TURNKEY_REFRESH_SECONDS, TURNKEY_OAUTH_PATH, } from '../consts.js';
|
|
4
4
|
export class TurnkeyOauthWallet {
|
|
5
|
-
static async generateOAuthNonce(
|
|
5
|
+
static async generateOAuthNonce(iframeClient) {
|
|
6
6
|
try {
|
|
7
|
-
|
|
8
|
-
const targetPublicKey = await indexedDbClient.getPublicKey();
|
|
7
|
+
const targetPublicKey = iframeClient.iframePublicKey;
|
|
9
8
|
if (!targetPublicKey) {
|
|
10
9
|
throw new WalletException(new Error('Target public key not found'));
|
|
11
10
|
}
|
|
@@ -22,10 +21,10 @@ export class TurnkeyOauthWallet {
|
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
static async oauthLogin(args) {
|
|
25
|
-
const { client,
|
|
24
|
+
const { client, iframeClient, expirationSeconds } = args;
|
|
26
25
|
const path = args.oauthLoginPath || TURNKEY_OAUTH_PATH;
|
|
27
26
|
try {
|
|
28
|
-
const targetPublicKey =
|
|
27
|
+
const targetPublicKey = iframeClient.iframePublicKey;
|
|
29
28
|
if (!targetPublicKey) {
|
|
30
29
|
throw new WalletException(new Error('Target public key not found'));
|
|
31
30
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type TurnkeyIframeClient } from '@turnkey/sdk-browser';
|
|
2
2
|
import { type TurnkeyConfirmEmailOTPResponse, type TurnkeyOTPCredentialsResponse } from './../types.js';
|
|
3
3
|
import { type HttpRestClient } from '@injectivelabs/utils';
|
|
4
4
|
export declare class TurnkeyOtpWallet {
|
|
@@ -7,16 +7,15 @@ export declare class TurnkeyOtpWallet {
|
|
|
7
7
|
subOrgId?: string;
|
|
8
8
|
otpInitPath?: string;
|
|
9
9
|
client: HttpRestClient;
|
|
10
|
-
|
|
10
|
+
iframeClient: TurnkeyIframeClient;
|
|
11
11
|
invalidateExistingSessions?: boolean;
|
|
12
|
-
expirationSeconds?: number;
|
|
13
12
|
}): Promise<TurnkeyOTPCredentialsResponse | undefined>;
|
|
14
13
|
static confirmEmailOTP(args: {
|
|
15
14
|
otpCode: string;
|
|
16
15
|
emailOTPId: string;
|
|
17
16
|
client: HttpRestClient;
|
|
18
|
-
targetPublicKey: string;
|
|
19
17
|
organizationId: string;
|
|
18
|
+
iframeClient: TurnkeyIframeClient;
|
|
20
19
|
otpVerifyPath?: string;
|
|
21
20
|
expirationSeconds?: number;
|
|
22
21
|
}): Promise<TurnkeyConfirmEmailOTPResponse | undefined>;
|
|
@@ -2,21 +2,18 @@ import { ErrorType, WalletException, UnspecifiedErrorCode, } from '@injectivelab
|
|
|
2
2
|
import { DEFAULT_TURNKEY_REFRESH_SECONDS, TURNKEY_OTP_INIT_PATH, TURNKEY_OTP_VERIFY_PATH, } from '../consts.js';
|
|
3
3
|
export class TurnkeyOtpWallet {
|
|
4
4
|
static async initEmailOTP(args) {
|
|
5
|
-
const { client,
|
|
5
|
+
const { client, iframeClient } = args;
|
|
6
6
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
throw new WalletException(new Error('Public key not found'));
|
|
7
|
+
const targetPublicKey = iframeClient.iframePublicKey;
|
|
8
|
+
if (!targetPublicKey) {
|
|
9
|
+
throw new WalletException(new Error('Target public key not found'));
|
|
11
10
|
}
|
|
12
11
|
// client.$post is undefined, resorting to this for now
|
|
13
12
|
const response = await client.post(args.otpInitPath || TURNKEY_OTP_INIT_PATH, {
|
|
14
|
-
targetPublicKey
|
|
13
|
+
targetPublicKey,
|
|
15
14
|
email: args.email,
|
|
16
15
|
suborgId: args.subOrgId,
|
|
17
16
|
invalidateExistingSessions: args.invalidateExistingSessions,
|
|
18
|
-
isUsingIndexedDB: true,
|
|
19
|
-
expirationSeconds: expirationSeconds || DEFAULT_TURNKEY_REFRESH_SECONDS,
|
|
20
17
|
});
|
|
21
18
|
return response?.data;
|
|
22
19
|
}
|
|
@@ -29,11 +26,15 @@ export class TurnkeyOtpWallet {
|
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
28
|
static async confirmEmailOTP(args) {
|
|
32
|
-
const { client,
|
|
29
|
+
const { client, iframeClient, expirationSeconds } = args;
|
|
33
30
|
try {
|
|
34
31
|
const organizationId = args.organizationId;
|
|
35
32
|
const emailOTPId = args.emailOTPId;
|
|
33
|
+
const targetPublicKey = iframeClient.iframePublicKey;
|
|
36
34
|
const otpVerifyPath = args.otpVerifyPath || TURNKEY_OTP_VERIFY_PATH;
|
|
35
|
+
if (!targetPublicKey) {
|
|
36
|
+
throw new WalletException(new Error('Target public key not found'));
|
|
37
|
+
}
|
|
37
38
|
if (!emailOTPId) {
|
|
38
39
|
throw new WalletException(new Error('Email OTP ID is required'));
|
|
39
40
|
}
|
|
@@ -41,7 +42,6 @@ export class TurnkeyOtpWallet {
|
|
|
41
42
|
throw new WalletException(new Error('Organization ID is required'));
|
|
42
43
|
}
|
|
43
44
|
const response = await client.post(otpVerifyPath, {
|
|
44
|
-
isUsingIndexedDB: true,
|
|
45
45
|
targetPublicKey,
|
|
46
46
|
otpId: emailOTPId,
|
|
47
47
|
otpCode: args.otpCode,
|