@solana-mobile/mobile-wallet-adapter-protocol 2.2.0-new-arch-beta → 2.2.0

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.
Files changed (31) hide show
  1. package/README.md +69 -69
  2. package/android/build.gradle +158 -158
  3. package/android/gradle/wrapper/gradle-wrapper.properties +5 -5
  4. package/android/gradle.properties +5 -5
  5. package/android/src/main/java/com/solanamobile/mobilewalletadapter/reactnative/JSONSerializationUtils.kt +11 -9
  6. package/android/src/main/java/com/solanamobile/mobilewalletadapter/reactnative/SolanaMobileWalletAdapterModule.kt +201 -201
  7. package/android/src/main/java/com/solanamobile/mobilewalletadapter/reactnative/SolanaMobileWalletAdapterPackage.kt +35 -35
  8. package/android/src/newarch/SolanaMobileWalletAdapter.kt +7 -7
  9. package/android/src/oldarch/SolanaMobileWalletAdapter.kt +16 -16
  10. package/lib/cjs/index.browser.js +249 -184
  11. package/lib/cjs/index.js +249 -184
  12. package/lib/cjs/index.native.js +8 -0
  13. package/lib/esm/index.browser.js +249 -184
  14. package/lib/esm/index.js +249 -184
  15. package/lib/types/index.browser.d.ts +10 -4
  16. package/lib/types/index.browser.d.ts.map +1 -1
  17. package/lib/types/index.d.ts +10 -4
  18. package/lib/types/index.d.ts.map +1 -1
  19. package/lib/types/index.native.d.ts +10 -4
  20. package/lib/types/index.native.d.ts.map +1 -1
  21. package/package.json +71 -66
  22. package/src/__forks__/react-native/base64Utils.ts +1 -1
  23. package/src/__forks__/react-native/transact.ts +91 -91
  24. package/src/base64Utils.ts +19 -0
  25. package/src/codegenSpec/NativeSolanaMobileWalletAdapter.ts +13 -13
  26. package/src/createMobileWalletProxy.ts +7 -0
  27. package/src/errors.ts +2 -0
  28. package/src/getAssociateAndroidIntentURL.ts +3 -4
  29. package/src/startSession.ts +2 -34
  30. package/src/transact.ts +593 -499
  31. package/src/types.ts +9 -0
@@ -11,6 +11,7 @@ declare const SolanaMobileWalletAdapterErrorCode: {
11
11
  readonly ERROR_SESSION_TIMEOUT: "ERROR_SESSION_TIMEOUT";
12
12
  readonly ERROR_WALLET_NOT_FOUND: "ERROR_WALLET_NOT_FOUND";
13
13
  readonly ERROR_INVALID_PROTOCOL_VERSION: "ERROR_INVALID_PROTOCOL_VERSION";
14
+ readonly ERROR_BROWSER_NOT_SUPPORTED: "ERROR_BROWSER_NOT_SUPPORTED";
14
15
  };
15
16
  type SolanaMobileWalletAdapterErrorCodeEnum = (typeof SolanaMobileWalletAdapterErrorCode)[keyof typeof SolanaMobileWalletAdapterErrorCode];
16
17
  type ErrorDataTypeMap = {
@@ -28,6 +29,7 @@ type ErrorDataTypeMap = {
28
29
  [SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT]: undefined;
29
30
  [SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND]: undefined;
30
31
  [SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION]: undefined;
32
+ [SolanaMobileWalletAdapterErrorCode.ERROR_BROWSER_NOT_SUPPORTED]: undefined;
31
33
  };
32
34
  declare class SolanaMobileWalletAdapterError<TErrorCode extends SolanaMobileWalletAdapterErrorCodeEnum> extends Error {
33
35
  data: ErrorDataTypeMap[TErrorCode] | undefined;
@@ -248,10 +250,14 @@ type SignInResult = Readonly<{
248
250
  signature: Base64EncodedAddress;
249
251
  signature_type?: string;
250
252
  }>;
251
- declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
252
- declare function transactRemote<TReturn>(callback: (wallet: RemoteMobileWallet) => TReturn, config: RemoteWalletAssociationConfig): Promise<{
253
+ type Scenario = Readonly<{
254
+ wallet: Promise<MobileWallet>;
255
+ close: () => void;
256
+ }>;
257
+ type RemoteScenario = Scenario & Readonly<{
253
258
  associationUrl: URL;
254
- result: Promise<TReturn>;
255
259
  }>;
256
- export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, transactRemote, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult };
260
+ declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
261
+ declare function startRemoteScenario(config: RemoteWalletAssociationConfig): Promise<RemoteScenario>;
262
+ export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, startRemoteScenario, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult, Scenario, RemoteScenario };
257
263
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/createHelloReq.ts","../../src/types.ts","../../src/base64Utils.ts","../../src/createSIWSMessage.ts","../../src/createMobileWalletProxy.ts","../../src/createSequenceNumberVector.ts","../../src/parseHelloRsp.ts","../../src/encryptedMessage.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/jsonRpcMessage.ts","../../src/parseSessionProps.ts","../../src/associationPort.ts","../../src/arrayBufferToBase64String.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/reflectorId.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/startSession.ts","../../src/transact.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/base64Utils.ts","../../src/createHelloReq.ts","../../src/types.ts","../../src/createSIWSMessage.ts","../../src/createMobileWalletProxy.ts","../../src/createSequenceNumberVector.ts","../../src/parseHelloRsp.ts","../../src/encryptedMessage.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/arrayBufferToBase64String.ts","../../src/associationPort.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/jsonRpcMessage.ts","../../src/parseSessionProps.ts","../../src/startSession.ts","../../src/transact.ts"],"names":[],"mappings":""}
@@ -11,6 +11,7 @@ declare const SolanaMobileWalletAdapterErrorCode: {
11
11
  readonly ERROR_SESSION_TIMEOUT: "ERROR_SESSION_TIMEOUT";
12
12
  readonly ERROR_WALLET_NOT_FOUND: "ERROR_WALLET_NOT_FOUND";
13
13
  readonly ERROR_INVALID_PROTOCOL_VERSION: "ERROR_INVALID_PROTOCOL_VERSION";
14
+ readonly ERROR_BROWSER_NOT_SUPPORTED: "ERROR_BROWSER_NOT_SUPPORTED";
14
15
  };
15
16
  type SolanaMobileWalletAdapterErrorCodeEnum = (typeof SolanaMobileWalletAdapterErrorCode)[keyof typeof SolanaMobileWalletAdapterErrorCode];
16
17
  type ErrorDataTypeMap = {
@@ -28,6 +29,7 @@ type ErrorDataTypeMap = {
28
29
  [SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT]: undefined;
29
30
  [SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND]: undefined;
30
31
  [SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION]: undefined;
32
+ [SolanaMobileWalletAdapterErrorCode.ERROR_BROWSER_NOT_SUPPORTED]: undefined;
31
33
  };
32
34
  declare class SolanaMobileWalletAdapterError<TErrorCode extends SolanaMobileWalletAdapterErrorCodeEnum> extends Error {
33
35
  data: ErrorDataTypeMap[TErrorCode] | undefined;
@@ -248,10 +250,14 @@ type SignInResult = Readonly<{
248
250
  signature: Base64EncodedAddress;
249
251
  signature_type?: string;
250
252
  }>;
251
- declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
252
- declare function transactRemote<TReturn>(callback: (wallet: RemoteMobileWallet) => TReturn, config: RemoteWalletAssociationConfig): Promise<{
253
+ type Scenario = Readonly<{
254
+ wallet: Promise<MobileWallet>;
255
+ close: () => void;
256
+ }>;
257
+ type RemoteScenario = Scenario & Readonly<{
253
258
  associationUrl: URL;
254
- result: Promise<TReturn>;
255
259
  }>;
256
- export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, transactRemote, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult };
260
+ declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
261
+ declare function startRemoteScenario(config: RemoteWalletAssociationConfig): Promise<RemoteScenario>;
262
+ export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, startRemoteScenario, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult, Scenario, RemoteScenario };
257
263
  //# sourceMappingURL=index.native.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.native.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/createHelloReq.ts","../../src/types.ts","../../src/base64Utils.ts","../../src/createSIWSMessage.ts","../../src/createMobileWalletProxy.ts","../../src/createSequenceNumberVector.ts","../../src/parseHelloRsp.ts","../../src/encryptedMessage.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/jsonRpcMessage.ts","../../src/parseSessionProps.ts","../../src/associationPort.ts","../../src/arrayBufferToBase64String.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/reflectorId.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/startSession.ts","../../src/transact.ts","../../src/codegenSpec/NativeSolanaMobileWalletAdapter.ts","../../src/__forks__/react-native/transact.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.native.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/base64Utils.ts","../../src/createHelloReq.ts","../../src/types.ts","../../src/createSIWSMessage.ts","../../src/createMobileWalletProxy.ts","../../src/createSequenceNumberVector.ts","../../src/parseHelloRsp.ts","../../src/encryptedMessage.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/arrayBufferToBase64String.ts","../../src/associationPort.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/jsonRpcMessage.ts","../../src/parseSessionProps.ts","../../src/startSession.ts","../../src/transact.ts","../../src/codegenSpec/NativeSolanaMobileWalletAdapter.ts","../../src/__forks__/react-native/transact.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,66 +1,71 @@
1
- {
2
- "name": "@solana-mobile/mobile-wallet-adapter-protocol",
3
- "description": "An implementation of the Solana Mobile Mobile Wallet Adapter protocol. Use this to open a session with a mobile wallet app, and to issue API calls to it.",
4
- "version": "2.2.0-new-arch-beta",
5
- "author": "Steven Luscher <steven.luscher@solanamobile.com>",
6
- "repository": "https://github.com/solana-mobile/mobile-wallet-adapter",
7
- "license": "Apache-2.0",
8
- "type": "module",
9
- "sideEffects": false,
10
- "main": "lib/cjs/index.js",
11
- "react-native": "lib/cjs/index.native.js",
12
- "module": "lib/esm/index.js",
13
- "types": "lib/types/index.d.ts",
14
- "browser": {
15
- "./lib/cjs/index.js": "./lib/cjs/index.browser.js",
16
- "./lib/esm/index.js": "./lib/esm/index.browser.js"
17
- },
18
- "exports": {
19
- "./package.json": "./package.json",
20
- ".": {
21
- "import": "./lib/esm/index.js",
22
- "require": "./lib/cjs/index.js"
23
- }
24
- },
25
- "files": [
26
- "android",
27
- "!android/build",
28
- "lib",
29
- "LICENSE"
30
- ],
31
- "publishConfig": {
32
- "access": "public"
33
- },
34
- "scripts": {
35
- "clean": "shx rm -rf lib/*",
36
- "build": "yarn clean && rollup --config ../../rollup.config.ts --configPlugin rollup-plugin-ts",
37
- "build:watch": "yarn clean && rollup --config ../../rollup.config.ts --configPlugin rollup-plugin-ts --watch",
38
- "postbuild": "cross-env echo {\\\"type\\\":\\\"commonjs\\\"} | npx json > lib/cjs/package.json && echo {\\\"type\\\":\\\"module\\\"} | npx json > lib/esm/package.json",
39
- "prepublishOnly": "agadoo"
40
- },
41
- "dependencies": {
42
- "@solana/wallet-standard": "^1.1.2",
43
- "@solana/wallet-standard-util": "^1.1.1",
44
- "@wallet-standard/core": "^1.0.3",
45
- "js-base64": "^3.7.5"
46
- },
47
- "devDependencies": {
48
- "@solana/web3.js": "^1.91.7",
49
- "@types/react-native": "^0.69.3",
50
- "agadoo": "^3.0.0",
51
- "cross-env": "^7.0.3",
52
- "shx": "^0.3.4"
53
- },
54
- "peerDependencies": {
55
- "@solana/web3.js": "^1.58.0",
56
- "react-native": ">0.69"
57
- },
58
- "codegenConfig": {
59
- "name": "SolanaMobileWalletAdapter",
60
- "type": "all",
61
- "jsSrcsDir": "./src/codegenSpec",
62
- "android": {
63
- "javaPackageName": "com.solanamobile.mobilewalletadapter.reactnative"
64
- }
65
- }
66
- }
1
+ {
2
+ "name": "@solana-mobile/mobile-wallet-adapter-protocol",
3
+ "description": "An implementation of the Solana Mobile Mobile Wallet Adapter protocol. Use this to open a session with a mobile wallet app, and to issue API calls to it.",
4
+ "version": "2.2.0",
5
+ "author": "Steven Luscher <steven.luscher@solanamobile.com>",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/solana-mobile/mobile-wallet-adapter.git"
9
+ },
10
+ "license": "Apache-2.0",
11
+ "type": "module",
12
+ "sideEffects": false,
13
+ "main": "lib/cjs/index.js",
14
+ "react-native": "lib/cjs/index.native.js",
15
+ "module": "lib/esm/index.js",
16
+ "types": "lib/types/index.d.ts",
17
+ "browser": {
18
+ "./lib/cjs/index.js": "./lib/cjs/index.browser.js",
19
+ "./lib/esm/index.js": "./lib/esm/index.browser.js"
20
+ },
21
+ "exports": {
22
+ "./package.json": "./package.json",
23
+ ".": {
24
+ "import": "./lib/esm/index.js",
25
+ "require": "./lib/cjs/index.js",
26
+ "types": "./lib/types/index.d.ts"
27
+ }
28
+ },
29
+ "files": [
30
+ "android",
31
+ "src/codegenSpec",
32
+ "!android/build",
33
+ "lib",
34
+ "LICENSE"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "clean": "shx rm -rf lib/*",
41
+ "build": "yarn clean && rollup --config ../../rollup.config.ts --configPlugin rollup-plugin-ts",
42
+ "build:watch": "yarn clean && rollup --config ../../rollup.config.ts --configPlugin rollup-plugin-ts --watch",
43
+ "postbuild": "cross-env echo {\\\"type\\\":\\\"commonjs\\\"} | npx json > lib/cjs/package.json && echo {\\\"type\\\":\\\"module\\\"} | npx json > lib/esm/package.json",
44
+ "prepublishOnly": "agadoo"
45
+ },
46
+ "dependencies": {
47
+ "@solana/wallet-standard": "^1.1.2",
48
+ "@solana/wallet-standard-util": "^1.1.1",
49
+ "@wallet-standard/core": "^1.0.3",
50
+ "js-base64": "^3.7.5"
51
+ },
52
+ "devDependencies": {
53
+ "@solana/web3.js": "^1.91.7",
54
+ "@types/react-native": "^0.69.3",
55
+ "agadoo": "^3.0.0",
56
+ "cross-env": "^7.0.3",
57
+ "shx": "^0.3.4"
58
+ },
59
+ "peerDependencies": {
60
+ "@solana/web3.js": "^1.58.0",
61
+ "react-native": ">0.69"
62
+ },
63
+ "codegenConfig": {
64
+ "name": "SolanaMobileWalletAdapter",
65
+ "type": "all",
66
+ "jsSrcsDir": "./src/codegenSpec",
67
+ "android": {
68
+ "javaPackageName": "com.solanamobile.mobilewalletadapter.reactnative"
69
+ }
70
+ }
71
+ }
@@ -1 +1 @@
1
- export { encode } from 'js-base64';
1
+ export { encode, fromUint8Array, toUint8Array } from 'js-base64';
@@ -1,91 +1,91 @@
1
- import { Platform } from 'react-native';
2
-
3
- import NativeSolanaMobileWalletAdapter from '../../codegenSpec/NativeSolanaMobileWalletAdapter.js';
4
- import createMobileWalletProxy from '../../createMobileWalletProxy.js';
5
- import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolError } from '../../errors.js';
6
- import { MobileWallet, SessionProperties, WalletAssociationConfig } from '../../types.js';
7
-
8
- type ReactNativeError = Error & { code?: string; userInfo?: Record<string, unknown> };
9
-
10
- const LINKING_ERROR =
11
- `The package 'solana-mobile-wallet-adapter-protocol' doesn't seem to be linked. Make sure: \n\n` +
12
- '- You rebuilt the app after installing the package\n' +
13
- '- If you are using Lerna workspaces\n' +
14
- ' - You have added `@solana-mobile/mobile-wallet-adapter-protocol` as an explicit dependency, and\n' +
15
- ' - You have added `@solana-mobile/mobile-wallet-adapter-protocol` to the `nohoist` section of your package.json\n' +
16
- '- You are not using Expo managed workflow\n';
17
-
18
- const SolanaMobileWalletAdapter =
19
- Platform.OS === 'android' && NativeSolanaMobileWalletAdapter
20
- ? NativeSolanaMobileWalletAdapter
21
- : (new Proxy(
22
- {},
23
- {
24
- get() {
25
- throw new Error(
26
- Platform.OS !== 'android'
27
- ? 'The package `solana-mobile-wallet-adapter-protocol` is only compatible with React Native Android'
28
- : LINKING_ERROR,
29
- );
30
- },
31
- },
32
- ) as typeof NativeSolanaMobileWalletAdapter);
33
-
34
- function getErrorMessage(e: ReactNativeError): string {
35
- switch (e.code) {
36
- case 'ERROR_WALLET_NOT_FOUND':
37
- return 'Found no installed wallet that supports the mobile wallet protocol.';
38
- default:
39
- return e.message;
40
- }
41
- }
42
-
43
- function handleError(e: any): never {
44
- if (e instanceof Error) {
45
- const reactNativeError: ReactNativeError = e;
46
- switch (reactNativeError.code) {
47
- case undefined:
48
- throw e;
49
- case 'JSON_RPC_ERROR': {
50
- const details = reactNativeError.userInfo as Readonly<{ jsonRpcErrorCode: number }>;
51
- throw new SolanaMobileWalletAdapterProtocolError(
52
- 0 /* jsonRpcMessageId */,
53
- details.jsonRpcErrorCode,
54
- e.message,
55
- );
56
- }
57
- default:
58
- throw new SolanaMobileWalletAdapterError<any>(
59
- reactNativeError.code,
60
- getErrorMessage(reactNativeError),
61
- reactNativeError.userInfo,
62
- );
63
- }
64
- }
65
- throw e;
66
- }
67
-
68
- export async function transact<TReturn>(
69
- callback: (wallet: MobileWallet) => TReturn,
70
- config?: WalletAssociationConfig,
71
- ): Promise<TReturn> {
72
- let didSuccessfullyConnect = false;
73
- try {
74
- const sessionProperties: SessionProperties = await SolanaMobileWalletAdapter.startSession(config);
75
- didSuccessfullyConnect = true;
76
- const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
77
- try {
78
- return SolanaMobileWalletAdapter.invoke(method, params);
79
- } catch (e) {
80
- return handleError(e);
81
- }
82
- });
83
- return await callback(wallet);
84
- } catch (e) {
85
- return handleError(e);
86
- } finally {
87
- if (didSuccessfullyConnect) {
88
- await SolanaMobileWalletAdapter.endSession();
89
- }
90
- }
91
- }
1
+ import { Platform } from 'react-native';
2
+
3
+ import NativeSolanaMobileWalletAdapter from '../../codegenSpec/NativeSolanaMobileWalletAdapter.js';
4
+ import createMobileWalletProxy from '../../createMobileWalletProxy.js';
5
+ import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolError } from '../../errors.js';
6
+ import { MobileWallet, SessionProperties, WalletAssociationConfig } from '../../types.js';
7
+
8
+ type ReactNativeError = Error & { code?: string; userInfo?: Record<string, unknown> };
9
+
10
+ const LINKING_ERROR =
11
+ `The package 'solana-mobile-wallet-adapter-protocol' doesn't seem to be linked. Make sure: \n\n` +
12
+ '- You rebuilt the app after installing the package\n' +
13
+ '- If you are using Lerna workspaces\n' +
14
+ ' - You have added `@solana-mobile/mobile-wallet-adapter-protocol` as an explicit dependency, and\n' +
15
+ ' - You have added `@solana-mobile/mobile-wallet-adapter-protocol` to the `nohoist` section of your package.json\n' +
16
+ '- You are not using Expo managed workflow\n';
17
+
18
+ const SolanaMobileWalletAdapter =
19
+ Platform.OS === 'android' && NativeSolanaMobileWalletAdapter
20
+ ? NativeSolanaMobileWalletAdapter
21
+ : (new Proxy(
22
+ {},
23
+ {
24
+ get() {
25
+ throw new Error(
26
+ Platform.OS !== 'android'
27
+ ? 'The package `solana-mobile-wallet-adapter-protocol` is only compatible with React Native Android'
28
+ : LINKING_ERROR,
29
+ );
30
+ },
31
+ },
32
+ ) as typeof NativeSolanaMobileWalletAdapter);
33
+
34
+ function getErrorMessage(e: ReactNativeError): string {
35
+ switch (e.code) {
36
+ case 'ERROR_WALLET_NOT_FOUND':
37
+ return 'Found no installed wallet that supports the mobile wallet protocol.';
38
+ default:
39
+ return e.message;
40
+ }
41
+ }
42
+
43
+ function handleError(e: any): never {
44
+ if (e instanceof Error) {
45
+ const reactNativeError: ReactNativeError = e;
46
+ switch (reactNativeError.code) {
47
+ case undefined:
48
+ throw e;
49
+ case 'JSON_RPC_ERROR': {
50
+ const details = reactNativeError.userInfo as Readonly<{ jsonRpcErrorCode: number }>;
51
+ throw new SolanaMobileWalletAdapterProtocolError(
52
+ 0 /* jsonRpcMessageId */,
53
+ details.jsonRpcErrorCode,
54
+ e.message,
55
+ );
56
+ }
57
+ default:
58
+ throw new SolanaMobileWalletAdapterError<any>(
59
+ reactNativeError.code,
60
+ getErrorMessage(reactNativeError),
61
+ reactNativeError.userInfo,
62
+ );
63
+ }
64
+ }
65
+ throw e;
66
+ }
67
+
68
+ export async function transact<TReturn>(
69
+ callback: (wallet: MobileWallet) => TReturn,
70
+ config?: WalletAssociationConfig,
71
+ ): Promise<TReturn> {
72
+ let didSuccessfullyConnect = false;
73
+ try {
74
+ const sessionProperties: SessionProperties = await SolanaMobileWalletAdapter.startSession(config);
75
+ didSuccessfullyConnect = true;
76
+ const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
77
+ try {
78
+ return SolanaMobileWalletAdapter.invoke(method, params);
79
+ } catch (e) {
80
+ return handleError(e);
81
+ }
82
+ });
83
+ return await callback(wallet);
84
+ } catch (e) {
85
+ return handleError(e);
86
+ } finally {
87
+ if (didSuccessfullyConnect) {
88
+ await SolanaMobileWalletAdapter.endSession();
89
+ }
90
+ }
91
+ }
@@ -1,3 +1,22 @@
1
1
  export function encode(input: string): string {
2
2
  return window.btoa(input);
3
+ }
4
+
5
+ export function fromUint8Array(byteArray: Uint8Array, urlsafe?: boolean): string {
6
+ const base64 = window.btoa(String.fromCharCode.call(null, ...byteArray));
7
+ if (urlsafe) {
8
+ return base64
9
+ .replace(/\+/g, '-')
10
+ .replace(/\//g, '_')
11
+ .replace(/=+$/, '');
12
+ } else return base64;
13
+ }
14
+
15
+ export function toUint8Array(base64EncodedByteArray: string): Uint8Array {
16
+ return new Uint8Array(
17
+ window
18
+ .atob(base64EncodedByteArray)
19
+ .split('')
20
+ .map((c) => c.charCodeAt(0)),
21
+ );
3
22
  }
@@ -1,13 +1,13 @@
1
- import { TurboModule, TurboModuleRegistry } from 'react-native';
2
-
3
- export interface Spec extends TurboModule {
4
- startSession(config?: { baseUri?: string }): Promise<{
5
- protocol_version: 'legacy' | 'v1';
6
- }>;
7
-
8
- invoke(method: string, params: Object | undefined): Promise<Object>;
9
-
10
- endSession(): Promise<boolean>;
11
- }
12
-
13
- export default TurboModuleRegistry.getEnforcing<Spec>('SolanaMobileWalletAdapter') as Spec;
1
+ import { TurboModule, TurboModuleRegistry } from 'react-native';
2
+
3
+ export interface Spec extends TurboModule {
4
+ startSession(config?: { baseUri?: string }): Promise<{
5
+ protocol_version: 'legacy' | 'v1';
6
+ }>;
7
+
8
+ invoke(method: string, params: Object | undefined): Promise<Object>;
9
+
10
+ endSession(): Promise<boolean>;
11
+ }
12
+
13
+ export default TurboModuleRegistry.getEnforcing<Spec>('SolanaMobileWalletAdapter') as Spec;
@@ -26,6 +26,13 @@ export default function createMobileWalletProxy<
26
26
  ): MobileWallet {
27
27
  return new Proxy<MobileWallet>({} as MobileWallet, {
28
28
  get<TMethodName extends keyof MobileWallet>(target: MobileWallet, p: TMethodName) {
29
+ // Wrapping a Proxy in a promise results in the Proxy being asked for a 'then' property so must
30
+ // return null if 'then' is called on this proxy to let the 'resolve()' call know this is not a promise.
31
+ // see: https://stackoverflow.com/a/53890904
32
+ //@ts-ignore
33
+ if (p === 'then') {
34
+ return null;
35
+ }
29
36
  if (target[p] == null) {
30
37
  target[p] = async function (inputParams: Parameters<MobileWallet[TMethodName]>[0]) {
31
38
  const { method, params } = handleMobileWalletRequest(p, inputParams, protocolVersion);
package/src/errors.ts CHANGED
@@ -8,6 +8,7 @@ export const SolanaMobileWalletAdapterErrorCode = {
8
8
  ERROR_SESSION_TIMEOUT: 'ERROR_SESSION_TIMEOUT',
9
9
  ERROR_WALLET_NOT_FOUND: 'ERROR_WALLET_NOT_FOUND',
10
10
  ERROR_INVALID_PROTOCOL_VERSION: 'ERROR_INVALID_PROTOCOL_VERSION',
11
+ ERROR_BROWSER_NOT_SUPPORTED: 'ERROR_BROWSER_NOT_SUPPORTED',
11
12
  } as const;
12
13
  type SolanaMobileWalletAdapterErrorCodeEnum =
13
14
  typeof SolanaMobileWalletAdapterErrorCode[keyof typeof SolanaMobileWalletAdapterErrorCode];
@@ -27,6 +28,7 @@ type ErrorDataTypeMap = {
27
28
  [SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT]: undefined;
28
29
  [SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND]: undefined;
29
30
  [SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION]: undefined;
31
+ [SolanaMobileWalletAdapterErrorCode.ERROR_BROWSER_NOT_SUPPORTED]: undefined;
30
32
  };
31
33
 
32
34
  export class SolanaMobileWalletAdapterError<TErrorCode extends SolanaMobileWalletAdapterErrorCodeEnum> extends Error {
@@ -2,8 +2,8 @@ import arrayBufferToBase64String from './arrayBufferToBase64String.js';
2
2
  import { assertAssociationPort } from './associationPort.js';
3
3
  import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from './errors.js';
4
4
  import getStringWithURLUnsafeBase64CharactersReplaced from './getStringWithURLUnsafeBase64CharactersReplaced.js';
5
- import { assertReflectorId } from './reflectorId.js';
6
5
  import { ProtocolVersion } from './types.js';
6
+ import { fromUint8Array } from './base64Utils.js';
7
7
 
8
8
  const INTENT_NAME = 'solana-wallet';
9
9
 
@@ -60,17 +60,16 @@ export default async function getAssociateAndroidIntentURL(
60
60
  export async function getRemoteAssociateAndroidIntentURL(
61
61
  associationPublicKey: CryptoKey,
62
62
  hostAuthority: string,
63
- putativeId: number,
63
+ reflectorId: Uint8Array,
64
64
  associationURLBase?: string,
65
65
  protocolVersions: ProtocolVersion[] = ['v1'],
66
66
  ): Promise<URL> {
67
- const reflectorId = assertReflectorId(putativeId);
68
67
  const exportedKey = await crypto.subtle.exportKey('raw', associationPublicKey);
69
68
  const encodedKey = arrayBufferToBase64String(exportedKey);
70
69
  const url = getIntentURL('v1/associate/remote', associationURLBase);
71
70
  url.searchParams.set('association', getStringWithURLUnsafeBase64CharactersReplaced(encodedKey));
72
71
  url.searchParams.set('reflector', `${hostAuthority}`);
73
- url.searchParams.set('id', `${reflectorId}`);
72
+ url.searchParams.set('id', `${fromUint8Array(reflectorId, true)}`);
74
73
  protocolVersions.forEach( (version) => {
75
74
  url.searchParams.set('v', version);
76
75
  })
@@ -1,7 +1,6 @@
1
1
  import { AssociationPort, getRandomAssociationPort } from './associationPort.js';
2
2
  import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from './errors.js';
3
- import getAssociateAndroidIntentURL, { getRemoteAssociateAndroidIntentURL } from './getAssociateAndroidIntentURL.js';
4
- import { assertReflectorId, getRandomReflectorId, ReflectorId } from './reflectorId.js';
3
+ import getAssociateAndroidIntentURL from './getAssociateAndroidIntentURL.js';
5
4
 
6
5
  // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
7
6
  const Browser = {
@@ -35,7 +34,7 @@ function getDetectionPromise() {
35
34
  const timeoutId = setTimeout(() => {
36
35
  cleanup();
37
36
  reject();
38
- }, 2000);
37
+ }, 3000);
39
38
  });
40
39
  }
41
40
 
@@ -96,35 +95,4 @@ export async function startSession(
96
95
  );
97
96
  await launchAssociation(associationUrl);
98
97
  return randomAssociationPort;
99
- }
100
-
101
- export async function startRemoteSession(
102
- associationPublicKey: CryptoKey,
103
- hostAuthority: string,
104
- associationURLBase?: string,
105
- ): Promise<ReflectorId> {
106
- const randomReflectorId = getRandomReflectorId();
107
- const associationUrl = await getRemoteAssociateAndroidIntentURL(
108
- associationPublicKey,
109
- hostAuthority,
110
- randomReflectorId,
111
- associationURLBase,
112
- );
113
- await launchAssociation(associationUrl);
114
- return randomReflectorId;
115
- }
116
-
117
- export async function getRemoteSessionUrl(
118
- associationPublicKey: CryptoKey,
119
- hostAuthority: string,
120
- associationURLBase?: string,
121
- ): Promise<{associationUrl: URL, reflectorId: ReflectorId }> {
122
- const randomReflectorId = getRandomReflectorId();
123
- const associationUrl = await getRemoteAssociateAndroidIntentURL(
124
- associationPublicKey,
125
- hostAuthority,
126
- randomReflectorId,
127
- associationURLBase,
128
- );
129
- return { associationUrl, reflectorId: randomReflectorId };
130
98
  }