@phantom/react-native-sdk 1.0.2 → 1.0.4
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 -0
- package/dist/index.js +271 -29
- package/dist/index.mjs +267 -19
- package/package.json +11 -10
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ interface PhantomSDKConfig extends Omit<EmbeddedProviderConfig, "apiBaseUrl" | "
|
|
|
25
25
|
authUrl?: string;
|
|
26
26
|
redirectUrl?: string;
|
|
27
27
|
};
|
|
28
|
+
/** When also provided, the Auth2 PKCE flow is used instead of the legacy Phantom Connect flow. */
|
|
29
|
+
unstable__auth2Options?: {
|
|
30
|
+
authApiBaseUrl: string;
|
|
31
|
+
clientId: string;
|
|
32
|
+
};
|
|
28
33
|
}
|
|
29
34
|
interface ConnectOptions {
|
|
30
35
|
/** OAuth provider to use (required) */
|
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_constants4.NetworkId,
|
|
35
35
|
PhantomProvider: () => PhantomProvider,
|
|
36
36
|
darkTheme: () => import_wallet_sdk_ui6.darkTheme,
|
|
37
37
|
lightTheme: () => import_wallet_sdk_ui6.lightTheme,
|
|
@@ -48,7 +48,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
48
48
|
// src/PhantomProvider.tsx
|
|
49
49
|
var import_react8 = require("react");
|
|
50
50
|
var import_embedded_provider_core = require("@phantom/embedded-provider-core");
|
|
51
|
-
var
|
|
51
|
+
var import_constants3 = require("@phantom/constants");
|
|
52
52
|
var import_wallet_sdk_ui5 = require("@phantom/wallet-sdk-ui");
|
|
53
53
|
|
|
54
54
|
// src/ModalProvider.tsx
|
|
@@ -557,7 +557,7 @@ var ExpoAuthProvider = class {
|
|
|
557
557
|
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
558
558
|
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
559
559
|
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
560
|
-
sdk_version: "1.0.
|
|
560
|
+
sdk_version: "1.0.4",
|
|
561
561
|
sdk_type: "react-native",
|
|
562
562
|
platform: import_react_native5.Platform.OS
|
|
563
563
|
});
|
|
@@ -632,6 +632,235 @@ var ExpoAuthProvider = class {
|
|
|
632
632
|
}
|
|
633
633
|
};
|
|
634
634
|
|
|
635
|
+
// src/providers/embedded/ExpoAuth2AuthProvider.ts
|
|
636
|
+
var WebBrowser2 = __toESM(require("expo-web-browser"));
|
|
637
|
+
var import_auth2 = require("@phantom/auth2");
|
|
638
|
+
var ExpoAuth2AuthProvider = class {
|
|
639
|
+
constructor(stamper, auth2ProviderOptions, kmsClientOptions) {
|
|
640
|
+
this.stamper = stamper;
|
|
641
|
+
this.auth2ProviderOptions = auth2ProviderOptions;
|
|
642
|
+
this.kms = new import_auth2.Auth2KmsRpcClient(stamper, kmsClientOptions);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Runs the full PKCE Auth2 flow inline using expo-web-browser.
|
|
646
|
+
*
|
|
647
|
+
* Unlike the browser flow (which requires a page redirect and resumeAuthFromRedirect),
|
|
648
|
+
* expo-web-browser intercepts the OAuth callback URL and returns it synchronously,
|
|
649
|
+
* so the token exchange and KMS calls all happen here before returning AuthResult.
|
|
650
|
+
*/
|
|
651
|
+
async authenticate(options) {
|
|
652
|
+
if (!this.stamper.getKeyInfo()) {
|
|
653
|
+
await this.stamper.init();
|
|
654
|
+
}
|
|
655
|
+
const keyPair = this.stamper.getCryptoKeyPair();
|
|
656
|
+
if (!keyPair) {
|
|
657
|
+
throw new Error("Stamper key pair not found.");
|
|
658
|
+
}
|
|
659
|
+
const codeVerifier = (0, import_auth2.createCodeVerifier)();
|
|
660
|
+
const salt = (0, import_auth2.createSalt)();
|
|
661
|
+
const url = await (0, import_auth2.createConnectStartUrl)({
|
|
662
|
+
keyPair,
|
|
663
|
+
connectLoginUrl: this.auth2ProviderOptions.connectLoginUrl,
|
|
664
|
+
clientId: this.auth2ProviderOptions.clientId,
|
|
665
|
+
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
666
|
+
sessionId: options.sessionId,
|
|
667
|
+
provider: options.provider,
|
|
668
|
+
codeVerifier,
|
|
669
|
+
salt
|
|
670
|
+
});
|
|
671
|
+
await WebBrowser2.warmUpAsync();
|
|
672
|
+
let result;
|
|
673
|
+
try {
|
|
674
|
+
result = await WebBrowser2.openAuthSessionAsync(url, this.auth2ProviderOptions.redirectUri);
|
|
675
|
+
} finally {
|
|
676
|
+
await WebBrowser2.coolDownAsync();
|
|
677
|
+
}
|
|
678
|
+
if (!result.url) {
|
|
679
|
+
throw new Error("Authentication failed");
|
|
680
|
+
}
|
|
681
|
+
const callbackUrl = new URL(result.url);
|
|
682
|
+
const state = callbackUrl.searchParams.get("state");
|
|
683
|
+
if (state && state !== options.sessionId) {
|
|
684
|
+
throw new Error("Auth2 state mismatch \u2014 possible CSRF attack.");
|
|
685
|
+
}
|
|
686
|
+
const error = callbackUrl.searchParams.get("error");
|
|
687
|
+
if (error) {
|
|
688
|
+
const description = callbackUrl.searchParams.get("error_description");
|
|
689
|
+
throw new Error(`Auth2 callback error: ${description ?? error}`);
|
|
690
|
+
}
|
|
691
|
+
const code = callbackUrl.searchParams.get("code");
|
|
692
|
+
if (!code) {
|
|
693
|
+
throw new Error("Auth2 callback missing authorization code");
|
|
694
|
+
}
|
|
695
|
+
const { idToken, bearerToken, authUserId, expiresInMs } = await (0, import_auth2.exchangeAuthCode)({
|
|
696
|
+
authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
|
|
697
|
+
clientId: this.auth2ProviderOptions.clientId,
|
|
698
|
+
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
699
|
+
code,
|
|
700
|
+
codeVerifier
|
|
701
|
+
});
|
|
702
|
+
this.stamper.idToken = idToken;
|
|
703
|
+
this.stamper.salt = salt;
|
|
704
|
+
const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
|
|
705
|
+
return {
|
|
706
|
+
walletId,
|
|
707
|
+
organizationId,
|
|
708
|
+
provider: options.provider,
|
|
709
|
+
accountDerivationIndex: 0,
|
|
710
|
+
// discoverWalletId uses derivation index of 0.
|
|
711
|
+
expiresInMs,
|
|
712
|
+
authUserId,
|
|
713
|
+
bearerToken
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
// src/providers/embedded/ExpoAuth2Stamper.ts
|
|
719
|
+
var SecureStore2 = __toESM(require("expo-secure-store"));
|
|
720
|
+
var import_bs58 = __toESM(require("bs58"));
|
|
721
|
+
var import_buffer = require("buffer");
|
|
722
|
+
var import_base64url = require("@phantom/base64url");
|
|
723
|
+
var import_sdk_types = require("@phantom/sdk-types");
|
|
724
|
+
var ExpoAuth2Stamper = class {
|
|
725
|
+
/**
|
|
726
|
+
* @param storageKey - expo-secure-store key used to persist the P-256 private key.
|
|
727
|
+
* Use a unique key per app, e.g. `phantom-auth2-<appId>`.
|
|
728
|
+
*/
|
|
729
|
+
constructor(storageKey) {
|
|
730
|
+
this.storageKey = storageKey;
|
|
731
|
+
this.privateKey = null;
|
|
732
|
+
this.publicKey = null;
|
|
733
|
+
this._keyInfo = null;
|
|
734
|
+
this.algorithm = import_sdk_types.Algorithm.secp256r1;
|
|
735
|
+
this.type = "OIDC";
|
|
736
|
+
}
|
|
737
|
+
async init() {
|
|
738
|
+
const stored = await this.loadRecord();
|
|
739
|
+
if (stored) {
|
|
740
|
+
this.privateKey = await this.importPrivateKey(stored.privateKeyPkcs8);
|
|
741
|
+
this.publicKey = await this.importPublicKeyFromBase58(stored.keyInfo.publicKey);
|
|
742
|
+
this._keyInfo = stored.keyInfo;
|
|
743
|
+
return this._keyInfo;
|
|
744
|
+
}
|
|
745
|
+
return this.generateAndStore();
|
|
746
|
+
}
|
|
747
|
+
getKeyInfo() {
|
|
748
|
+
return this._keyInfo;
|
|
749
|
+
}
|
|
750
|
+
getCryptoKeyPair() {
|
|
751
|
+
if (!this.privateKey || !this.publicKey)
|
|
752
|
+
return null;
|
|
753
|
+
return { privateKey: this.privateKey, publicKey: this.publicKey };
|
|
754
|
+
}
|
|
755
|
+
async stamp(params) {
|
|
756
|
+
if (!this.privateKey || !this._keyInfo) {
|
|
757
|
+
throw new Error("ExpoAuth2Stamper not initialized. Call init() first.");
|
|
758
|
+
}
|
|
759
|
+
const signatureRaw = await crypto.subtle.sign(
|
|
760
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
761
|
+
this.privateKey,
|
|
762
|
+
new Uint8Array(params.data)
|
|
763
|
+
);
|
|
764
|
+
const rawPublicKey = import_bs58.default.decode(this._keyInfo.publicKey);
|
|
765
|
+
if (this.idToken === void 0 || this.salt === void 0) {
|
|
766
|
+
throw new Error("ExpoAuth2Stamper not initialized with idToken or salt.");
|
|
767
|
+
}
|
|
768
|
+
const stampData = {
|
|
769
|
+
kind: "OIDC",
|
|
770
|
+
idToken: this.idToken,
|
|
771
|
+
publicKey: (0, import_base64url.base64urlEncode)(rawPublicKey),
|
|
772
|
+
algorithm: "Secp256r1",
|
|
773
|
+
salt: this.salt,
|
|
774
|
+
signature: (0, import_base64url.base64urlEncode)(new Uint8Array(signatureRaw))
|
|
775
|
+
};
|
|
776
|
+
return (0, import_base64url.base64urlEncode)(new TextEncoder().encode(JSON.stringify(stampData)));
|
|
777
|
+
}
|
|
778
|
+
async resetKeyPair() {
|
|
779
|
+
await this.clearStoredRecord();
|
|
780
|
+
this.privateKey = null;
|
|
781
|
+
this.publicKey = null;
|
|
782
|
+
this._keyInfo = null;
|
|
783
|
+
return this.generateAndStore();
|
|
784
|
+
}
|
|
785
|
+
async clear() {
|
|
786
|
+
await this.clearStoredRecord();
|
|
787
|
+
this.privateKey = null;
|
|
788
|
+
this.publicKey = null;
|
|
789
|
+
this._keyInfo = null;
|
|
790
|
+
}
|
|
791
|
+
// Auth2 doesn't use key rotation; minimal no-op implementations.
|
|
792
|
+
async rotateKeyPair() {
|
|
793
|
+
return this.init();
|
|
794
|
+
}
|
|
795
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
796
|
+
async commitRotation(authenticatorId) {
|
|
797
|
+
if (this._keyInfo) {
|
|
798
|
+
this._keyInfo.authenticatorId = authenticatorId;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
async rollbackRotation() {
|
|
802
|
+
}
|
|
803
|
+
async generateAndStore() {
|
|
804
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
805
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
806
|
+
true,
|
|
807
|
+
// extractable — needed to export PKCS#8 for SecureStore
|
|
808
|
+
["sign", "verify"]
|
|
809
|
+
);
|
|
810
|
+
const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
|
|
811
|
+
const publicKeyBase58 = import_bs58.default.encode(rawPublicKey);
|
|
812
|
+
const keyIdBuffer = await crypto.subtle.digest("SHA-256", rawPublicKey.buffer);
|
|
813
|
+
const keyId = (0, import_base64url.base64urlEncode)(new Uint8Array(keyIdBuffer)).substring(0, 16);
|
|
814
|
+
this._keyInfo = { keyId, publicKey: publicKeyBase58, createdAt: Date.now() };
|
|
815
|
+
const pkcs8Buffer = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
|
|
816
|
+
const privateKeyPkcs8 = import_buffer.Buffer.from(pkcs8Buffer).toString("base64");
|
|
817
|
+
await SecureStore2.setItemAsync(
|
|
818
|
+
this.storageKey,
|
|
819
|
+
JSON.stringify({ privateKeyPkcs8, keyInfo: this._keyInfo }),
|
|
820
|
+
{ requireAuthentication: false }
|
|
821
|
+
);
|
|
822
|
+
this.privateKey = await this.importPrivateKey(privateKeyPkcs8);
|
|
823
|
+
this.publicKey = keyPair.publicKey;
|
|
824
|
+
return this._keyInfo;
|
|
825
|
+
}
|
|
826
|
+
async importPublicKeyFromBase58(base58PublicKey) {
|
|
827
|
+
const rawBytes = import_bs58.default.decode(base58PublicKey);
|
|
828
|
+
return crypto.subtle.importKey(
|
|
829
|
+
"raw",
|
|
830
|
+
rawBytes.buffer.slice(rawBytes.byteOffset, rawBytes.byteOffset + rawBytes.byteLength),
|
|
831
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
832
|
+
true,
|
|
833
|
+
// extractable so createAuth2RequestJar can export it as JWK
|
|
834
|
+
["verify"]
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
async importPrivateKey(pkcs8Base64) {
|
|
838
|
+
const pkcs8Bytes = import_buffer.Buffer.from(pkcs8Base64, "base64");
|
|
839
|
+
return crypto.subtle.importKey(
|
|
840
|
+
"pkcs8",
|
|
841
|
+
pkcs8Bytes,
|
|
842
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
843
|
+
false,
|
|
844
|
+
// non-extractable once loaded into memory
|
|
845
|
+
["sign"]
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
async loadRecord() {
|
|
849
|
+
try {
|
|
850
|
+
const raw = await SecureStore2.getItemAsync(this.storageKey);
|
|
851
|
+
return raw ? JSON.parse(raw) : null;
|
|
852
|
+
} catch {
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
async clearStoredRecord() {
|
|
857
|
+
try {
|
|
858
|
+
await SecureStore2.deleteItemAsync(this.storageKey);
|
|
859
|
+
} catch {
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
|
|
635
864
|
// src/providers/embedded/url-params.ts
|
|
636
865
|
var import_react_native6 = require("react-native");
|
|
637
866
|
var ExpoURLParamsAccessor = class {
|
|
@@ -701,17 +930,17 @@ var ExpoURLParamsAccessor = class {
|
|
|
701
930
|
};
|
|
702
931
|
|
|
703
932
|
// src/providers/embedded/stamper.ts
|
|
704
|
-
var
|
|
933
|
+
var SecureStore3 = __toESM(require("expo-secure-store"));
|
|
705
934
|
var import_api_key_stamper = require("@phantom/api-key-stamper");
|
|
935
|
+
var import_constants2 = require("@phantom/constants");
|
|
706
936
|
var import_crypto = require("@phantom/crypto");
|
|
707
|
-
var
|
|
708
|
-
var import_sdk_types = require("@phantom/sdk-types");
|
|
937
|
+
var import_base64url2 = require("@phantom/base64url");
|
|
709
938
|
var ReactNativeStamper = class {
|
|
710
939
|
// Optional for PKI, required for OIDC
|
|
711
940
|
constructor(config = {}) {
|
|
712
941
|
this.activeKeyRecord = null;
|
|
713
942
|
this.pendingKeyRecord = null;
|
|
714
|
-
this.algorithm =
|
|
943
|
+
this.algorithm = import_constants2.DEFAULT_AUTHENTICATOR_ALGORITHM;
|
|
715
944
|
this.type = "PKI";
|
|
716
945
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
717
946
|
this.appId = config.appId || "default";
|
|
@@ -761,11 +990,11 @@ var ReactNativeStamper = class {
|
|
|
761
990
|
const activeKey = this.getActiveKeyName();
|
|
762
991
|
const pendingKey = this.getPendingKeyName();
|
|
763
992
|
try {
|
|
764
|
-
await
|
|
993
|
+
await SecureStore3.deleteItemAsync(activeKey);
|
|
765
994
|
} catch (error) {
|
|
766
995
|
}
|
|
767
996
|
try {
|
|
768
|
-
await
|
|
997
|
+
await SecureStore3.deleteItemAsync(pendingKey);
|
|
769
998
|
} catch (error) {
|
|
770
999
|
}
|
|
771
1000
|
this.activeKeyRecord = null;
|
|
@@ -787,7 +1016,7 @@ var ReactNativeStamper = class {
|
|
|
787
1016
|
}
|
|
788
1017
|
if (this.activeKeyRecord) {
|
|
789
1018
|
try {
|
|
790
|
-
await
|
|
1019
|
+
await SecureStore3.deleteItemAsync(this.getActiveKeyName());
|
|
791
1020
|
} catch (error) {
|
|
792
1021
|
}
|
|
793
1022
|
}
|
|
@@ -798,7 +1027,7 @@ var ReactNativeStamper = class {
|
|
|
798
1027
|
this.pendingKeyRecord = null;
|
|
799
1028
|
await this.storeKeyRecord(this.activeKeyRecord, "active");
|
|
800
1029
|
try {
|
|
801
|
-
await
|
|
1030
|
+
await SecureStore3.deleteItemAsync(this.getPendingKeyName());
|
|
802
1031
|
} catch (error) {
|
|
803
1032
|
}
|
|
804
1033
|
}
|
|
@@ -810,7 +1039,7 @@ var ReactNativeStamper = class {
|
|
|
810
1039
|
return;
|
|
811
1040
|
}
|
|
812
1041
|
try {
|
|
813
|
-
await
|
|
1042
|
+
await SecureStore3.deleteItemAsync(this.getPendingKeyName());
|
|
814
1043
|
} catch (error) {
|
|
815
1044
|
}
|
|
816
1045
|
this.pendingKeyRecord = null;
|
|
@@ -836,18 +1065,18 @@ var ReactNativeStamper = class {
|
|
|
836
1065
|
return record;
|
|
837
1066
|
}
|
|
838
1067
|
createKeyId(publicKey) {
|
|
839
|
-
return (0,
|
|
1068
|
+
return (0, import_base64url2.base64urlEncode)(new TextEncoder().encode(publicKey)).substring(0, 16);
|
|
840
1069
|
}
|
|
841
1070
|
async storeKeyRecord(record, type) {
|
|
842
1071
|
const keyName = type === "active" ? this.getActiveKeyName() : this.getPendingKeyName();
|
|
843
|
-
await
|
|
1072
|
+
await SecureStore3.setItemAsync(keyName, JSON.stringify(record), {
|
|
844
1073
|
requireAuthentication: false
|
|
845
1074
|
});
|
|
846
1075
|
}
|
|
847
1076
|
async loadActiveKeyRecord() {
|
|
848
1077
|
try {
|
|
849
1078
|
const activeKey = this.getActiveKeyName();
|
|
850
|
-
const storedRecord = await
|
|
1079
|
+
const storedRecord = await SecureStore3.getItemAsync(activeKey);
|
|
851
1080
|
if (storedRecord) {
|
|
852
1081
|
return JSON.parse(storedRecord);
|
|
853
1082
|
}
|
|
@@ -858,7 +1087,7 @@ var ReactNativeStamper = class {
|
|
|
858
1087
|
async loadPendingKeyRecord() {
|
|
859
1088
|
try {
|
|
860
1089
|
const pendingKey = this.getPendingKeyName();
|
|
861
|
-
const storedRecord = await
|
|
1090
|
+
const storedRecord = await SecureStore3.getItemAsync(pendingKey);
|
|
862
1091
|
if (storedRecord) {
|
|
863
1092
|
return JSON.parse(storedRecord);
|
|
864
1093
|
}
|
|
@@ -929,24 +1158,36 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
929
1158
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
930
1159
|
return {
|
|
931
1160
|
...config,
|
|
932
|
-
apiBaseUrl: config.apiBaseUrl ||
|
|
933
|
-
embeddedWalletType: config.embeddedWalletType ||
|
|
1161
|
+
apiBaseUrl: config.apiBaseUrl || import_constants3.DEFAULT_WALLET_API_URL,
|
|
1162
|
+
embeddedWalletType: config.embeddedWalletType || import_constants3.DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
934
1163
|
authOptions: {
|
|
935
1164
|
...config.authOptions || {},
|
|
936
1165
|
redirectUrl,
|
|
937
|
-
authUrl: config.authOptions?.authUrl ||
|
|
1166
|
+
authUrl: config.authOptions?.authUrl || import_constants3.DEFAULT_AUTH_URL
|
|
938
1167
|
}
|
|
939
1168
|
};
|
|
940
1169
|
}, [config]);
|
|
941
1170
|
const sdk = (0, import_react8.useMemo)(() => {
|
|
942
1171
|
const storage = new ExpoSecureStorage();
|
|
943
|
-
const authProvider = new ExpoAuthProvider();
|
|
944
1172
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
945
1173
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
946
|
-
const stamper = new ReactNativeStamper({
|
|
1174
|
+
const stamper = config.unstable__auth2Options ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}`) : new ReactNativeStamper({
|
|
947
1175
|
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
948
1176
|
appId: memoizedConfig.appId
|
|
949
1177
|
});
|
|
1178
|
+
const authProvider = config.unstable__auth2Options && config.authOptions?.authUrl && config.authOptions?.redirectUrl && config.apiBaseUrl && stamper instanceof ExpoAuth2Stamper ? new ExpoAuth2AuthProvider(
|
|
1179
|
+
stamper,
|
|
1180
|
+
{
|
|
1181
|
+
redirectUri: config.authOptions.redirectUrl,
|
|
1182
|
+
connectLoginUrl: config.authOptions.authUrl,
|
|
1183
|
+
clientId: config.unstable__auth2Options.clientId,
|
|
1184
|
+
authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
1188
|
+
appId: config.appId
|
|
1189
|
+
}
|
|
1190
|
+
) : new ExpoAuthProvider();
|
|
950
1191
|
const platformName = `${import_react_native7.Platform.OS}-${import_react_native7.Platform.Version}`;
|
|
951
1192
|
const platform = {
|
|
952
1193
|
storage,
|
|
@@ -956,17 +1197,18 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
956
1197
|
phantomAppProvider: new ReactNativePhantomAppProvider(),
|
|
957
1198
|
name: platformName,
|
|
958
1199
|
analyticsHeaders: {
|
|
959
|
-
[
|
|
960
|
-
[
|
|
961
|
-
[
|
|
962
|
-
[
|
|
963
|
-
[
|
|
964
|
-
[
|
|
1200
|
+
[import_constants3.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
1201
|
+
[import_constants3.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
|
|
1202
|
+
[import_constants3.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native7.Platform.Version}`,
|
|
1203
|
+
[import_constants3.ANALYTICS_HEADERS.CLIENT]: import_react_native7.Platform.OS,
|
|
1204
|
+
[import_constants3.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1205
|
+
[import_constants3.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1206
|
+
[import_constants3.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.4"
|
|
965
1207
|
// Replaced at build time
|
|
966
1208
|
}
|
|
967
1209
|
};
|
|
968
1210
|
return new import_embedded_provider_core.EmbeddedProvider(memoizedConfig, platform, logger);
|
|
969
|
-
}, [memoizedConfig, debugConfig, config
|
|
1211
|
+
}, [memoizedConfig, debugConfig, config]);
|
|
970
1212
|
(0, import_react8.useEffect)(() => {
|
|
971
1213
|
const handleConnectStart = () => {
|
|
972
1214
|
setIsConnecting(true);
|
|
@@ -1075,7 +1317,7 @@ function useEthereum() {
|
|
|
1075
1317
|
|
|
1076
1318
|
// src/index.ts
|
|
1077
1319
|
var import_client = require("@phantom/client");
|
|
1078
|
-
var
|
|
1320
|
+
var import_constants4 = require("@phantom/constants");
|
|
1079
1321
|
var import_wallet_sdk_ui6 = require("@phantom/wallet-sdk-ui");
|
|
1080
1322
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1081
1323
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -515,7 +515,7 @@ var ExpoAuthProvider = class {
|
|
|
515
515
|
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
516
516
|
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
517
517
|
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
518
|
-
sdk_version: "1.0.
|
|
518
|
+
sdk_version: "1.0.4",
|
|
519
519
|
sdk_type: "react-native",
|
|
520
520
|
platform: Platform.OS
|
|
521
521
|
});
|
|
@@ -590,6 +590,241 @@ var ExpoAuthProvider = class {
|
|
|
590
590
|
}
|
|
591
591
|
};
|
|
592
592
|
|
|
593
|
+
// src/providers/embedded/ExpoAuth2AuthProvider.ts
|
|
594
|
+
import * as WebBrowser2 from "expo-web-browser";
|
|
595
|
+
import {
|
|
596
|
+
createCodeVerifier,
|
|
597
|
+
createSalt,
|
|
598
|
+
exchangeAuthCode,
|
|
599
|
+
Auth2KmsRpcClient,
|
|
600
|
+
createConnectStartUrl
|
|
601
|
+
} from "@phantom/auth2";
|
|
602
|
+
var ExpoAuth2AuthProvider = class {
|
|
603
|
+
constructor(stamper, auth2ProviderOptions, kmsClientOptions) {
|
|
604
|
+
this.stamper = stamper;
|
|
605
|
+
this.auth2ProviderOptions = auth2ProviderOptions;
|
|
606
|
+
this.kms = new Auth2KmsRpcClient(stamper, kmsClientOptions);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Runs the full PKCE Auth2 flow inline using expo-web-browser.
|
|
610
|
+
*
|
|
611
|
+
* Unlike the browser flow (which requires a page redirect and resumeAuthFromRedirect),
|
|
612
|
+
* expo-web-browser intercepts the OAuth callback URL and returns it synchronously,
|
|
613
|
+
* so the token exchange and KMS calls all happen here before returning AuthResult.
|
|
614
|
+
*/
|
|
615
|
+
async authenticate(options) {
|
|
616
|
+
if (!this.stamper.getKeyInfo()) {
|
|
617
|
+
await this.stamper.init();
|
|
618
|
+
}
|
|
619
|
+
const keyPair = this.stamper.getCryptoKeyPair();
|
|
620
|
+
if (!keyPair) {
|
|
621
|
+
throw new Error("Stamper key pair not found.");
|
|
622
|
+
}
|
|
623
|
+
const codeVerifier = createCodeVerifier();
|
|
624
|
+
const salt = createSalt();
|
|
625
|
+
const url = await createConnectStartUrl({
|
|
626
|
+
keyPair,
|
|
627
|
+
connectLoginUrl: this.auth2ProviderOptions.connectLoginUrl,
|
|
628
|
+
clientId: this.auth2ProviderOptions.clientId,
|
|
629
|
+
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
630
|
+
sessionId: options.sessionId,
|
|
631
|
+
provider: options.provider,
|
|
632
|
+
codeVerifier,
|
|
633
|
+
salt
|
|
634
|
+
});
|
|
635
|
+
await WebBrowser2.warmUpAsync();
|
|
636
|
+
let result;
|
|
637
|
+
try {
|
|
638
|
+
result = await WebBrowser2.openAuthSessionAsync(url, this.auth2ProviderOptions.redirectUri);
|
|
639
|
+
} finally {
|
|
640
|
+
await WebBrowser2.coolDownAsync();
|
|
641
|
+
}
|
|
642
|
+
if (!result.url) {
|
|
643
|
+
throw new Error("Authentication failed");
|
|
644
|
+
}
|
|
645
|
+
const callbackUrl = new URL(result.url);
|
|
646
|
+
const state = callbackUrl.searchParams.get("state");
|
|
647
|
+
if (state && state !== options.sessionId) {
|
|
648
|
+
throw new Error("Auth2 state mismatch \u2014 possible CSRF attack.");
|
|
649
|
+
}
|
|
650
|
+
const error = callbackUrl.searchParams.get("error");
|
|
651
|
+
if (error) {
|
|
652
|
+
const description = callbackUrl.searchParams.get("error_description");
|
|
653
|
+
throw new Error(`Auth2 callback error: ${description ?? error}`);
|
|
654
|
+
}
|
|
655
|
+
const code = callbackUrl.searchParams.get("code");
|
|
656
|
+
if (!code) {
|
|
657
|
+
throw new Error("Auth2 callback missing authorization code");
|
|
658
|
+
}
|
|
659
|
+
const { idToken, bearerToken, authUserId, expiresInMs } = await exchangeAuthCode({
|
|
660
|
+
authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
|
|
661
|
+
clientId: this.auth2ProviderOptions.clientId,
|
|
662
|
+
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
663
|
+
code,
|
|
664
|
+
codeVerifier
|
|
665
|
+
});
|
|
666
|
+
this.stamper.idToken = idToken;
|
|
667
|
+
this.stamper.salt = salt;
|
|
668
|
+
const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
|
|
669
|
+
return {
|
|
670
|
+
walletId,
|
|
671
|
+
organizationId,
|
|
672
|
+
provider: options.provider,
|
|
673
|
+
accountDerivationIndex: 0,
|
|
674
|
+
// discoverWalletId uses derivation index of 0.
|
|
675
|
+
expiresInMs,
|
|
676
|
+
authUserId,
|
|
677
|
+
bearerToken
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// src/providers/embedded/ExpoAuth2Stamper.ts
|
|
683
|
+
import * as SecureStore2 from "expo-secure-store";
|
|
684
|
+
import bs58 from "bs58";
|
|
685
|
+
import { Buffer } from "buffer";
|
|
686
|
+
import { base64urlEncode } from "@phantom/base64url";
|
|
687
|
+
import { Algorithm } from "@phantom/sdk-types";
|
|
688
|
+
var ExpoAuth2Stamper = class {
|
|
689
|
+
/**
|
|
690
|
+
* @param storageKey - expo-secure-store key used to persist the P-256 private key.
|
|
691
|
+
* Use a unique key per app, e.g. `phantom-auth2-<appId>`.
|
|
692
|
+
*/
|
|
693
|
+
constructor(storageKey) {
|
|
694
|
+
this.storageKey = storageKey;
|
|
695
|
+
this.privateKey = null;
|
|
696
|
+
this.publicKey = null;
|
|
697
|
+
this._keyInfo = null;
|
|
698
|
+
this.algorithm = Algorithm.secp256r1;
|
|
699
|
+
this.type = "OIDC";
|
|
700
|
+
}
|
|
701
|
+
async init() {
|
|
702
|
+
const stored = await this.loadRecord();
|
|
703
|
+
if (stored) {
|
|
704
|
+
this.privateKey = await this.importPrivateKey(stored.privateKeyPkcs8);
|
|
705
|
+
this.publicKey = await this.importPublicKeyFromBase58(stored.keyInfo.publicKey);
|
|
706
|
+
this._keyInfo = stored.keyInfo;
|
|
707
|
+
return this._keyInfo;
|
|
708
|
+
}
|
|
709
|
+
return this.generateAndStore();
|
|
710
|
+
}
|
|
711
|
+
getKeyInfo() {
|
|
712
|
+
return this._keyInfo;
|
|
713
|
+
}
|
|
714
|
+
getCryptoKeyPair() {
|
|
715
|
+
if (!this.privateKey || !this.publicKey)
|
|
716
|
+
return null;
|
|
717
|
+
return { privateKey: this.privateKey, publicKey: this.publicKey };
|
|
718
|
+
}
|
|
719
|
+
async stamp(params) {
|
|
720
|
+
if (!this.privateKey || !this._keyInfo) {
|
|
721
|
+
throw new Error("ExpoAuth2Stamper not initialized. Call init() first.");
|
|
722
|
+
}
|
|
723
|
+
const signatureRaw = await crypto.subtle.sign(
|
|
724
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
725
|
+
this.privateKey,
|
|
726
|
+
new Uint8Array(params.data)
|
|
727
|
+
);
|
|
728
|
+
const rawPublicKey = bs58.decode(this._keyInfo.publicKey);
|
|
729
|
+
if (this.idToken === void 0 || this.salt === void 0) {
|
|
730
|
+
throw new Error("ExpoAuth2Stamper not initialized with idToken or salt.");
|
|
731
|
+
}
|
|
732
|
+
const stampData = {
|
|
733
|
+
kind: "OIDC",
|
|
734
|
+
idToken: this.idToken,
|
|
735
|
+
publicKey: base64urlEncode(rawPublicKey),
|
|
736
|
+
algorithm: "Secp256r1",
|
|
737
|
+
salt: this.salt,
|
|
738
|
+
signature: base64urlEncode(new Uint8Array(signatureRaw))
|
|
739
|
+
};
|
|
740
|
+
return base64urlEncode(new TextEncoder().encode(JSON.stringify(stampData)));
|
|
741
|
+
}
|
|
742
|
+
async resetKeyPair() {
|
|
743
|
+
await this.clearStoredRecord();
|
|
744
|
+
this.privateKey = null;
|
|
745
|
+
this.publicKey = null;
|
|
746
|
+
this._keyInfo = null;
|
|
747
|
+
return this.generateAndStore();
|
|
748
|
+
}
|
|
749
|
+
async clear() {
|
|
750
|
+
await this.clearStoredRecord();
|
|
751
|
+
this.privateKey = null;
|
|
752
|
+
this.publicKey = null;
|
|
753
|
+
this._keyInfo = null;
|
|
754
|
+
}
|
|
755
|
+
// Auth2 doesn't use key rotation; minimal no-op implementations.
|
|
756
|
+
async rotateKeyPair() {
|
|
757
|
+
return this.init();
|
|
758
|
+
}
|
|
759
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
760
|
+
async commitRotation(authenticatorId) {
|
|
761
|
+
if (this._keyInfo) {
|
|
762
|
+
this._keyInfo.authenticatorId = authenticatorId;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
async rollbackRotation() {
|
|
766
|
+
}
|
|
767
|
+
async generateAndStore() {
|
|
768
|
+
const keyPair = await crypto.subtle.generateKey(
|
|
769
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
770
|
+
true,
|
|
771
|
+
// extractable — needed to export PKCS#8 for SecureStore
|
|
772
|
+
["sign", "verify"]
|
|
773
|
+
);
|
|
774
|
+
const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
|
|
775
|
+
const publicKeyBase58 = bs58.encode(rawPublicKey);
|
|
776
|
+
const keyIdBuffer = await crypto.subtle.digest("SHA-256", rawPublicKey.buffer);
|
|
777
|
+
const keyId = base64urlEncode(new Uint8Array(keyIdBuffer)).substring(0, 16);
|
|
778
|
+
this._keyInfo = { keyId, publicKey: publicKeyBase58, createdAt: Date.now() };
|
|
779
|
+
const pkcs8Buffer = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
|
|
780
|
+
const privateKeyPkcs8 = Buffer.from(pkcs8Buffer).toString("base64");
|
|
781
|
+
await SecureStore2.setItemAsync(
|
|
782
|
+
this.storageKey,
|
|
783
|
+
JSON.stringify({ privateKeyPkcs8, keyInfo: this._keyInfo }),
|
|
784
|
+
{ requireAuthentication: false }
|
|
785
|
+
);
|
|
786
|
+
this.privateKey = await this.importPrivateKey(privateKeyPkcs8);
|
|
787
|
+
this.publicKey = keyPair.publicKey;
|
|
788
|
+
return this._keyInfo;
|
|
789
|
+
}
|
|
790
|
+
async importPublicKeyFromBase58(base58PublicKey) {
|
|
791
|
+
const rawBytes = bs58.decode(base58PublicKey);
|
|
792
|
+
return crypto.subtle.importKey(
|
|
793
|
+
"raw",
|
|
794
|
+
rawBytes.buffer.slice(rawBytes.byteOffset, rawBytes.byteOffset + rawBytes.byteLength),
|
|
795
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
796
|
+
true,
|
|
797
|
+
// extractable so createAuth2RequestJar can export it as JWK
|
|
798
|
+
["verify"]
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
async importPrivateKey(pkcs8Base64) {
|
|
802
|
+
const pkcs8Bytes = Buffer.from(pkcs8Base64, "base64");
|
|
803
|
+
return crypto.subtle.importKey(
|
|
804
|
+
"pkcs8",
|
|
805
|
+
pkcs8Bytes,
|
|
806
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
807
|
+
false,
|
|
808
|
+
// non-extractable once loaded into memory
|
|
809
|
+
["sign"]
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
async loadRecord() {
|
|
813
|
+
try {
|
|
814
|
+
const raw = await SecureStore2.getItemAsync(this.storageKey);
|
|
815
|
+
return raw ? JSON.parse(raw) : null;
|
|
816
|
+
} catch {
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
async clearStoredRecord() {
|
|
821
|
+
try {
|
|
822
|
+
await SecureStore2.deleteItemAsync(this.storageKey);
|
|
823
|
+
} catch {
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
|
|
593
828
|
// src/providers/embedded/url-params.ts
|
|
594
829
|
import { Linking } from "react-native";
|
|
595
830
|
var ExpoURLParamsAccessor = class {
|
|
@@ -659,17 +894,17 @@ var ExpoURLParamsAccessor = class {
|
|
|
659
894
|
};
|
|
660
895
|
|
|
661
896
|
// src/providers/embedded/stamper.ts
|
|
662
|
-
import * as
|
|
897
|
+
import * as SecureStore3 from "expo-secure-store";
|
|
663
898
|
import { ApiKeyStamper } from "@phantom/api-key-stamper";
|
|
899
|
+
import { DEFAULT_AUTHENTICATOR_ALGORITHM } from "@phantom/constants";
|
|
664
900
|
import { generateKeyPair } from "@phantom/crypto";
|
|
665
|
-
import { base64urlEncode } from "@phantom/base64url";
|
|
666
|
-
import { Algorithm } from "@phantom/sdk-types";
|
|
901
|
+
import { base64urlEncode as base64urlEncode2 } from "@phantom/base64url";
|
|
667
902
|
var ReactNativeStamper = class {
|
|
668
903
|
// Optional for PKI, required for OIDC
|
|
669
904
|
constructor(config = {}) {
|
|
670
905
|
this.activeKeyRecord = null;
|
|
671
906
|
this.pendingKeyRecord = null;
|
|
672
|
-
this.algorithm =
|
|
907
|
+
this.algorithm = DEFAULT_AUTHENTICATOR_ALGORITHM;
|
|
673
908
|
this.type = "PKI";
|
|
674
909
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
675
910
|
this.appId = config.appId || "default";
|
|
@@ -719,11 +954,11 @@ var ReactNativeStamper = class {
|
|
|
719
954
|
const activeKey = this.getActiveKeyName();
|
|
720
955
|
const pendingKey = this.getPendingKeyName();
|
|
721
956
|
try {
|
|
722
|
-
await
|
|
957
|
+
await SecureStore3.deleteItemAsync(activeKey);
|
|
723
958
|
} catch (error) {
|
|
724
959
|
}
|
|
725
960
|
try {
|
|
726
|
-
await
|
|
961
|
+
await SecureStore3.deleteItemAsync(pendingKey);
|
|
727
962
|
} catch (error) {
|
|
728
963
|
}
|
|
729
964
|
this.activeKeyRecord = null;
|
|
@@ -745,7 +980,7 @@ var ReactNativeStamper = class {
|
|
|
745
980
|
}
|
|
746
981
|
if (this.activeKeyRecord) {
|
|
747
982
|
try {
|
|
748
|
-
await
|
|
983
|
+
await SecureStore3.deleteItemAsync(this.getActiveKeyName());
|
|
749
984
|
} catch (error) {
|
|
750
985
|
}
|
|
751
986
|
}
|
|
@@ -756,7 +991,7 @@ var ReactNativeStamper = class {
|
|
|
756
991
|
this.pendingKeyRecord = null;
|
|
757
992
|
await this.storeKeyRecord(this.activeKeyRecord, "active");
|
|
758
993
|
try {
|
|
759
|
-
await
|
|
994
|
+
await SecureStore3.deleteItemAsync(this.getPendingKeyName());
|
|
760
995
|
} catch (error) {
|
|
761
996
|
}
|
|
762
997
|
}
|
|
@@ -768,7 +1003,7 @@ var ReactNativeStamper = class {
|
|
|
768
1003
|
return;
|
|
769
1004
|
}
|
|
770
1005
|
try {
|
|
771
|
-
await
|
|
1006
|
+
await SecureStore3.deleteItemAsync(this.getPendingKeyName());
|
|
772
1007
|
} catch (error) {
|
|
773
1008
|
}
|
|
774
1009
|
this.pendingKeyRecord = null;
|
|
@@ -794,18 +1029,18 @@ var ReactNativeStamper = class {
|
|
|
794
1029
|
return record;
|
|
795
1030
|
}
|
|
796
1031
|
createKeyId(publicKey) {
|
|
797
|
-
return
|
|
1032
|
+
return base64urlEncode2(new TextEncoder().encode(publicKey)).substring(0, 16);
|
|
798
1033
|
}
|
|
799
1034
|
async storeKeyRecord(record, type) {
|
|
800
1035
|
const keyName = type === "active" ? this.getActiveKeyName() : this.getPendingKeyName();
|
|
801
|
-
await
|
|
1036
|
+
await SecureStore3.setItemAsync(keyName, JSON.stringify(record), {
|
|
802
1037
|
requireAuthentication: false
|
|
803
1038
|
});
|
|
804
1039
|
}
|
|
805
1040
|
async loadActiveKeyRecord() {
|
|
806
1041
|
try {
|
|
807
1042
|
const activeKey = this.getActiveKeyName();
|
|
808
|
-
const storedRecord = await
|
|
1043
|
+
const storedRecord = await SecureStore3.getItemAsync(activeKey);
|
|
809
1044
|
if (storedRecord) {
|
|
810
1045
|
return JSON.parse(storedRecord);
|
|
811
1046
|
}
|
|
@@ -816,7 +1051,7 @@ var ReactNativeStamper = class {
|
|
|
816
1051
|
async loadPendingKeyRecord() {
|
|
817
1052
|
try {
|
|
818
1053
|
const pendingKey = this.getPendingKeyName();
|
|
819
|
-
const storedRecord = await
|
|
1054
|
+
const storedRecord = await SecureStore3.getItemAsync(pendingKey);
|
|
820
1055
|
if (storedRecord) {
|
|
821
1056
|
return JSON.parse(storedRecord);
|
|
822
1057
|
}
|
|
@@ -898,13 +1133,25 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
898
1133
|
}, [config]);
|
|
899
1134
|
const sdk = useMemo2(() => {
|
|
900
1135
|
const storage = new ExpoSecureStorage();
|
|
901
|
-
const authProvider = new ExpoAuthProvider();
|
|
902
1136
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
903
1137
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
904
|
-
const stamper = new ReactNativeStamper({
|
|
1138
|
+
const stamper = config.unstable__auth2Options ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}`) : new ReactNativeStamper({
|
|
905
1139
|
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
906
1140
|
appId: memoizedConfig.appId
|
|
907
1141
|
});
|
|
1142
|
+
const authProvider = config.unstable__auth2Options && config.authOptions?.authUrl && config.authOptions?.redirectUrl && config.apiBaseUrl && stamper instanceof ExpoAuth2Stamper ? new ExpoAuth2AuthProvider(
|
|
1143
|
+
stamper,
|
|
1144
|
+
{
|
|
1145
|
+
redirectUri: config.authOptions.redirectUrl,
|
|
1146
|
+
connectLoginUrl: config.authOptions.authUrl,
|
|
1147
|
+
clientId: config.unstable__auth2Options.clientId,
|
|
1148
|
+
authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
1152
|
+
appId: config.appId
|
|
1153
|
+
}
|
|
1154
|
+
) : new ExpoAuthProvider();
|
|
908
1155
|
const platformName = `${Platform2.OS}-${Platform2.Version}`;
|
|
909
1156
|
const platform = {
|
|
910
1157
|
storage,
|
|
@@ -915,16 +1162,17 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
915
1162
|
name: platformName,
|
|
916
1163
|
analyticsHeaders: {
|
|
917
1164
|
[ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
918
|
-
[ANALYTICS_HEADERS.PLATFORM]:
|
|
1165
|
+
[ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
|
|
919
1166
|
[ANALYTICS_HEADERS.PLATFORM_VERSION]: `${Platform2.Version}`,
|
|
1167
|
+
[ANALYTICS_HEADERS.CLIENT]: Platform2.OS,
|
|
920
1168
|
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
921
1169
|
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
922
|
-
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.
|
|
1170
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.4"
|
|
923
1171
|
// Replaced at build time
|
|
924
1172
|
}
|
|
925
1173
|
};
|
|
926
1174
|
return new EmbeddedProvider(memoizedConfig, platform, logger);
|
|
927
|
-
}, [memoizedConfig, debugConfig, config
|
|
1175
|
+
}, [memoizedConfig, debugConfig, config]);
|
|
928
1176
|
useEffect2(() => {
|
|
929
1177
|
const handleConnectStart = () => {
|
|
930
1178
|
setIsConnecting(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/react-native-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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,15 +45,16 @@
|
|
|
45
45
|
"directory": "packages/react-native-sdk"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@phantom/api-key-stamper": "^1.0.
|
|
49
|
-
"@phantom/
|
|
50
|
-
"@phantom/
|
|
51
|
-
"@phantom/
|
|
52
|
-
"@phantom/
|
|
53
|
-
"@phantom/
|
|
54
|
-
"@phantom/
|
|
55
|
-
"@phantom/
|
|
56
|
-
"@phantom/
|
|
48
|
+
"@phantom/api-key-stamper": "^1.0.4",
|
|
49
|
+
"@phantom/auth2": "^1.0.0",
|
|
50
|
+
"@phantom/base64url": "^1.0.4",
|
|
51
|
+
"@phantom/chain-interfaces": "^1.0.4",
|
|
52
|
+
"@phantom/client": "^1.0.4",
|
|
53
|
+
"@phantom/constants": "^1.0.4",
|
|
54
|
+
"@phantom/crypto": "^1.0.4",
|
|
55
|
+
"@phantom/embedded-provider-core": "^1.0.4",
|
|
56
|
+
"@phantom/sdk-types": "^1.0.4",
|
|
57
|
+
"@phantom/wallet-sdk-ui": "^1.0.4",
|
|
57
58
|
"@types/bs58": "^5.0.0",
|
|
58
59
|
"bs58": "^6.0.0",
|
|
59
60
|
"buffer": "^6.0.3"
|