@phantom/react-native-sdk 0.1.0 → 0.1.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/dist/index.d.ts +5 -4
- package/dist/index.js +177 -16
- package/dist/index.mjs +177 -16
- package/package.json +11 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
|
|
4
|
-
import { EmbeddedProviderConfig, AuthOptions, EmbeddedProvider, WalletAddress, ConnectResult, SignMessageParams, SignAndSendTransactionParams, SignedTransaction } from '@phantom/embedded-provider-core';
|
|
5
|
-
export { ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
6
|
-
export { AddressType
|
|
4
|
+
import { EmbeddedProviderConfig, AuthOptions, EmbeddedProvider, WalletAddress, ConnectResult, SignMessageParams, SignMessageResult, SignAndSendTransactionParams, SignedTransaction } from '@phantom/embedded-provider-core';
|
|
5
|
+
export { ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
6
|
+
export { AddressType } from '@phantom/client';
|
|
7
|
+
export { NetworkId } from '@phantom/constants';
|
|
7
8
|
|
|
8
9
|
interface PhantomProviderConfig extends Omit<EmbeddedProviderConfig, "authOptions"> {
|
|
9
10
|
/** Custom URL scheme for your app (e.g., "myapp") */
|
|
@@ -66,7 +67,7 @@ declare function useAccounts(): {
|
|
|
66
67
|
};
|
|
67
68
|
|
|
68
69
|
declare function useSignMessage(): {
|
|
69
|
-
signMessage: (params: SignMessageParams) => Promise<
|
|
70
|
+
signMessage: (params: SignMessageParams) => Promise<SignMessageResult>;
|
|
70
71
|
isSigning: boolean;
|
|
71
72
|
error: Error | null;
|
|
72
73
|
};
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AddressType: () => import_client.AddressType,
|
|
34
|
-
NetworkId: () =>
|
|
34
|
+
NetworkId: () => import_constants.NetworkId,
|
|
35
35
|
PhantomProvider: () => PhantomProvider,
|
|
36
36
|
useAccounts: () => useAccounts,
|
|
37
37
|
useConnect: () => useConnect,
|
|
@@ -96,22 +96,52 @@ var ExpoSecureStorage = class {
|
|
|
96
96
|
|
|
97
97
|
// src/providers/embedded/auth.ts
|
|
98
98
|
var WebBrowser = __toESM(require("expo-web-browser"));
|
|
99
|
+
var DEFAULT_AUTH_URL = "https://auth.phantom.app";
|
|
99
100
|
var ExpoAuthProvider = class {
|
|
100
101
|
async authenticate(options) {
|
|
101
102
|
if ("jwtToken" in options) {
|
|
102
103
|
return;
|
|
103
104
|
}
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const phantomOptions = options;
|
|
106
|
+
const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData } = phantomOptions;
|
|
107
|
+
if (!redirectUrl) {
|
|
108
|
+
throw new Error("redirectUrl is required for web browser authentication");
|
|
109
|
+
}
|
|
110
|
+
if (!organizationId || !sessionId) {
|
|
111
|
+
throw new Error("organizationId and sessionId are required for authentication");
|
|
107
112
|
}
|
|
108
113
|
try {
|
|
114
|
+
const baseUrl = authUrl || DEFAULT_AUTH_URL;
|
|
115
|
+
const params = new URLSearchParams({
|
|
116
|
+
organization_id: organizationId,
|
|
117
|
+
parent_organization_id: parentOrganizationId,
|
|
118
|
+
redirect_uri: redirectUrl,
|
|
119
|
+
session_id: sessionId,
|
|
120
|
+
clear_previous_session: "true"
|
|
121
|
+
});
|
|
122
|
+
if (provider) {
|
|
123
|
+
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
124
|
+
params.append("provider", provider);
|
|
125
|
+
} else {
|
|
126
|
+
console.log("[ExpoAuthProvider] No provider specified, defaulting to Google");
|
|
127
|
+
params.append("provider", "google");
|
|
128
|
+
}
|
|
129
|
+
if (customAuthData) {
|
|
130
|
+
console.log("[ExpoAuthProvider] Adding custom auth data");
|
|
131
|
+
params.append("authData", JSON.stringify(customAuthData));
|
|
132
|
+
}
|
|
133
|
+
const fullAuthUrl = `${baseUrl}?${params.toString()}`;
|
|
109
134
|
console.log("[ExpoAuthProvider] Starting authentication", {
|
|
110
|
-
|
|
111
|
-
redirectUrl
|
|
135
|
+
baseUrl,
|
|
136
|
+
redirectUrl,
|
|
137
|
+
organizationId,
|
|
138
|
+
parentOrganizationId,
|
|
139
|
+
sessionId,
|
|
140
|
+
provider,
|
|
141
|
+
hasCustomData: !!customAuthData
|
|
112
142
|
});
|
|
113
143
|
await WebBrowser.warmUpAsync();
|
|
114
|
-
const result = await WebBrowser.openAuthSessionAsync(
|
|
144
|
+
const result = await WebBrowser.openAuthSessionAsync(fullAuthUrl, redirectUrl, {
|
|
115
145
|
// Use system browser on iOS for ASWebAuthenticationSession
|
|
116
146
|
preferEphemeralSession: false
|
|
117
147
|
});
|
|
@@ -121,19 +151,14 @@ var ExpoAuthProvider = class {
|
|
|
121
151
|
});
|
|
122
152
|
if (result.type === "success" && result.url) {
|
|
123
153
|
const url = new URL(result.url);
|
|
124
|
-
const walletId = url.searchParams.get("
|
|
125
|
-
const
|
|
154
|
+
const walletId = url.searchParams.get("wallet_id");
|
|
155
|
+
const provider2 = url.searchParams.get("provider");
|
|
126
156
|
if (!walletId) {
|
|
127
157
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
128
158
|
}
|
|
129
|
-
const userInfo = {};
|
|
130
|
-
url.searchParams.forEach((value, key) => {
|
|
131
|
-
userInfo[key] = value;
|
|
132
|
-
});
|
|
133
159
|
return {
|
|
134
160
|
walletId,
|
|
135
|
-
provider:
|
|
136
|
-
userInfo
|
|
161
|
+
provider: provider2 || void 0
|
|
137
162
|
};
|
|
138
163
|
} else if (result.type === "cancel") {
|
|
139
164
|
throw new Error("User cancelled authentication");
|
|
@@ -247,7 +272,136 @@ var ExpoLogger = class {
|
|
|
247
272
|
}
|
|
248
273
|
};
|
|
249
274
|
|
|
275
|
+
// src/providers/embedded/stamper.ts
|
|
276
|
+
var SecureStore2 = __toESM(require("expo-secure-store"));
|
|
277
|
+
var import_api_key_stamper = require("@phantom/api-key-stamper");
|
|
278
|
+
var import_crypto = require("@phantom/crypto");
|
|
279
|
+
var import_base64url = require("@phantom/base64url");
|
|
280
|
+
var import_sdk_types = require("@phantom/sdk-types");
|
|
281
|
+
var ReactNativeStamper = class {
|
|
282
|
+
constructor(config = {}) {
|
|
283
|
+
this.keyInfo = null;
|
|
284
|
+
this.algorithm = import_sdk_types.Algorithm.ed25519;
|
|
285
|
+
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
286
|
+
this.organizationId = config.organizationId || "default";
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Initialize the stamper and generate/load cryptographic keys
|
|
290
|
+
*/
|
|
291
|
+
async init() {
|
|
292
|
+
const storedSecretKey = await this.getStoredSecretKey();
|
|
293
|
+
if (storedSecretKey) {
|
|
294
|
+
const keyInfo2 = await this.getStoredKeyInfo();
|
|
295
|
+
if (keyInfo2) {
|
|
296
|
+
this.keyInfo = keyInfo2;
|
|
297
|
+
return keyInfo2;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const keyInfo = await this.generateAndStoreKeyPair();
|
|
301
|
+
this.keyInfo = keyInfo;
|
|
302
|
+
return keyInfo;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get the current key information
|
|
306
|
+
*/
|
|
307
|
+
getKeyInfo() {
|
|
308
|
+
return this.keyInfo;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Generate and store a new key pair, replacing any existing keys
|
|
312
|
+
*/
|
|
313
|
+
async resetKeyPair() {
|
|
314
|
+
await this.clear();
|
|
315
|
+
const keyInfo = await this.generateAndStoreKeyPair();
|
|
316
|
+
this.keyInfo = keyInfo;
|
|
317
|
+
return keyInfo;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Create X-Phantom-Stamp header value using stored secret key
|
|
321
|
+
* @param data - Data to sign (Buffer)
|
|
322
|
+
* @returns Complete X-Phantom-Stamp header value
|
|
323
|
+
*/
|
|
324
|
+
async stamp({
|
|
325
|
+
data
|
|
326
|
+
}) {
|
|
327
|
+
if (!this.keyInfo) {
|
|
328
|
+
throw new Error("Stamper not initialized. Call init() first.");
|
|
329
|
+
}
|
|
330
|
+
const storedSecretKey = await this.getStoredSecretKey();
|
|
331
|
+
if (!storedSecretKey) {
|
|
332
|
+
throw new Error("Secret key not found in secure storage");
|
|
333
|
+
}
|
|
334
|
+
const apiKeyStamper = new import_api_key_stamper.ApiKeyStamper({ apiSecretKey: storedSecretKey });
|
|
335
|
+
return await apiKeyStamper.stamp({ data });
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Clear all stored keys from SecureStore
|
|
339
|
+
*/
|
|
340
|
+
async clear() {
|
|
341
|
+
const infoKey = this.getInfoKey();
|
|
342
|
+
const secretKey = this.getSecretKey();
|
|
343
|
+
try {
|
|
344
|
+
await SecureStore2.deleteItemAsync(infoKey);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
await SecureStore2.deleteItemAsync(secretKey);
|
|
349
|
+
} catch (error) {
|
|
350
|
+
}
|
|
351
|
+
this.keyInfo = null;
|
|
352
|
+
}
|
|
353
|
+
async generateAndStoreKeyPair() {
|
|
354
|
+
const keypair = (0, import_crypto.generateKeyPair)();
|
|
355
|
+
const keyId = this.createKeyId(keypair.publicKey);
|
|
356
|
+
const keyInfo = {
|
|
357
|
+
keyId,
|
|
358
|
+
publicKey: keypair.publicKey
|
|
359
|
+
};
|
|
360
|
+
await this.storeKeyPair(keypair.secretKey, keyInfo);
|
|
361
|
+
return keyInfo;
|
|
362
|
+
}
|
|
363
|
+
createKeyId(publicKey) {
|
|
364
|
+
return (0, import_base64url.base64urlEncode)(new TextEncoder().encode(publicKey)).substring(0, 16);
|
|
365
|
+
}
|
|
366
|
+
async storeKeyPair(secretKey, keyInfo) {
|
|
367
|
+
const infoKey = this.getInfoKey();
|
|
368
|
+
const secretKeyName = this.getSecretKey();
|
|
369
|
+
await SecureStore2.setItemAsync(infoKey, JSON.stringify(keyInfo), {
|
|
370
|
+
requireAuthentication: false
|
|
371
|
+
});
|
|
372
|
+
await SecureStore2.setItemAsync(secretKeyName, secretKey, {
|
|
373
|
+
requireAuthentication: false
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
async getStoredKeyInfo() {
|
|
377
|
+
try {
|
|
378
|
+
const infoKey = this.getInfoKey();
|
|
379
|
+
const storedInfo = await SecureStore2.getItemAsync(infoKey);
|
|
380
|
+
if (storedInfo) {
|
|
381
|
+
return JSON.parse(storedInfo);
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
}
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
async getStoredSecretKey() {
|
|
388
|
+
try {
|
|
389
|
+
const secretKeyName = this.getSecretKey();
|
|
390
|
+
return await SecureStore2.getItemAsync(secretKeyName);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
getInfoKey() {
|
|
396
|
+
return `${this.keyPrefix}-${this.organizationId}-info`;
|
|
397
|
+
}
|
|
398
|
+
getSecretKey() {
|
|
399
|
+
return `${this.keyPrefix}-${this.organizationId}-secret`;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
250
403
|
// src/PhantomProvider.tsx
|
|
404
|
+
var import_react_native2 = require("react-native");
|
|
251
405
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
252
406
|
var PhantomContext = (0, import_react.createContext)(void 0);
|
|
253
407
|
function PhantomProvider({ children, config }) {
|
|
@@ -268,10 +422,16 @@ function PhantomProvider({ children, config }) {
|
|
|
268
422
|
const authProvider = new ExpoAuthProvider();
|
|
269
423
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
270
424
|
const logger = new ExpoLogger(config.debug);
|
|
425
|
+
const stamper = new ReactNativeStamper({
|
|
426
|
+
keyPrefix: `phantom-rn-${config.organizationId}`,
|
|
427
|
+
organizationId: config.organizationId
|
|
428
|
+
});
|
|
271
429
|
const platform = {
|
|
272
430
|
storage,
|
|
273
431
|
authProvider,
|
|
274
|
-
urlParamsAccessor
|
|
432
|
+
urlParamsAccessor,
|
|
433
|
+
stamper,
|
|
434
|
+
name: `${import_react_native2.Platform.OS}-${import_react_native2.Platform.Version}`
|
|
275
435
|
};
|
|
276
436
|
return new import_embedded_provider_core.EmbeddedProvider(embeddedConfig, platform, logger);
|
|
277
437
|
}, [config]);
|
|
@@ -465,6 +625,7 @@ function useSignAndSendTransaction() {
|
|
|
465
625
|
|
|
466
626
|
// src/index.ts
|
|
467
627
|
var import_client = require("@phantom/client");
|
|
628
|
+
var import_constants = require("@phantom/constants");
|
|
468
629
|
// Annotate the CommonJS export names for ESM import in node:
|
|
469
630
|
0 && (module.exports = {
|
|
470
631
|
AddressType,
|
package/dist/index.mjs
CHANGED
|
@@ -52,22 +52,52 @@ var ExpoSecureStorage = class {
|
|
|
52
52
|
|
|
53
53
|
// src/providers/embedded/auth.ts
|
|
54
54
|
import * as WebBrowser from "expo-web-browser";
|
|
55
|
+
var DEFAULT_AUTH_URL = "https://auth.phantom.app";
|
|
55
56
|
var ExpoAuthProvider = class {
|
|
56
57
|
async authenticate(options) {
|
|
57
58
|
if ("jwtToken" in options) {
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
const phantomOptions = options;
|
|
62
|
+
const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData } = phantomOptions;
|
|
63
|
+
if (!redirectUrl) {
|
|
64
|
+
throw new Error("redirectUrl is required for web browser authentication");
|
|
65
|
+
}
|
|
66
|
+
if (!organizationId || !sessionId) {
|
|
67
|
+
throw new Error("organizationId and sessionId are required for authentication");
|
|
63
68
|
}
|
|
64
69
|
try {
|
|
70
|
+
const baseUrl = authUrl || DEFAULT_AUTH_URL;
|
|
71
|
+
const params = new URLSearchParams({
|
|
72
|
+
organization_id: organizationId,
|
|
73
|
+
parent_organization_id: parentOrganizationId,
|
|
74
|
+
redirect_uri: redirectUrl,
|
|
75
|
+
session_id: sessionId,
|
|
76
|
+
clear_previous_session: "true"
|
|
77
|
+
});
|
|
78
|
+
if (provider) {
|
|
79
|
+
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
80
|
+
params.append("provider", provider);
|
|
81
|
+
} else {
|
|
82
|
+
console.log("[ExpoAuthProvider] No provider specified, defaulting to Google");
|
|
83
|
+
params.append("provider", "google");
|
|
84
|
+
}
|
|
85
|
+
if (customAuthData) {
|
|
86
|
+
console.log("[ExpoAuthProvider] Adding custom auth data");
|
|
87
|
+
params.append("authData", JSON.stringify(customAuthData));
|
|
88
|
+
}
|
|
89
|
+
const fullAuthUrl = `${baseUrl}?${params.toString()}`;
|
|
65
90
|
console.log("[ExpoAuthProvider] Starting authentication", {
|
|
66
|
-
|
|
67
|
-
redirectUrl
|
|
91
|
+
baseUrl,
|
|
92
|
+
redirectUrl,
|
|
93
|
+
organizationId,
|
|
94
|
+
parentOrganizationId,
|
|
95
|
+
sessionId,
|
|
96
|
+
provider,
|
|
97
|
+
hasCustomData: !!customAuthData
|
|
68
98
|
});
|
|
69
99
|
await WebBrowser.warmUpAsync();
|
|
70
|
-
const result = await WebBrowser.openAuthSessionAsync(
|
|
100
|
+
const result = await WebBrowser.openAuthSessionAsync(fullAuthUrl, redirectUrl, {
|
|
71
101
|
// Use system browser on iOS for ASWebAuthenticationSession
|
|
72
102
|
preferEphemeralSession: false
|
|
73
103
|
});
|
|
@@ -77,19 +107,14 @@ var ExpoAuthProvider = class {
|
|
|
77
107
|
});
|
|
78
108
|
if (result.type === "success" && result.url) {
|
|
79
109
|
const url = new URL(result.url);
|
|
80
|
-
const walletId = url.searchParams.get("
|
|
81
|
-
const
|
|
110
|
+
const walletId = url.searchParams.get("wallet_id");
|
|
111
|
+
const provider2 = url.searchParams.get("provider");
|
|
82
112
|
if (!walletId) {
|
|
83
113
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
84
114
|
}
|
|
85
|
-
const userInfo = {};
|
|
86
|
-
url.searchParams.forEach((value, key) => {
|
|
87
|
-
userInfo[key] = value;
|
|
88
|
-
});
|
|
89
115
|
return {
|
|
90
116
|
walletId,
|
|
91
|
-
provider:
|
|
92
|
-
userInfo
|
|
117
|
+
provider: provider2 || void 0
|
|
93
118
|
};
|
|
94
119
|
} else if (result.type === "cancel") {
|
|
95
120
|
throw new Error("User cancelled authentication");
|
|
@@ -203,7 +228,136 @@ var ExpoLogger = class {
|
|
|
203
228
|
}
|
|
204
229
|
};
|
|
205
230
|
|
|
231
|
+
// src/providers/embedded/stamper.ts
|
|
232
|
+
import * as SecureStore2 from "expo-secure-store";
|
|
233
|
+
import { ApiKeyStamper } from "@phantom/api-key-stamper";
|
|
234
|
+
import { generateKeyPair } from "@phantom/crypto";
|
|
235
|
+
import { base64urlEncode } from "@phantom/base64url";
|
|
236
|
+
import { Algorithm } from "@phantom/sdk-types";
|
|
237
|
+
var ReactNativeStamper = class {
|
|
238
|
+
constructor(config = {}) {
|
|
239
|
+
this.keyInfo = null;
|
|
240
|
+
this.algorithm = Algorithm.ed25519;
|
|
241
|
+
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
242
|
+
this.organizationId = config.organizationId || "default";
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Initialize the stamper and generate/load cryptographic keys
|
|
246
|
+
*/
|
|
247
|
+
async init() {
|
|
248
|
+
const storedSecretKey = await this.getStoredSecretKey();
|
|
249
|
+
if (storedSecretKey) {
|
|
250
|
+
const keyInfo2 = await this.getStoredKeyInfo();
|
|
251
|
+
if (keyInfo2) {
|
|
252
|
+
this.keyInfo = keyInfo2;
|
|
253
|
+
return keyInfo2;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const keyInfo = await this.generateAndStoreKeyPair();
|
|
257
|
+
this.keyInfo = keyInfo;
|
|
258
|
+
return keyInfo;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get the current key information
|
|
262
|
+
*/
|
|
263
|
+
getKeyInfo() {
|
|
264
|
+
return this.keyInfo;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Generate and store a new key pair, replacing any existing keys
|
|
268
|
+
*/
|
|
269
|
+
async resetKeyPair() {
|
|
270
|
+
await this.clear();
|
|
271
|
+
const keyInfo = await this.generateAndStoreKeyPair();
|
|
272
|
+
this.keyInfo = keyInfo;
|
|
273
|
+
return keyInfo;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Create X-Phantom-Stamp header value using stored secret key
|
|
277
|
+
* @param data - Data to sign (Buffer)
|
|
278
|
+
* @returns Complete X-Phantom-Stamp header value
|
|
279
|
+
*/
|
|
280
|
+
async stamp({
|
|
281
|
+
data
|
|
282
|
+
}) {
|
|
283
|
+
if (!this.keyInfo) {
|
|
284
|
+
throw new Error("Stamper not initialized. Call init() first.");
|
|
285
|
+
}
|
|
286
|
+
const storedSecretKey = await this.getStoredSecretKey();
|
|
287
|
+
if (!storedSecretKey) {
|
|
288
|
+
throw new Error("Secret key not found in secure storage");
|
|
289
|
+
}
|
|
290
|
+
const apiKeyStamper = new ApiKeyStamper({ apiSecretKey: storedSecretKey });
|
|
291
|
+
return await apiKeyStamper.stamp({ data });
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Clear all stored keys from SecureStore
|
|
295
|
+
*/
|
|
296
|
+
async clear() {
|
|
297
|
+
const infoKey = this.getInfoKey();
|
|
298
|
+
const secretKey = this.getSecretKey();
|
|
299
|
+
try {
|
|
300
|
+
await SecureStore2.deleteItemAsync(infoKey);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
await SecureStore2.deleteItemAsync(secretKey);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
}
|
|
307
|
+
this.keyInfo = null;
|
|
308
|
+
}
|
|
309
|
+
async generateAndStoreKeyPair() {
|
|
310
|
+
const keypair = generateKeyPair();
|
|
311
|
+
const keyId = this.createKeyId(keypair.publicKey);
|
|
312
|
+
const keyInfo = {
|
|
313
|
+
keyId,
|
|
314
|
+
publicKey: keypair.publicKey
|
|
315
|
+
};
|
|
316
|
+
await this.storeKeyPair(keypair.secretKey, keyInfo);
|
|
317
|
+
return keyInfo;
|
|
318
|
+
}
|
|
319
|
+
createKeyId(publicKey) {
|
|
320
|
+
return base64urlEncode(new TextEncoder().encode(publicKey)).substring(0, 16);
|
|
321
|
+
}
|
|
322
|
+
async storeKeyPair(secretKey, keyInfo) {
|
|
323
|
+
const infoKey = this.getInfoKey();
|
|
324
|
+
const secretKeyName = this.getSecretKey();
|
|
325
|
+
await SecureStore2.setItemAsync(infoKey, JSON.stringify(keyInfo), {
|
|
326
|
+
requireAuthentication: false
|
|
327
|
+
});
|
|
328
|
+
await SecureStore2.setItemAsync(secretKeyName, secretKey, {
|
|
329
|
+
requireAuthentication: false
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
async getStoredKeyInfo() {
|
|
333
|
+
try {
|
|
334
|
+
const infoKey = this.getInfoKey();
|
|
335
|
+
const storedInfo = await SecureStore2.getItemAsync(infoKey);
|
|
336
|
+
if (storedInfo) {
|
|
337
|
+
return JSON.parse(storedInfo);
|
|
338
|
+
}
|
|
339
|
+
} catch (error) {
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
async getStoredSecretKey() {
|
|
344
|
+
try {
|
|
345
|
+
const secretKeyName = this.getSecretKey();
|
|
346
|
+
return await SecureStore2.getItemAsync(secretKeyName);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
getInfoKey() {
|
|
352
|
+
return `${this.keyPrefix}-${this.organizationId}-info`;
|
|
353
|
+
}
|
|
354
|
+
getSecretKey() {
|
|
355
|
+
return `${this.keyPrefix}-${this.organizationId}-secret`;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
206
359
|
// src/PhantomProvider.tsx
|
|
360
|
+
import { Platform } from "react-native";
|
|
207
361
|
import { jsx } from "react/jsx-runtime";
|
|
208
362
|
var PhantomContext = createContext(void 0);
|
|
209
363
|
function PhantomProvider({ children, config }) {
|
|
@@ -224,10 +378,16 @@ function PhantomProvider({ children, config }) {
|
|
|
224
378
|
const authProvider = new ExpoAuthProvider();
|
|
225
379
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
226
380
|
const logger = new ExpoLogger(config.debug);
|
|
381
|
+
const stamper = new ReactNativeStamper({
|
|
382
|
+
keyPrefix: `phantom-rn-${config.organizationId}`,
|
|
383
|
+
organizationId: config.organizationId
|
|
384
|
+
});
|
|
227
385
|
const platform = {
|
|
228
386
|
storage,
|
|
229
387
|
authProvider,
|
|
230
|
-
urlParamsAccessor
|
|
388
|
+
urlParamsAccessor,
|
|
389
|
+
stamper,
|
|
390
|
+
name: `${Platform.OS}-${Platform.Version}`
|
|
231
391
|
};
|
|
232
392
|
return new EmbeddedProvider(embeddedConfig, platform, logger);
|
|
233
393
|
}, [config]);
|
|
@@ -420,7 +580,8 @@ function useSignAndSendTransaction() {
|
|
|
420
580
|
}
|
|
421
581
|
|
|
422
582
|
// src/index.ts
|
|
423
|
-
import { AddressType
|
|
583
|
+
import { AddressType } from "@phantom/client";
|
|
584
|
+
import { NetworkId } from "@phantom/constants";
|
|
424
585
|
export {
|
|
425
586
|
AddressType,
|
|
426
587
|
NetworkId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/react-native-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Phantom Wallet SDK for React Native and Expo applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -45,8 +45,16 @@
|
|
|
45
45
|
"directory": "packages/react-native-sdk"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@phantom/
|
|
49
|
-
"@phantom/
|
|
48
|
+
"@phantom/api-key-stamper": "^0.1.2",
|
|
49
|
+
"@phantom/base64url": "^0.1.0",
|
|
50
|
+
"@phantom/client": "^0.1.5",
|
|
51
|
+
"@phantom/constants": "^0.0.2",
|
|
52
|
+
"@phantom/crypto": "^0.1.1",
|
|
53
|
+
"@phantom/embedded-provider-core": "^0.1.2",
|
|
54
|
+
"@phantom/sdk-types": "^0.1.1",
|
|
55
|
+
"@types/bs58": "^5.0.0",
|
|
56
|
+
"bs58": "^6.0.0",
|
|
57
|
+
"buffer": "^6.0.3"
|
|
50
58
|
},
|
|
51
59
|
"peerDependencies": {
|
|
52
60
|
"expo": ">=53.0.0",
|