@phantom/react-native-sdk 1.0.5 → 1.0.7
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 +36 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +104 -33
- package/dist/index.mjs +88 -19
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -489,6 +489,42 @@ The SDK automatically handles deep link redirects. Ensure your app's URL scheme
|
|
|
489
489
|
|
|
490
490
|
**Redirect URL format:** `{scheme}://phantom-auth-callback?wallet_id=...&session_id=...`
|
|
491
491
|
|
|
492
|
+
## Dapp-Sponsored Transactions (presignTransaction)
|
|
493
|
+
|
|
494
|
+
Pass `presignTransaction` directly to `signAndSendTransaction` for calls that need co-signing. Calls without it proceed normally — it is never applied globally.
|
|
495
|
+
|
|
496
|
+
> **Important:** Phantom embedded wallets do not accept pre-signed transactions. If your use case requires a second signer (e.g. your app as the fee payer), that signing must happen via this option, after Phantom has constructed and validated the transaction. This restriction does not apply to injected providers (e.g. the Phantom browser extension).
|
|
497
|
+
|
|
498
|
+
> **Note:** `presignTransaction` only fires for Solana transactions via the embedded provider. EVM transactions are unaffected.
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
import { useSolana, base64urlDecode, base64urlEncode } from "@phantom/react-native-sdk";
|
|
502
|
+
import { Keypair, VersionedTransaction } from "@solana/web3.js";
|
|
503
|
+
|
|
504
|
+
const feePayerKeypair = Keypair.fromSecretKey(/* your fee payer secret key */);
|
|
505
|
+
|
|
506
|
+
function SendWithFeeSponsor() {
|
|
507
|
+
const { solana } = useSolana();
|
|
508
|
+
|
|
509
|
+
const sendSponsored = async () => {
|
|
510
|
+
// This call co-signs as fee payer
|
|
511
|
+
const result = await solana.signAndSendTransaction(transaction, {
|
|
512
|
+
presignTransaction: async (tx, context) => {
|
|
513
|
+
const txBytes = base64urlDecode(tx);
|
|
514
|
+
const versionedTx = VersionedTransaction.deserialize(txBytes);
|
|
515
|
+
versionedTx.sign([feePayerKeypair]);
|
|
516
|
+
return base64urlEncode(versionedTx.serialize());
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
const sendNormal = async () => {
|
|
522
|
+
// This call has no co-signer
|
|
523
|
+
const result = await solana.signAndSendTransaction(transaction);
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
492
528
|
## Security Features
|
|
493
529
|
|
|
494
530
|
### Secure Storage
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,10 @@ export { ConnectErrorEventData, ConnectEventData, ConnectResult, ConnectStartEve
|
|
|
6
6
|
import { PhantomTheme } from '@phantom/wallet-sdk-ui';
|
|
7
7
|
export { PhantomTheme, darkTheme, lightTheme } from '@phantom/wallet-sdk-ui';
|
|
8
8
|
import { ISolanaChain, IEthereumChain } from '@phantom/chain-interfaces';
|
|
9
|
-
export {
|
|
9
|
+
export { SignAndSendTransactionOptions } from '@phantom/chain-interfaces';
|
|
10
|
+
export { AddressType, PresignTransactionContext } from '@phantom/client';
|
|
10
11
|
export { NetworkId } from '@phantom/constants';
|
|
12
|
+
export { base64urlDecode, base64urlEncode } from '@phantom/base64url';
|
|
11
13
|
|
|
12
14
|
interface PhantomDebugConfig {
|
|
13
15
|
/** Enable debug logging */
|
package/dist/index.js
CHANGED
|
@@ -31,8 +31,10 @@ 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_constants5.NetworkId,
|
|
35
35
|
PhantomProvider: () => PhantomProvider,
|
|
36
|
+
base64urlDecode: () => import_base64url3.base64urlDecode,
|
|
37
|
+
base64urlEncode: () => import_base64url3.base64urlEncode,
|
|
36
38
|
darkTheme: () => import_wallet_sdk_ui6.darkTheme,
|
|
37
39
|
lightTheme: () => import_wallet_sdk_ui6.lightTheme,
|
|
38
40
|
useAccounts: () => useAccounts,
|
|
@@ -48,7 +50,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
48
50
|
// src/PhantomProvider.tsx
|
|
49
51
|
var import_react8 = require("react");
|
|
50
52
|
var import_embedded_provider_core = require("@phantom/embedded-provider-core");
|
|
51
|
-
var
|
|
53
|
+
var import_constants4 = require("@phantom/constants");
|
|
52
54
|
var import_wallet_sdk_ui5 = require("@phantom/wallet-sdk-ui");
|
|
53
55
|
|
|
54
56
|
// src/ModalProvider.tsx
|
|
@@ -557,7 +559,7 @@ var ExpoAuthProvider = class {
|
|
|
557
559
|
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
558
560
|
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
559
561
|
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
560
|
-
sdk_version: "1.0.
|
|
562
|
+
sdk_version: "1.0.7",
|
|
561
563
|
sdk_type: "react-native",
|
|
562
564
|
platform: import_react_native5.Platform.OS
|
|
563
565
|
});
|
|
@@ -692,14 +694,14 @@ var ExpoAuth2AuthProvider = class {
|
|
|
692
694
|
if (!code) {
|
|
693
695
|
throw new Error("Auth2 callback missing authorization code");
|
|
694
696
|
}
|
|
695
|
-
const { idToken, bearerToken, authUserId, expiresInMs } = await (0, import_auth2.exchangeAuthCode)({
|
|
697
|
+
const { idToken, bearerToken, authUserId, expiresInMs, refreshToken } = await (0, import_auth2.exchangeAuthCode)({
|
|
696
698
|
authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
|
|
697
699
|
clientId: this.auth2ProviderOptions.clientId,
|
|
698
700
|
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
699
701
|
code,
|
|
700
702
|
codeVerifier
|
|
701
703
|
});
|
|
702
|
-
await this.stamper.
|
|
704
|
+
await this.stamper.setTokens({ idToken, bearerToken, refreshToken, expiresInMs });
|
|
703
705
|
const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
|
|
704
706
|
return {
|
|
705
707
|
walletId,
|
|
@@ -720,16 +722,24 @@ var import_bs58 = __toESM(require("bs58"));
|
|
|
720
722
|
var import_buffer = require("buffer");
|
|
721
723
|
var import_base64url = require("@phantom/base64url");
|
|
722
724
|
var import_sdk_types = require("@phantom/sdk-types");
|
|
725
|
+
var import_auth22 = require("@phantom/auth2");
|
|
726
|
+
var import_constants2 = require("@phantom/constants");
|
|
723
727
|
var ExpoAuth2Stamper = class {
|
|
724
728
|
/**
|
|
725
729
|
* @param storageKey - expo-secure-store key used to persist the P-256 private key.
|
|
726
730
|
* Use a unique key per app, e.g. `phantom-auth2-<appId>`.
|
|
731
|
+
* @param refreshConfig - When provided, the stamper will automatically refresh
|
|
732
|
+
* the id_token using the refresh_token before it expires.
|
|
727
733
|
*/
|
|
728
|
-
constructor(storageKey) {
|
|
734
|
+
constructor(storageKey, refreshConfig) {
|
|
729
735
|
this.storageKey = storageKey;
|
|
736
|
+
this.refreshConfig = refreshConfig;
|
|
730
737
|
this._keyPair = null;
|
|
731
738
|
this._keyInfo = null;
|
|
732
739
|
this._idToken = null;
|
|
740
|
+
this._bearerToken = null;
|
|
741
|
+
this._refreshToken = null;
|
|
742
|
+
this._tokenExpiresAt = null;
|
|
733
743
|
this.algorithm = import_sdk_types.Algorithm.secp256r1;
|
|
734
744
|
this.type = "OIDC";
|
|
735
745
|
}
|
|
@@ -744,6 +754,15 @@ var ExpoAuth2Stamper = class {
|
|
|
744
754
|
if (stored.idToken) {
|
|
745
755
|
this._idToken = stored.idToken;
|
|
746
756
|
}
|
|
757
|
+
if (stored.bearerToken) {
|
|
758
|
+
this._bearerToken = stored.bearerToken;
|
|
759
|
+
}
|
|
760
|
+
if (stored.refreshToken) {
|
|
761
|
+
this._refreshToken = stored.refreshToken;
|
|
762
|
+
}
|
|
763
|
+
if (stored.tokenExpiresAt) {
|
|
764
|
+
this._tokenExpiresAt = stored.tokenExpiresAt;
|
|
765
|
+
}
|
|
747
766
|
return this._keyInfo;
|
|
748
767
|
}
|
|
749
768
|
return this.generateAndStore();
|
|
@@ -755,16 +774,58 @@ var ExpoAuth2Stamper = class {
|
|
|
755
774
|
return this._keyPair;
|
|
756
775
|
}
|
|
757
776
|
/**
|
|
758
|
-
*
|
|
777
|
+
* Returns the current token state (refreshing proactively if near expiry),
|
|
778
|
+
* or null if no token has been set yet.
|
|
779
|
+
*/
|
|
780
|
+
async getTokens() {
|
|
781
|
+
if (this.refreshConfig && this._refreshToken && this._tokenExpiresAt !== null && Date.now() >= this._tokenExpiresAt - import_constants2.TOKEN_REFRESH_BUFFER_MS) {
|
|
782
|
+
const refreshed = await (0, import_auth22.refreshToken)({
|
|
783
|
+
authApiBaseUrl: this.refreshConfig.authApiBaseUrl,
|
|
784
|
+
clientId: this.refreshConfig.clientId,
|
|
785
|
+
redirectUri: this.refreshConfig.redirectUri,
|
|
786
|
+
refreshToken: this._refreshToken
|
|
787
|
+
});
|
|
788
|
+
await this.setTokens(refreshed);
|
|
789
|
+
}
|
|
790
|
+
if (!this._idToken || !this._bearerToken) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
return {
|
|
794
|
+
idToken: this._idToken,
|
|
795
|
+
bearerToken: this._bearerToken,
|
|
796
|
+
refreshToken: this._refreshToken ?? void 0
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Arms the stamper with the OIDC token data for subsequent KMS stamp() calls.
|
|
759
801
|
*
|
|
760
|
-
* Persists the
|
|
761
|
-
* auto-connect can restore
|
|
802
|
+
* Persists the tokens to SecureStore alongside the key pair so that
|
|
803
|
+
* auto-connect can restore them on the next app launch without a new login.
|
|
804
|
+
*
|
|
805
|
+
* @param refreshToken - When provided alongside a `refreshConfig`, enables
|
|
806
|
+
* silent token refresh before the token expires.
|
|
807
|
+
* @param expiresInMs - Token lifetime in milliseconds (from `expires_in * 1000`).
|
|
808
|
+
* Used to compute the absolute expiry time for proactive refresh.
|
|
762
809
|
*/
|
|
763
|
-
async
|
|
810
|
+
async setTokens({
|
|
811
|
+
idToken,
|
|
812
|
+
bearerToken,
|
|
813
|
+
refreshToken,
|
|
814
|
+
expiresInMs
|
|
815
|
+
}) {
|
|
764
816
|
this._idToken = idToken;
|
|
817
|
+
this._bearerToken = bearerToken;
|
|
818
|
+
this._refreshToken = refreshToken ?? null;
|
|
819
|
+
this._tokenExpiresAt = expiresInMs != null ? Date.now() + expiresInMs : null;
|
|
765
820
|
const existing = await this.loadRecord();
|
|
766
821
|
if (existing) {
|
|
767
|
-
await this.storeRecord({
|
|
822
|
+
await this.storeRecord({
|
|
823
|
+
...existing,
|
|
824
|
+
idToken,
|
|
825
|
+
bearerToken,
|
|
826
|
+
refreshToken,
|
|
827
|
+
tokenExpiresAt: this._tokenExpiresAt ?? void 0
|
|
828
|
+
});
|
|
768
829
|
}
|
|
769
830
|
}
|
|
770
831
|
async stamp(params) {
|
|
@@ -797,6 +858,9 @@ var ExpoAuth2Stamper = class {
|
|
|
797
858
|
this._keyPair = null;
|
|
798
859
|
this._keyInfo = null;
|
|
799
860
|
this._idToken = null;
|
|
861
|
+
this._bearerToken = null;
|
|
862
|
+
this._refreshToken = null;
|
|
863
|
+
this._tokenExpiresAt = null;
|
|
800
864
|
}
|
|
801
865
|
// Auth2 doesn't use key rotation; minimal no-op implementations.
|
|
802
866
|
async rotateKeyPair() {
|
|
@@ -940,7 +1004,7 @@ var ExpoURLParamsAccessor = class {
|
|
|
940
1004
|
// src/providers/embedded/stamper.ts
|
|
941
1005
|
var SecureStore3 = __toESM(require("expo-secure-store"));
|
|
942
1006
|
var import_api_key_stamper = require("@phantom/api-key-stamper");
|
|
943
|
-
var
|
|
1007
|
+
var import_constants3 = require("@phantom/constants");
|
|
944
1008
|
var import_crypto = require("@phantom/crypto");
|
|
945
1009
|
var import_base64url2 = require("@phantom/base64url");
|
|
946
1010
|
var ReactNativeStamper = class {
|
|
@@ -948,7 +1012,7 @@ var ReactNativeStamper = class {
|
|
|
948
1012
|
constructor(config = {}) {
|
|
949
1013
|
this.activeKeyRecord = null;
|
|
950
1014
|
this.pendingKeyRecord = null;
|
|
951
|
-
this.algorithm =
|
|
1015
|
+
this.algorithm = import_constants3.DEFAULT_AUTHENTICATOR_ALGORITHM;
|
|
952
1016
|
this.type = "PKI";
|
|
953
1017
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
954
1018
|
this.appId = config.appId || "default";
|
|
@@ -1116,24 +1180,24 @@ var ExpoLogger = class {
|
|
|
1116
1180
|
constructor(enabled = false) {
|
|
1117
1181
|
this.enabled = enabled;
|
|
1118
1182
|
}
|
|
1119
|
-
info(
|
|
1183
|
+
info(message, ...args) {
|
|
1120
1184
|
if (this.enabled) {
|
|
1121
|
-
console.info(`[
|
|
1185
|
+
console.info(`[PHANTOM] ${message}`, ...args);
|
|
1122
1186
|
}
|
|
1123
1187
|
}
|
|
1124
|
-
warn(
|
|
1188
|
+
warn(message, ...args) {
|
|
1125
1189
|
if (this.enabled) {
|
|
1126
|
-
console.warn(`[
|
|
1190
|
+
console.warn(`[PHANTOM] ${message}`, ...args);
|
|
1127
1191
|
}
|
|
1128
1192
|
}
|
|
1129
|
-
error(
|
|
1193
|
+
error(message, ...args) {
|
|
1130
1194
|
if (this.enabled) {
|
|
1131
|
-
console.error(`[
|
|
1195
|
+
console.error(`[PHANTOM] ${message}`, ...args);
|
|
1132
1196
|
}
|
|
1133
1197
|
}
|
|
1134
|
-
|
|
1198
|
+
debug(message, ...args) {
|
|
1135
1199
|
if (this.enabled) {
|
|
1136
|
-
console.log(`[
|
|
1200
|
+
console.log(`[PHANTOM] ${message}`, ...args);
|
|
1137
1201
|
}
|
|
1138
1202
|
}
|
|
1139
1203
|
};
|
|
@@ -1166,12 +1230,12 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
1166
1230
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
1167
1231
|
return {
|
|
1168
1232
|
...config,
|
|
1169
|
-
apiBaseUrl: config.apiBaseUrl ||
|
|
1170
|
-
embeddedWalletType: config.embeddedWalletType ||
|
|
1233
|
+
apiBaseUrl: config.apiBaseUrl || import_constants4.DEFAULT_WALLET_API_URL,
|
|
1234
|
+
embeddedWalletType: config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
1171
1235
|
authOptions: {
|
|
1172
1236
|
...config.authOptions || {},
|
|
1173
1237
|
redirectUrl,
|
|
1174
|
-
authUrl: config.authOptions?.authUrl ||
|
|
1238
|
+
authUrl: config.authOptions?.authUrl || import_constants4.DEFAULT_AUTH_URL
|
|
1175
1239
|
}
|
|
1176
1240
|
};
|
|
1177
1241
|
}, [config]);
|
|
@@ -1179,7 +1243,11 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
1179
1243
|
const storage = new ExpoSecureStorage();
|
|
1180
1244
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
1181
1245
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
1182
|
-
const stamper = config.unstable__auth2Options ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}
|
|
1246
|
+
const stamper = config.unstable__auth2Options && config.authOptions?.redirectUrl ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}`, {
|
|
1247
|
+
authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl,
|
|
1248
|
+
clientId: config.unstable__auth2Options.clientId,
|
|
1249
|
+
redirectUri: config.authOptions.redirectUrl
|
|
1250
|
+
}) : new ReactNativeStamper({
|
|
1183
1251
|
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
1184
1252
|
appId: memoizedConfig.appId
|
|
1185
1253
|
});
|
|
@@ -1205,13 +1273,13 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
1205
1273
|
phantomAppProvider: new ReactNativePhantomAppProvider(),
|
|
1206
1274
|
name: platformName,
|
|
1207
1275
|
analyticsHeaders: {
|
|
1208
|
-
[
|
|
1209
|
-
[
|
|
1210
|
-
[
|
|
1211
|
-
[
|
|
1212
|
-
[
|
|
1213
|
-
[
|
|
1214
|
-
[
|
|
1276
|
+
[import_constants4.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
1277
|
+
[import_constants4.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
|
|
1278
|
+
[import_constants4.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native7.Platform.Version}`,
|
|
1279
|
+
[import_constants4.ANALYTICS_HEADERS.CLIENT]: import_react_native7.Platform.OS,
|
|
1280
|
+
[import_constants4.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1281
|
+
[import_constants4.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1282
|
+
[import_constants4.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.7"
|
|
1215
1283
|
// Replaced at build time
|
|
1216
1284
|
}
|
|
1217
1285
|
};
|
|
@@ -1325,13 +1393,16 @@ function useEthereum() {
|
|
|
1325
1393
|
|
|
1326
1394
|
// src/index.ts
|
|
1327
1395
|
var import_client = require("@phantom/client");
|
|
1328
|
-
var
|
|
1396
|
+
var import_constants5 = require("@phantom/constants");
|
|
1397
|
+
var import_base64url3 = require("@phantom/base64url");
|
|
1329
1398
|
var import_wallet_sdk_ui6 = require("@phantom/wallet-sdk-ui");
|
|
1330
1399
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1331
1400
|
0 && (module.exports = {
|
|
1332
1401
|
AddressType,
|
|
1333
1402
|
NetworkId,
|
|
1334
1403
|
PhantomProvider,
|
|
1404
|
+
base64urlDecode,
|
|
1405
|
+
base64urlEncode,
|
|
1335
1406
|
darkTheme,
|
|
1336
1407
|
lightTheme,
|
|
1337
1408
|
useAccounts,
|
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.7",
|
|
519
519
|
sdk_type: "react-native",
|
|
520
520
|
platform: Platform.OS
|
|
521
521
|
});
|
|
@@ -655,14 +655,14 @@ var ExpoAuth2AuthProvider = class {
|
|
|
655
655
|
if (!code) {
|
|
656
656
|
throw new Error("Auth2 callback missing authorization code");
|
|
657
657
|
}
|
|
658
|
-
const { idToken, bearerToken, authUserId, expiresInMs } = await exchangeAuthCode({
|
|
658
|
+
const { idToken, bearerToken, authUserId, expiresInMs, refreshToken } = await exchangeAuthCode({
|
|
659
659
|
authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
|
|
660
660
|
clientId: this.auth2ProviderOptions.clientId,
|
|
661
661
|
redirectUri: this.auth2ProviderOptions.redirectUri,
|
|
662
662
|
code,
|
|
663
663
|
codeVerifier
|
|
664
664
|
});
|
|
665
|
-
await this.stamper.
|
|
665
|
+
await this.stamper.setTokens({ idToken, bearerToken, refreshToken, expiresInMs });
|
|
666
666
|
const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
|
|
667
667
|
return {
|
|
668
668
|
walletId,
|
|
@@ -683,16 +683,24 @@ import bs58 from "bs58";
|
|
|
683
683
|
import { Buffer } from "buffer";
|
|
684
684
|
import { base64urlEncode } from "@phantom/base64url";
|
|
685
685
|
import { Algorithm } from "@phantom/sdk-types";
|
|
686
|
+
import { refreshToken as refreshTokenRequest } from "@phantom/auth2";
|
|
687
|
+
import { TOKEN_REFRESH_BUFFER_MS } from "@phantom/constants";
|
|
686
688
|
var ExpoAuth2Stamper = class {
|
|
687
689
|
/**
|
|
688
690
|
* @param storageKey - expo-secure-store key used to persist the P-256 private key.
|
|
689
691
|
* Use a unique key per app, e.g. `phantom-auth2-<appId>`.
|
|
692
|
+
* @param refreshConfig - When provided, the stamper will automatically refresh
|
|
693
|
+
* the id_token using the refresh_token before it expires.
|
|
690
694
|
*/
|
|
691
|
-
constructor(storageKey) {
|
|
695
|
+
constructor(storageKey, refreshConfig) {
|
|
692
696
|
this.storageKey = storageKey;
|
|
697
|
+
this.refreshConfig = refreshConfig;
|
|
693
698
|
this._keyPair = null;
|
|
694
699
|
this._keyInfo = null;
|
|
695
700
|
this._idToken = null;
|
|
701
|
+
this._bearerToken = null;
|
|
702
|
+
this._refreshToken = null;
|
|
703
|
+
this._tokenExpiresAt = null;
|
|
696
704
|
this.algorithm = Algorithm.secp256r1;
|
|
697
705
|
this.type = "OIDC";
|
|
698
706
|
}
|
|
@@ -707,6 +715,15 @@ var ExpoAuth2Stamper = class {
|
|
|
707
715
|
if (stored.idToken) {
|
|
708
716
|
this._idToken = stored.idToken;
|
|
709
717
|
}
|
|
718
|
+
if (stored.bearerToken) {
|
|
719
|
+
this._bearerToken = stored.bearerToken;
|
|
720
|
+
}
|
|
721
|
+
if (stored.refreshToken) {
|
|
722
|
+
this._refreshToken = stored.refreshToken;
|
|
723
|
+
}
|
|
724
|
+
if (stored.tokenExpiresAt) {
|
|
725
|
+
this._tokenExpiresAt = stored.tokenExpiresAt;
|
|
726
|
+
}
|
|
710
727
|
return this._keyInfo;
|
|
711
728
|
}
|
|
712
729
|
return this.generateAndStore();
|
|
@@ -718,16 +735,58 @@ var ExpoAuth2Stamper = class {
|
|
|
718
735
|
return this._keyPair;
|
|
719
736
|
}
|
|
720
737
|
/**
|
|
721
|
-
*
|
|
738
|
+
* Returns the current token state (refreshing proactively if near expiry),
|
|
739
|
+
* or null if no token has been set yet.
|
|
740
|
+
*/
|
|
741
|
+
async getTokens() {
|
|
742
|
+
if (this.refreshConfig && this._refreshToken && this._tokenExpiresAt !== null && Date.now() >= this._tokenExpiresAt - TOKEN_REFRESH_BUFFER_MS) {
|
|
743
|
+
const refreshed = await refreshTokenRequest({
|
|
744
|
+
authApiBaseUrl: this.refreshConfig.authApiBaseUrl,
|
|
745
|
+
clientId: this.refreshConfig.clientId,
|
|
746
|
+
redirectUri: this.refreshConfig.redirectUri,
|
|
747
|
+
refreshToken: this._refreshToken
|
|
748
|
+
});
|
|
749
|
+
await this.setTokens(refreshed);
|
|
750
|
+
}
|
|
751
|
+
if (!this._idToken || !this._bearerToken) {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
idToken: this._idToken,
|
|
756
|
+
bearerToken: this._bearerToken,
|
|
757
|
+
refreshToken: this._refreshToken ?? void 0
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Arms the stamper with the OIDC token data for subsequent KMS stamp() calls.
|
|
762
|
+
*
|
|
763
|
+
* Persists the tokens to SecureStore alongside the key pair so that
|
|
764
|
+
* auto-connect can restore them on the next app launch without a new login.
|
|
722
765
|
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
766
|
+
* @param refreshToken - When provided alongside a `refreshConfig`, enables
|
|
767
|
+
* silent token refresh before the token expires.
|
|
768
|
+
* @param expiresInMs - Token lifetime in milliseconds (from `expires_in * 1000`).
|
|
769
|
+
* Used to compute the absolute expiry time for proactive refresh.
|
|
725
770
|
*/
|
|
726
|
-
async
|
|
771
|
+
async setTokens({
|
|
772
|
+
idToken,
|
|
773
|
+
bearerToken,
|
|
774
|
+
refreshToken,
|
|
775
|
+
expiresInMs
|
|
776
|
+
}) {
|
|
727
777
|
this._idToken = idToken;
|
|
778
|
+
this._bearerToken = bearerToken;
|
|
779
|
+
this._refreshToken = refreshToken ?? null;
|
|
780
|
+
this._tokenExpiresAt = expiresInMs != null ? Date.now() + expiresInMs : null;
|
|
728
781
|
const existing = await this.loadRecord();
|
|
729
782
|
if (existing) {
|
|
730
|
-
await this.storeRecord({
|
|
783
|
+
await this.storeRecord({
|
|
784
|
+
...existing,
|
|
785
|
+
idToken,
|
|
786
|
+
bearerToken,
|
|
787
|
+
refreshToken,
|
|
788
|
+
tokenExpiresAt: this._tokenExpiresAt ?? void 0
|
|
789
|
+
});
|
|
731
790
|
}
|
|
732
791
|
}
|
|
733
792
|
async stamp(params) {
|
|
@@ -760,6 +819,9 @@ var ExpoAuth2Stamper = class {
|
|
|
760
819
|
this._keyPair = null;
|
|
761
820
|
this._keyInfo = null;
|
|
762
821
|
this._idToken = null;
|
|
822
|
+
this._bearerToken = null;
|
|
823
|
+
this._refreshToken = null;
|
|
824
|
+
this._tokenExpiresAt = null;
|
|
763
825
|
}
|
|
764
826
|
// Auth2 doesn't use key rotation; minimal no-op implementations.
|
|
765
827
|
async rotateKeyPair() {
|
|
@@ -1079,24 +1141,24 @@ var ExpoLogger = class {
|
|
|
1079
1141
|
constructor(enabled = false) {
|
|
1080
1142
|
this.enabled = enabled;
|
|
1081
1143
|
}
|
|
1082
|
-
info(
|
|
1144
|
+
info(message, ...args) {
|
|
1083
1145
|
if (this.enabled) {
|
|
1084
|
-
console.info(`[
|
|
1146
|
+
console.info(`[PHANTOM] ${message}`, ...args);
|
|
1085
1147
|
}
|
|
1086
1148
|
}
|
|
1087
|
-
warn(
|
|
1149
|
+
warn(message, ...args) {
|
|
1088
1150
|
if (this.enabled) {
|
|
1089
|
-
console.warn(`[
|
|
1151
|
+
console.warn(`[PHANTOM] ${message}`, ...args);
|
|
1090
1152
|
}
|
|
1091
1153
|
}
|
|
1092
|
-
error(
|
|
1154
|
+
error(message, ...args) {
|
|
1093
1155
|
if (this.enabled) {
|
|
1094
|
-
console.error(`[
|
|
1156
|
+
console.error(`[PHANTOM] ${message}`, ...args);
|
|
1095
1157
|
}
|
|
1096
1158
|
}
|
|
1097
|
-
|
|
1159
|
+
debug(message, ...args) {
|
|
1098
1160
|
if (this.enabled) {
|
|
1099
|
-
console.log(`[
|
|
1161
|
+
console.log(`[PHANTOM] ${message}`, ...args);
|
|
1100
1162
|
}
|
|
1101
1163
|
}
|
|
1102
1164
|
};
|
|
@@ -1142,7 +1204,11 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
1142
1204
|
const storage = new ExpoSecureStorage();
|
|
1143
1205
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
1144
1206
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
1145
|
-
const stamper = config.unstable__auth2Options ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}
|
|
1207
|
+
const stamper = config.unstable__auth2Options && config.authOptions?.redirectUrl ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}`, {
|
|
1208
|
+
authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl,
|
|
1209
|
+
clientId: config.unstable__auth2Options.clientId,
|
|
1210
|
+
redirectUri: config.authOptions.redirectUrl
|
|
1211
|
+
}) : new ReactNativeStamper({
|
|
1146
1212
|
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
1147
1213
|
appId: memoizedConfig.appId
|
|
1148
1214
|
});
|
|
@@ -1174,7 +1240,7 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
|
|
|
1174
1240
|
[ANALYTICS_HEADERS.CLIENT]: Platform2.OS,
|
|
1175
1241
|
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1176
1242
|
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1177
|
-
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.
|
|
1243
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.7"
|
|
1178
1244
|
// Replaced at build time
|
|
1179
1245
|
}
|
|
1180
1246
|
};
|
|
@@ -1289,11 +1355,14 @@ function useEthereum() {
|
|
|
1289
1355
|
// src/index.ts
|
|
1290
1356
|
import { AddressType } from "@phantom/client";
|
|
1291
1357
|
import { NetworkId } from "@phantom/constants";
|
|
1358
|
+
import { base64urlEncode as base64urlEncode3, base64urlDecode } from "@phantom/base64url";
|
|
1292
1359
|
import { darkTheme as darkTheme2, lightTheme } from "@phantom/wallet-sdk-ui";
|
|
1293
1360
|
export {
|
|
1294
1361
|
AddressType,
|
|
1295
1362
|
NetworkId,
|
|
1296
1363
|
PhantomProvider,
|
|
1364
|
+
base64urlDecode,
|
|
1365
|
+
base64urlEncode3 as base64urlEncode,
|
|
1297
1366
|
darkTheme2 as darkTheme,
|
|
1298
1367
|
lightTheme,
|
|
1299
1368
|
useAccounts,
|
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.7",
|
|
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,16 +45,16 @@
|
|
|
45
45
|
"directory": "packages/react-native-sdk"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@phantom/api-key-stamper": "^1.0.
|
|
49
|
-
"@phantom/auth2": "^1.0.
|
|
50
|
-
"@phantom/base64url": "^1.0.
|
|
51
|
-
"@phantom/chain-interfaces": "^1.0.
|
|
52
|
-
"@phantom/client": "^1.0.
|
|
53
|
-
"@phantom/constants": "^1.0.
|
|
54
|
-
"@phantom/crypto": "^1.0.
|
|
55
|
-
"@phantom/embedded-provider-core": "^1.0.
|
|
56
|
-
"@phantom/sdk-types": "^1.0.
|
|
57
|
-
"@phantom/wallet-sdk-ui": "^1.0.
|
|
48
|
+
"@phantom/api-key-stamper": "^1.0.7",
|
|
49
|
+
"@phantom/auth2": "^1.0.2",
|
|
50
|
+
"@phantom/base64url": "^1.0.7",
|
|
51
|
+
"@phantom/chain-interfaces": "^1.0.7",
|
|
52
|
+
"@phantom/client": "^1.0.7",
|
|
53
|
+
"@phantom/constants": "^1.0.7",
|
|
54
|
+
"@phantom/crypto": "^1.0.7",
|
|
55
|
+
"@phantom/embedded-provider-core": "^1.0.7",
|
|
56
|
+
"@phantom/sdk-types": "^1.0.7",
|
|
57
|
+
"@phantom/wallet-sdk-ui": "^1.0.7",
|
|
58
58
|
"@types/bs58": "^5.0.0",
|
|
59
59
|
"bs58": "^6.0.0",
|
|
60
60
|
"buffer": "^6.0.3"
|