@solana-mobile/wallet-adapter-mobile 0.9.0 → 0.9.2

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 CHANGED
@@ -17,6 +17,7 @@ new SolanaMobileWalletAdapter({
17
17
  icon: 'relative/path/to/icon.png',
18
18
  },
19
19
  authorizationResultCache: createDefaultAuthorizationResultCache(),
20
+ cluster: WalletAdapterNetwork.Devnet,
20
21
  });
21
22
  ```
22
23
 
@@ -32,6 +33,7 @@ const wallets = useMemo(() => [
32
33
  icon: 'relative/path/to/icon.png',
33
34
  },
34
35
  authorizationResultCache: createDefaultAuthorizationResultCache(),
36
+ cluster: WalletAdapterNetwork.Devnet,
35
37
  });
36
38
  new PhantomWalletAdapter(),
37
39
  /* ... other wallets ... */
@@ -58,6 +60,18 @@ The `AppIdentity` config identifies your app to a native mobile wallet. When som
58
60
  - `uri` – The uri of your application. This uri may be required to participate in [dApp identity verification](https://github.com/solana-mobile/mobile-wallet-adapter/blob/main/spec/spec.md#dapp-identity-verification) as part of the mobile wallet adapter protocol specification.
59
61
  - `icon` – An icon file path, relative to the `uri`.
60
62
 
63
+ ### Address selector
64
+
65
+ The Mobile Wallet Adapter specification allows a wallet to authorize a dApp to use one or more addresses. dApps must supply code to select a single address for use in the adapter. That code must conform to the `AddressSelector` interface.
66
+
67
+ ```typescript
68
+ export interface AddressSelector {
69
+ select(addresses: Base64EncodedAddress[]): Promise<Base64EncodedAddress>;
70
+ }
71
+ ```
72
+
73
+ Alternatively, you can use the included `createDefaultAddressSelector()` method to create a selector that always chooses the first address in the list.
74
+
61
75
  ### Authorization result cache
62
76
 
63
77
  The first time that someone authorizes a native wallet app for use with your application, you should cache that authorization for future use. You can supply your own implementation that conforms to the `AuthorizationResultCache` interface.
@@ -72,3 +86,6 @@ export interface AuthorizationResultCache {
72
86
 
73
87
  Alternatively, you can use the included `createDefaultAuthorizationResultCache()` method to create a cache that reads and writes the adapter's last-obtained `AuthorizationResult` to your browser's local storage, if available.
74
88
 
89
+ ### Cluster
90
+
91
+ Each authorization a dApp makes with a wallet is tied to a particular Solana cluster. If a dApp wants to change the cluster on which to transact, it must seek an authorization for that cluster.
@@ -6,7 +6,7 @@ var mobileWalletAdapterProtocolWeb3js = require('@solana-mobile/mobile-wallet-ad
6
6
  var walletAdapterBase = require('@solana/wallet-adapter-base');
7
7
  var web3_js = require('@solana/web3.js');
8
8
 
9
- /******************************************************************************
9
+ /*! *****************************************************************************
10
10
  Copyright (c) Microsoft Corporation.
11
11
 
12
12
  Permission to use, copy, modify, and/or distribute this software for any
@@ -54,6 +54,9 @@ function getPublicKeyFromAddress(address) {
54
54
  class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalletAdapter {
55
55
  constructor(config) {
56
56
  super();
57
+ this.supportedTransactionVersions = new Set(
58
+ // FIXME(#244): We can't actually know what versions are supported until we know which wallet we're talking to.
59
+ ['legacy', 0]);
57
60
  this.name = SolanaMobileWalletAdapterWalletName;
58
61
  this.url = 'https://solanamobile.com';
59
62
  this.icon = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI4IiB3aWR0aD0iMjgiIHZpZXdCb3g9Ii0zIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0RDQjhGRiI+PHBhdGggZD0iTTE3LjQgMTcuNEgxNXYyLjRoMi40di0yLjRabTEuMi05LjZoLTIuNHYyLjRoMi40VjcuOFoiLz48cGF0aCBkPSJNMjEuNiAzVjBoLTIuNHYzaC0zLjZWMGgtMi40djNoLTIuNHY2LjZINC41YTIuMSAyLjEgMCAxIDEgMC00LjJoMi43VjNINC41QTQuNSA0LjUgMCAwIDAgMCA3LjVWMjRoMjEuNnYtNi42aC0yLjR2NC4ySDIuNFYxMS41Yy41LjMgMS4yLjQgMS44LjVoNy41QTYuNiA2LjYgMCAwIDAgMjQgOVYzaC0yLjRabTAgNS43YTQuMiA0LjIgMCAxIDEtOC40IDBWNS40aDguNHYzLjNaIi8+PC9nPjwvc3ZnPg==';
@@ -232,49 +235,60 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
232
235
  const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
233
236
  try {
234
237
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
235
- var _a;
236
- let targetCommitment;
237
- switch (connection.commitment) {
238
- case 'confirmed':
239
- case 'finalized':
240
- case 'processed':
241
- targetCommitment = connection.commitment;
242
- break;
243
- default:
244
- targetCommitment = 'finalized';
245
- }
246
- let targetPreflightCommitment;
247
- switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
248
- case 'confirmed':
249
- case 'finalized':
250
- case 'processed':
251
- targetPreflightCommitment = options.preflightCommitment;
252
- break;
253
- case undefined:
254
- targetPreflightCommitment = targetCommitment;
255
- default:
256
- targetPreflightCommitment = 'finalized';
257
- }
258
238
  yield Promise.all([
259
239
  this.performReauthorization(wallet, authToken),
260
- (() => __awaiter(this, void 0, void 0, function* () {
261
- if (transaction.recentBlockhash == null) {
262
- const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
263
- ? 2
264
- : targetPreflightCommitment === 'confirmed'
265
- ? 1
266
- : 0;
267
- const targetCommitmentScore = targetCommitment === 'finalized' ? 2 : targetCommitment === 'confirmed' ? 1 : 0;
268
- const { blockhash } = yield connection.getLatestBlockhash({
269
- commitment: preflightCommitmentScore < targetCommitmentScore
270
- ? targetPreflightCommitment
271
- : targetCommitment,
272
- });
273
- transaction.recentBlockhash = blockhash;
274
- }
275
- }))(),
240
+ 'version' in transaction
241
+ ? null
242
+ : /**
243
+ * Unlike versioned transactions, legacy `Transaction` objects
244
+ * may not have an associated `feePayer` or `recentBlockhash`.
245
+ * This code exists to patch them up in case they are missing.
246
+ */
247
+ (() => __awaiter(this, void 0, void 0, function* () {
248
+ var _a;
249
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
250
+ if (transaction.recentBlockhash == null) {
251
+ let targetCommitment;
252
+ switch (connection.commitment) {
253
+ case 'confirmed':
254
+ case 'finalized':
255
+ case 'processed':
256
+ targetCommitment = connection.commitment;
257
+ break;
258
+ default:
259
+ targetCommitment = 'finalized';
260
+ }
261
+ let targetPreflightCommitment;
262
+ switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
263
+ case 'confirmed':
264
+ case 'finalized':
265
+ case 'processed':
266
+ targetPreflightCommitment = options.preflightCommitment;
267
+ break;
268
+ case undefined:
269
+ targetPreflightCommitment = targetCommitment;
270
+ default:
271
+ targetPreflightCommitment = 'finalized';
272
+ }
273
+ const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
274
+ ? 2
275
+ : targetPreflightCommitment === 'confirmed'
276
+ ? 1
277
+ : 0;
278
+ const targetCommitmentScore = targetCommitment === 'finalized'
279
+ ? 2
280
+ : targetCommitment === 'confirmed'
281
+ ? 1
282
+ : 0;
283
+ const { blockhash } = yield connection.getLatestBlockhash({
284
+ commitment: preflightCommitmentScore < targetCommitmentScore
285
+ ? targetPreflightCommitment
286
+ : targetCommitment,
287
+ });
288
+ transaction.recentBlockhash = blockhash;
289
+ }
290
+ }))(),
276
291
  ]);
277
- transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
278
292
  const signatures = yield wallet.signAndSendTransactions({
279
293
  minContextSlot,
280
294
  transactions: [transaction],
package/lib/cjs/index.js CHANGED
@@ -6,7 +6,7 @@ var mobileWalletAdapterProtocolWeb3js = require('@solana-mobile/mobile-wallet-ad
6
6
  var walletAdapterBase = require('@solana/wallet-adapter-base');
7
7
  var web3_js = require('@solana/web3.js');
8
8
 
9
- /******************************************************************************
9
+ /*! *****************************************************************************
10
10
  Copyright (c) Microsoft Corporation.
11
11
 
12
12
  Permission to use, copy, modify, and/or distribute this software for any
@@ -54,6 +54,9 @@ function getPublicKeyFromAddress(address) {
54
54
  class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalletAdapter {
55
55
  constructor(config) {
56
56
  super();
57
+ this.supportedTransactionVersions = new Set(
58
+ // FIXME(#244): We can't actually know what versions are supported until we know which wallet we're talking to.
59
+ ['legacy', 0]);
57
60
  this.name = SolanaMobileWalletAdapterWalletName;
58
61
  this.url = 'https://solanamobile.com';
59
62
  this.icon = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI4IiB3aWR0aD0iMjgiIHZpZXdCb3g9Ii0zIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0RDQjhGRiI+PHBhdGggZD0iTTE3LjQgMTcuNEgxNXYyLjRoMi40di0yLjRabTEuMi05LjZoLTIuNHYyLjRoMi40VjcuOFoiLz48cGF0aCBkPSJNMjEuNiAzVjBoLTIuNHYzaC0zLjZWMGgtMi40djNoLTIuNHY2LjZINC41YTIuMSAyLjEgMCAxIDEgMC00LjJoMi43VjNINC41QTQuNSA0LjUgMCAwIDAgMCA3LjVWMjRoMjEuNnYtNi42aC0yLjR2NC4ySDIuNFYxMS41Yy41LjMgMS4yLjQgMS44LjVoNy41QTYuNiA2LjYgMCAwIDAgMjQgOVYzaC0yLjRabTAgNS43YTQuMiA0LjIgMCAxIDEtOC40IDBWNS40aDguNHYzLjNaIi8+PC9nPjwvc3ZnPg==';
@@ -232,49 +235,60 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
232
235
  const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
233
236
  try {
234
237
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
235
- var _a;
236
- let targetCommitment;
237
- switch (connection.commitment) {
238
- case 'confirmed':
239
- case 'finalized':
240
- case 'processed':
241
- targetCommitment = connection.commitment;
242
- break;
243
- default:
244
- targetCommitment = 'finalized';
245
- }
246
- let targetPreflightCommitment;
247
- switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
248
- case 'confirmed':
249
- case 'finalized':
250
- case 'processed':
251
- targetPreflightCommitment = options.preflightCommitment;
252
- break;
253
- case undefined:
254
- targetPreflightCommitment = targetCommitment;
255
- default:
256
- targetPreflightCommitment = 'finalized';
257
- }
258
238
  yield Promise.all([
259
239
  this.performReauthorization(wallet, authToken),
260
- (() => __awaiter(this, void 0, void 0, function* () {
261
- if (transaction.recentBlockhash == null) {
262
- const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
263
- ? 2
264
- : targetPreflightCommitment === 'confirmed'
265
- ? 1
266
- : 0;
267
- const targetCommitmentScore = targetCommitment === 'finalized' ? 2 : targetCommitment === 'confirmed' ? 1 : 0;
268
- const { blockhash } = yield connection.getLatestBlockhash({
269
- commitment: preflightCommitmentScore < targetCommitmentScore
270
- ? targetPreflightCommitment
271
- : targetCommitment,
272
- });
273
- transaction.recentBlockhash = blockhash;
274
- }
275
- }))(),
240
+ 'version' in transaction
241
+ ? null
242
+ : /**
243
+ * Unlike versioned transactions, legacy `Transaction` objects
244
+ * may not have an associated `feePayer` or `recentBlockhash`.
245
+ * This code exists to patch them up in case they are missing.
246
+ */
247
+ (() => __awaiter(this, void 0, void 0, function* () {
248
+ var _a;
249
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
250
+ if (transaction.recentBlockhash == null) {
251
+ let targetCommitment;
252
+ switch (connection.commitment) {
253
+ case 'confirmed':
254
+ case 'finalized':
255
+ case 'processed':
256
+ targetCommitment = connection.commitment;
257
+ break;
258
+ default:
259
+ targetCommitment = 'finalized';
260
+ }
261
+ let targetPreflightCommitment;
262
+ switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
263
+ case 'confirmed':
264
+ case 'finalized':
265
+ case 'processed':
266
+ targetPreflightCommitment = options.preflightCommitment;
267
+ break;
268
+ case undefined:
269
+ targetPreflightCommitment = targetCommitment;
270
+ default:
271
+ targetPreflightCommitment = 'finalized';
272
+ }
273
+ const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
274
+ ? 2
275
+ : targetPreflightCommitment === 'confirmed'
276
+ ? 1
277
+ : 0;
278
+ const targetCommitmentScore = targetCommitment === 'finalized'
279
+ ? 2
280
+ : targetCommitment === 'confirmed'
281
+ ? 1
282
+ : 0;
283
+ const { blockhash } = yield connection.getLatestBlockhash({
284
+ commitment: preflightCommitmentScore < targetCommitmentScore
285
+ ? targetPreflightCommitment
286
+ : targetCommitment,
287
+ });
288
+ transaction.recentBlockhash = blockhash;
289
+ }
290
+ }))(),
276
291
  ]);
277
- transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
278
292
  const signatures = yield wallet.signAndSendTransactions({
279
293
  minContextSlot,
280
294
  transactions: [transaction],
@@ -13,7 +13,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
13
13
 
14
14
  var AsyncStorage__default = /*#__PURE__*/_interopDefaultLegacy(AsyncStorage);
15
15
 
16
- /******************************************************************************
16
+ /*! *****************************************************************************
17
17
  Copyright (c) Microsoft Corporation.
18
18
 
19
19
  Permission to use, copy, modify, and/or distribute this software for any
@@ -51,6 +51,9 @@ function getPublicKeyFromAddress(address) {
51
51
  class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalletAdapter {
52
52
  constructor(config) {
53
53
  super();
54
+ this.supportedTransactionVersions = new Set(
55
+ // FIXME(#244): We can't actually know what versions are supported until we know which wallet we're talking to.
56
+ ['legacy', 0]);
54
57
  this.name = SolanaMobileWalletAdapterWalletName;
55
58
  this.url = 'https://solanamobile.com';
56
59
  this.icon = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI4IiB3aWR0aD0iMjgiIHZpZXdCb3g9Ii0zIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0RDQjhGRiI+PHBhdGggZD0iTTE3LjQgMTcuNEgxNXYyLjRoMi40di0yLjRabTEuMi05LjZoLTIuNHYyLjRoMi40VjcuOFoiLz48cGF0aCBkPSJNMjEuNiAzVjBoLTIuNHYzaC0zLjZWMGgtMi40djNoLTIuNHY2LjZINC41YTIuMSAyLjEgMCAxIDEgMC00LjJoMi43VjNINC41QTQuNSA0LjUgMCAwIDAgMCA3LjVWMjRoMjEuNnYtNi42aC0yLjR2NC4ySDIuNFYxMS41Yy41LjMgMS4yLjQgMS44LjVoNy41QTYuNiA2LjYgMCAwIDAgMjQgOVYzaC0yLjRabTAgNS43YTQuMiA0LjIgMCAxIDEtOC40IDBWNS40aDguNHYzLjNaIi8+PC9nPjwvc3ZnPg==';
@@ -229,49 +232,60 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
229
232
  const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
230
233
  try {
231
234
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
232
- var _a;
233
- let targetCommitment;
234
- switch (connection.commitment) {
235
- case 'confirmed':
236
- case 'finalized':
237
- case 'processed':
238
- targetCommitment = connection.commitment;
239
- break;
240
- default:
241
- targetCommitment = 'finalized';
242
- }
243
- let targetPreflightCommitment;
244
- switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
245
- case 'confirmed':
246
- case 'finalized':
247
- case 'processed':
248
- targetPreflightCommitment = options.preflightCommitment;
249
- break;
250
- case undefined:
251
- targetPreflightCommitment = targetCommitment;
252
- default:
253
- targetPreflightCommitment = 'finalized';
254
- }
255
235
  yield Promise.all([
256
236
  this.performReauthorization(wallet, authToken),
257
- (() => __awaiter(this, void 0, void 0, function* () {
258
- if (transaction.recentBlockhash == null) {
259
- const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
260
- ? 2
261
- : targetPreflightCommitment === 'confirmed'
262
- ? 1
263
- : 0;
264
- const targetCommitmentScore = targetCommitment === 'finalized' ? 2 : targetCommitment === 'confirmed' ? 1 : 0;
265
- const { blockhash } = yield connection.getLatestBlockhash({
266
- commitment: preflightCommitmentScore < targetCommitmentScore
267
- ? targetPreflightCommitment
268
- : targetCommitment,
269
- });
270
- transaction.recentBlockhash = blockhash;
271
- }
272
- }))(),
237
+ 'version' in transaction
238
+ ? null
239
+ : /**
240
+ * Unlike versioned transactions, legacy `Transaction` objects
241
+ * may not have an associated `feePayer` or `recentBlockhash`.
242
+ * This code exists to patch them up in case they are missing.
243
+ */
244
+ (() => __awaiter(this, void 0, void 0, function* () {
245
+ var _a;
246
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
247
+ if (transaction.recentBlockhash == null) {
248
+ let targetCommitment;
249
+ switch (connection.commitment) {
250
+ case 'confirmed':
251
+ case 'finalized':
252
+ case 'processed':
253
+ targetCommitment = connection.commitment;
254
+ break;
255
+ default:
256
+ targetCommitment = 'finalized';
257
+ }
258
+ let targetPreflightCommitment;
259
+ switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
260
+ case 'confirmed':
261
+ case 'finalized':
262
+ case 'processed':
263
+ targetPreflightCommitment = options.preflightCommitment;
264
+ break;
265
+ case undefined:
266
+ targetPreflightCommitment = targetCommitment;
267
+ default:
268
+ targetPreflightCommitment = 'finalized';
269
+ }
270
+ const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
271
+ ? 2
272
+ : targetPreflightCommitment === 'confirmed'
273
+ ? 1
274
+ : 0;
275
+ const targetCommitmentScore = targetCommitment === 'finalized'
276
+ ? 2
277
+ : targetCommitment === 'confirmed'
278
+ ? 1
279
+ : 0;
280
+ const { blockhash } = yield connection.getLatestBlockhash({
281
+ commitment: preflightCommitmentScore < targetCommitmentScore
282
+ ? targetPreflightCommitment
283
+ : targetCommitment,
284
+ });
285
+ transaction.recentBlockhash = blockhash;
286
+ }
287
+ }))(),
273
288
  ]);
274
- transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
275
289
  const signatures = yield wallet.signAndSendTransactions({
276
290
  minContextSlot,
277
291
  transactions: [transaction],
@@ -2,7 +2,7 @@ import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
2
2
  import { BaseMessageSignerWalletAdapter, WalletReadyState, WalletPublicKeyError, WalletNotReadyError, WalletConnectionError, WalletDisconnectedError, WalletNotConnectedError, WalletSignTransactionError, WalletSendTransactionError, WalletSignMessageError } from '@solana/wallet-adapter-base';
3
3
  import { PublicKey } from '@solana/web3.js';
4
4
 
5
- /******************************************************************************
5
+ /*! *****************************************************************************
6
6
  Copyright (c) Microsoft Corporation.
7
7
 
8
8
  Permission to use, copy, modify, and/or distribute this software for any
@@ -50,6 +50,9 @@ function getPublicKeyFromAddress(address) {
50
50
  class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
51
51
  constructor(config) {
52
52
  super();
53
+ this.supportedTransactionVersions = new Set(
54
+ // FIXME(#244): We can't actually know what versions are supported until we know which wallet we're talking to.
55
+ ['legacy', 0]);
53
56
  this.name = SolanaMobileWalletAdapterWalletName;
54
57
  this.url = 'https://solanamobile.com';
55
58
  this.icon = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI4IiB3aWR0aD0iMjgiIHZpZXdCb3g9Ii0zIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0RDQjhGRiI+PHBhdGggZD0iTTE3LjQgMTcuNEgxNXYyLjRoMi40di0yLjRabTEuMi05LjZoLTIuNHYyLjRoMi40VjcuOFoiLz48cGF0aCBkPSJNMjEuNiAzVjBoLTIuNHYzaC0zLjZWMGgtMi40djNoLTIuNHY2LjZINC41YTIuMSAyLjEgMCAxIDEgMC00LjJoMi43VjNINC41QTQuNSA0LjUgMCAwIDAgMCA3LjVWMjRoMjEuNnYtNi42aC0yLjR2NC4ySDIuNFYxMS41Yy41LjMgMS4yLjQgMS44LjVoNy41QTYuNiA2LjYgMCAwIDAgMjQgOVYzaC0yLjRabTAgNS43YTQuMiA0LjIgMCAxIDEtOC40IDBWNS40aDguNHYzLjNaIi8+PC9nPjwvc3ZnPg==';
@@ -228,49 +231,60 @@ class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
228
231
  const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
229
232
  try {
230
233
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
231
- var _a;
232
- let targetCommitment;
233
- switch (connection.commitment) {
234
- case 'confirmed':
235
- case 'finalized':
236
- case 'processed':
237
- targetCommitment = connection.commitment;
238
- break;
239
- default:
240
- targetCommitment = 'finalized';
241
- }
242
- let targetPreflightCommitment;
243
- switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
244
- case 'confirmed':
245
- case 'finalized':
246
- case 'processed':
247
- targetPreflightCommitment = options.preflightCommitment;
248
- break;
249
- case undefined:
250
- targetPreflightCommitment = targetCommitment;
251
- default:
252
- targetPreflightCommitment = 'finalized';
253
- }
254
234
  yield Promise.all([
255
235
  this.performReauthorization(wallet, authToken),
256
- (() => __awaiter(this, void 0, void 0, function* () {
257
- if (transaction.recentBlockhash == null) {
258
- const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
259
- ? 2
260
- : targetPreflightCommitment === 'confirmed'
261
- ? 1
262
- : 0;
263
- const targetCommitmentScore = targetCommitment === 'finalized' ? 2 : targetCommitment === 'confirmed' ? 1 : 0;
264
- const { blockhash } = yield connection.getLatestBlockhash({
265
- commitment: preflightCommitmentScore < targetCommitmentScore
266
- ? targetPreflightCommitment
267
- : targetCommitment,
268
- });
269
- transaction.recentBlockhash = blockhash;
270
- }
271
- }))(),
236
+ 'version' in transaction
237
+ ? null
238
+ : /**
239
+ * Unlike versioned transactions, legacy `Transaction` objects
240
+ * may not have an associated `feePayer` or `recentBlockhash`.
241
+ * This code exists to patch them up in case they are missing.
242
+ */
243
+ (() => __awaiter(this, void 0, void 0, function* () {
244
+ var _a;
245
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
246
+ if (transaction.recentBlockhash == null) {
247
+ let targetCommitment;
248
+ switch (connection.commitment) {
249
+ case 'confirmed':
250
+ case 'finalized':
251
+ case 'processed':
252
+ targetCommitment = connection.commitment;
253
+ break;
254
+ default:
255
+ targetCommitment = 'finalized';
256
+ }
257
+ let targetPreflightCommitment;
258
+ switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
259
+ case 'confirmed':
260
+ case 'finalized':
261
+ case 'processed':
262
+ targetPreflightCommitment = options.preflightCommitment;
263
+ break;
264
+ case undefined:
265
+ targetPreflightCommitment = targetCommitment;
266
+ default:
267
+ targetPreflightCommitment = 'finalized';
268
+ }
269
+ const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
270
+ ? 2
271
+ : targetPreflightCommitment === 'confirmed'
272
+ ? 1
273
+ : 0;
274
+ const targetCommitmentScore = targetCommitment === 'finalized'
275
+ ? 2
276
+ : targetCommitment === 'confirmed'
277
+ ? 1
278
+ : 0;
279
+ const { blockhash } = yield connection.getLatestBlockhash({
280
+ commitment: preflightCommitmentScore < targetCommitmentScore
281
+ ? targetPreflightCommitment
282
+ : targetCommitment,
283
+ });
284
+ transaction.recentBlockhash = blockhash;
285
+ }
286
+ }))(),
272
287
  ]);
273
- transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
274
288
  const signatures = yield wallet.signAndSendTransactions({
275
289
  minContextSlot,
276
290
  transactions: [transaction],
package/lib/esm/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
2
2
  import { BaseMessageSignerWalletAdapter, WalletReadyState, WalletPublicKeyError, WalletNotReadyError, WalletConnectionError, WalletDisconnectedError, WalletNotConnectedError, WalletSignTransactionError, WalletSendTransactionError, WalletSignMessageError } from '@solana/wallet-adapter-base';
3
3
  import { PublicKey } from '@solana/web3.js';
4
4
 
5
- /******************************************************************************
5
+ /*! *****************************************************************************
6
6
  Copyright (c) Microsoft Corporation.
7
7
 
8
8
  Permission to use, copy, modify, and/or distribute this software for any
@@ -50,6 +50,9 @@ function getPublicKeyFromAddress(address) {
50
50
  class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
51
51
  constructor(config) {
52
52
  super();
53
+ this.supportedTransactionVersions = new Set(
54
+ // FIXME(#244): We can't actually know what versions are supported until we know which wallet we're talking to.
55
+ ['legacy', 0]);
53
56
  this.name = SolanaMobileWalletAdapterWalletName;
54
57
  this.url = 'https://solanamobile.com';
55
58
  this.icon = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI4IiB3aWR0aD0iMjgiIHZpZXdCb3g9Ii0zIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0RDQjhGRiI+PHBhdGggZD0iTTE3LjQgMTcuNEgxNXYyLjRoMi40di0yLjRabTEuMi05LjZoLTIuNHYyLjRoMi40VjcuOFoiLz48cGF0aCBkPSJNMjEuNiAzVjBoLTIuNHYzaC0zLjZWMGgtMi40djNoLTIuNHY2LjZINC41YTIuMSAyLjEgMCAxIDEgMC00LjJoMi43VjNINC41QTQuNSA0LjUgMCAwIDAgMCA3LjVWMjRoMjEuNnYtNi42aC0yLjR2NC4ySDIuNFYxMS41Yy41LjMgMS4yLjQgMS44LjVoNy41QTYuNiA2LjYgMCAwIDAgMjQgOVYzaC0yLjRabTAgNS43YTQuMiA0LjIgMCAxIDEtOC40IDBWNS40aDguNHYzLjNaIi8+PC9nPjwvc3ZnPg==';
@@ -228,49 +231,60 @@ class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
228
231
  const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
229
232
  try {
230
233
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
231
- var _a;
232
- let targetCommitment;
233
- switch (connection.commitment) {
234
- case 'confirmed':
235
- case 'finalized':
236
- case 'processed':
237
- targetCommitment = connection.commitment;
238
- break;
239
- default:
240
- targetCommitment = 'finalized';
241
- }
242
- let targetPreflightCommitment;
243
- switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
244
- case 'confirmed':
245
- case 'finalized':
246
- case 'processed':
247
- targetPreflightCommitment = options.preflightCommitment;
248
- break;
249
- case undefined:
250
- targetPreflightCommitment = targetCommitment;
251
- default:
252
- targetPreflightCommitment = 'finalized';
253
- }
254
234
  yield Promise.all([
255
235
  this.performReauthorization(wallet, authToken),
256
- (() => __awaiter(this, void 0, void 0, function* () {
257
- if (transaction.recentBlockhash == null) {
258
- const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
259
- ? 2
260
- : targetPreflightCommitment === 'confirmed'
261
- ? 1
262
- : 0;
263
- const targetCommitmentScore = targetCommitment === 'finalized' ? 2 : targetCommitment === 'confirmed' ? 1 : 0;
264
- const { blockhash } = yield connection.getLatestBlockhash({
265
- commitment: preflightCommitmentScore < targetCommitmentScore
266
- ? targetPreflightCommitment
267
- : targetCommitment,
268
- });
269
- transaction.recentBlockhash = blockhash;
270
- }
271
- }))(),
236
+ 'version' in transaction
237
+ ? null
238
+ : /**
239
+ * Unlike versioned transactions, legacy `Transaction` objects
240
+ * may not have an associated `feePayer` or `recentBlockhash`.
241
+ * This code exists to patch them up in case they are missing.
242
+ */
243
+ (() => __awaiter(this, void 0, void 0, function* () {
244
+ var _a;
245
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
246
+ if (transaction.recentBlockhash == null) {
247
+ let targetCommitment;
248
+ switch (connection.commitment) {
249
+ case 'confirmed':
250
+ case 'finalized':
251
+ case 'processed':
252
+ targetCommitment = connection.commitment;
253
+ break;
254
+ default:
255
+ targetCommitment = 'finalized';
256
+ }
257
+ let targetPreflightCommitment;
258
+ switch (options === null || options === void 0 ? void 0 : options.preflightCommitment) {
259
+ case 'confirmed':
260
+ case 'finalized':
261
+ case 'processed':
262
+ targetPreflightCommitment = options.preflightCommitment;
263
+ break;
264
+ case undefined:
265
+ targetPreflightCommitment = targetCommitment;
266
+ default:
267
+ targetPreflightCommitment = 'finalized';
268
+ }
269
+ const preflightCommitmentScore = targetPreflightCommitment === 'finalized'
270
+ ? 2
271
+ : targetPreflightCommitment === 'confirmed'
272
+ ? 1
273
+ : 0;
274
+ const targetCommitmentScore = targetCommitment === 'finalized'
275
+ ? 2
276
+ : targetCommitment === 'confirmed'
277
+ ? 1
278
+ : 0;
279
+ const { blockhash } = yield connection.getLatestBlockhash({
280
+ commitment: preflightCommitmentScore < targetCommitmentScore
281
+ ? targetPreflightCommitment
282
+ : targetCommitment,
283
+ });
284
+ transaction.recentBlockhash = blockhash;
285
+ }
286
+ }))(),
272
287
  ]);
273
- transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
274
288
  const signatures = yield wallet.signAndSendTransactions({
275
289
  minContextSlot,
276
290
  transactions: [transaction],
@@ -1,6 +1,7 @@
1
1
  import { AppIdentity, AuthorizationResult, Base64EncodedAddress, Cluster } from "@solana-mobile/mobile-wallet-adapter-protocol";
2
2
  import { BaseMessageSignerWalletAdapter, WalletName, WalletReadyState } from "@solana/wallet-adapter-base";
3
- import { Connection, PublicKey, SendOptions, Transaction, TransactionSignature } from "@solana/web3.js";
3
+ import { Connection, PublicKey, SendOptions, TransactionSignature, TransactionVersion, VersionedTransaction } from "@solana/web3.js";
4
+ import { Transaction as LegacyTransaction } from "@solana/web3.js";
4
5
  interface AuthorizationResultCache {
5
6
  clear(): Promise<void>;
6
7
  get(): Promise<AuthorizationResult | undefined>;
@@ -11,6 +12,7 @@ interface AddressSelector {
11
12
  }
12
13
  declare const SolanaMobileWalletAdapterWalletName: WalletName<string>;
13
14
  declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
15
+ readonly supportedTransactionVersions: Set<TransactionVersion>;
14
16
  name: WalletName<string>;
15
17
  url: string;
16
18
  icon: string;
@@ -41,9 +43,9 @@ declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
41
43
  private transact;
42
44
  private assertIsAuthorized;
43
45
  private performSignTransactions;
44
- sendTransaction(transaction: Transaction, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
45
- signTransaction(transaction: Transaction): Promise<Transaction>;
46
- signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
46
+ sendTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
47
+ signTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T): Promise<T>;
48
+ signAllTransactions<T extends LegacyTransaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
47
49
  signMessage(message: Uint8Array): Promise<Uint8Array>;
48
50
  }
49
51
  declare function createDefaultAddressSelector(): AddressSelector;
@@ -1,6 +1,7 @@
1
1
  import { AppIdentity, AuthorizationResult, Base64EncodedAddress, Cluster } from "@solana-mobile/mobile-wallet-adapter-protocol";
2
2
  import { BaseMessageSignerWalletAdapter, WalletName, WalletReadyState } from "@solana/wallet-adapter-base";
3
- import { Connection, PublicKey, SendOptions, Transaction, TransactionSignature } from "@solana/web3.js";
3
+ import { Connection, PublicKey, SendOptions, TransactionSignature, TransactionVersion, VersionedTransaction } from "@solana/web3.js";
4
+ import { Transaction as LegacyTransaction } from "@solana/web3.js";
4
5
  interface AuthorizationResultCache {
5
6
  clear(): Promise<void>;
6
7
  get(): Promise<AuthorizationResult | undefined>;
@@ -11,6 +12,7 @@ interface AddressSelector {
11
12
  }
12
13
  declare const SolanaMobileWalletAdapterWalletName: WalletName<string>;
13
14
  declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
15
+ readonly supportedTransactionVersions: Set<TransactionVersion>;
14
16
  name: WalletName<string>;
15
17
  url: string;
16
18
  icon: string;
@@ -41,9 +43,9 @@ declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
41
43
  private transact;
42
44
  private assertIsAuthorized;
43
45
  private performSignTransactions;
44
- sendTransaction(transaction: Transaction, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
45
- signTransaction(transaction: Transaction): Promise<Transaction>;
46
- signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
46
+ sendTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
47
+ signTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T): Promise<T>;
48
+ signAllTransactions<T extends LegacyTransaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
47
49
  signMessage(message: Uint8Array): Promise<Uint8Array>;
48
50
  }
49
51
  declare function createDefaultAddressSelector(): AddressSelector;
@@ -1,6 +1,7 @@
1
1
  import { AppIdentity, AuthorizationResult, Base64EncodedAddress, Cluster } from "@solana-mobile/mobile-wallet-adapter-protocol";
2
2
  import { BaseMessageSignerWalletAdapter, WalletName, WalletReadyState } from "@solana/wallet-adapter-base";
3
- import { Connection, PublicKey, SendOptions, Transaction, TransactionSignature } from "@solana/web3.js";
3
+ import { Connection, PublicKey, SendOptions, TransactionSignature, TransactionVersion, VersionedTransaction } from "@solana/web3.js";
4
+ import { Transaction as LegacyTransaction } from "@solana/web3.js";
4
5
  interface AuthorizationResultCache {
5
6
  clear(): Promise<void>;
6
7
  get(): Promise<AuthorizationResult | undefined>;
@@ -11,6 +12,7 @@ interface AddressSelector {
11
12
  }
12
13
  declare const SolanaMobileWalletAdapterWalletName: WalletName<string>;
13
14
  declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
15
+ readonly supportedTransactionVersions: Set<TransactionVersion>;
14
16
  name: WalletName<string>;
15
17
  url: string;
16
18
  icon: string;
@@ -41,9 +43,9 @@ declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
41
43
  private transact;
42
44
  private assertIsAuthorized;
43
45
  private performSignTransactions;
44
- sendTransaction(transaction: Transaction, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
45
- signTransaction(transaction: Transaction): Promise<Transaction>;
46
- signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
46
+ sendTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
47
+ signTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T): Promise<T>;
48
+ signAllTransactions<T extends LegacyTransaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
47
49
  signMessage(message: Uint8Array): Promise<Uint8Array>;
48
50
  }
49
51
  declare function createDefaultAddressSelector(): AddressSelector;
@@ -1,6 +1,7 @@
1
1
  import { AppIdentity, AuthorizationResult, Base64EncodedAddress, Cluster } from "@solana-mobile/mobile-wallet-adapter-protocol";
2
2
  import { BaseMessageSignerWalletAdapter, WalletName, WalletReadyState } from "@solana/wallet-adapter-base";
3
- import { Connection, PublicKey, SendOptions, Transaction, TransactionSignature } from "@solana/web3.js";
3
+ import { Connection, PublicKey, SendOptions, TransactionSignature, TransactionVersion, VersionedTransaction } from "@solana/web3.js";
4
+ import { Transaction as LegacyTransaction } from "@solana/web3.js";
4
5
  interface AuthorizationResultCache {
5
6
  clear(): Promise<void>;
6
7
  get(): Promise<AuthorizationResult | undefined>;
@@ -11,6 +12,7 @@ interface AddressSelector {
11
12
  }
12
13
  declare const SolanaMobileWalletAdapterWalletName: WalletName<string>;
13
14
  declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
15
+ readonly supportedTransactionVersions: Set<TransactionVersion>;
14
16
  name: WalletName<string>;
15
17
  url: string;
16
18
  icon: string;
@@ -41,9 +43,9 @@ declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
41
43
  private transact;
42
44
  private assertIsAuthorized;
43
45
  private performSignTransactions;
44
- sendTransaction(transaction: Transaction, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
45
- signTransaction(transaction: Transaction): Promise<Transaction>;
46
- signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
46
+ sendTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
47
+ signTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T): Promise<T>;
48
+ signAllTransactions<T extends LegacyTransaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
47
49
  signMessage(message: Uint8Array): Promise<Uint8Array>;
48
50
  }
49
51
  declare function createDefaultAddressSelector(): AddressSelector;
@@ -1,6 +1,7 @@
1
1
  import { AppIdentity, AuthorizationResult, Base64EncodedAddress, Cluster } from "@solana-mobile/mobile-wallet-adapter-protocol";
2
2
  import { BaseMessageSignerWalletAdapter, WalletName, WalletReadyState } from "@solana/wallet-adapter-base";
3
- import { Connection, PublicKey, SendOptions, Transaction, TransactionSignature } from "@solana/web3.js";
3
+ import { Connection, PublicKey, SendOptions, TransactionSignature, TransactionVersion, VersionedTransaction } from "@solana/web3.js";
4
+ import { Transaction as LegacyTransaction } from "@solana/web3.js";
4
5
  interface AuthorizationResultCache {
5
6
  clear(): Promise<void>;
6
7
  get(): Promise<AuthorizationResult | undefined>;
@@ -11,6 +12,7 @@ interface AddressSelector {
11
12
  }
12
13
  declare const SolanaMobileWalletAdapterWalletName: WalletName<string>;
13
14
  declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
15
+ readonly supportedTransactionVersions: Set<TransactionVersion>;
14
16
  name: WalletName<string>;
15
17
  url: string;
16
18
  icon: string;
@@ -41,9 +43,9 @@ declare class SolanaMobileWalletAdapter extends BaseMessageSignerWalletAdapter {
41
43
  private transact;
42
44
  private assertIsAuthorized;
43
45
  private performSignTransactions;
44
- sendTransaction(transaction: Transaction, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
45
- signTransaction(transaction: Transaction): Promise<Transaction>;
46
- signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;
46
+ sendTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendOptions): Promise<TransactionSignature>;
47
+ signTransaction<T extends LegacyTransaction | VersionedTransaction>(transaction: T): Promise<T>;
48
+ signAllTransactions<T extends LegacyTransaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
47
49
  signMessage(message: Uint8Array): Promise<Uint8Array>;
48
50
  }
49
51
  declare function createDefaultAddressSelector(): AddressSelector;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solana-mobile/wallet-adapter-mobile",
3
3
  "description": "An adapter for mobile wallet apps that conform to the Solana Mobile Wallet Adapter protocol",
4
- "version": "0.9.0",
4
+ "version": "0.9.2",
5
5
  "author": "Steven Luscher <steven.luscher@solanamobile.com>",
6
6
  "repository": "https://github.com/solana-mobile/mobile-wallet-adapter",
7
7
  "license": "Apache-2.0",
@@ -37,19 +37,19 @@
37
37
  "prepublishOnly": "agadoo"
38
38
  },
39
39
  "peerDependencies": {
40
- "@solana/web3.js": "^1.36.0"
40
+ "@solana/web3.js": "^1.58.0"
41
41
  },
42
42
  "dependencies": {
43
43
  "@react-native-async-storage/async-storage": "^1.17.7",
44
- "@solana-mobile/mobile-wallet-adapter-protocol-web3js": "^0.9.0",
45
- "@solana/wallet-adapter-base": "^0.9.8",
46
- "@solana/web3.js": "^1.20.0",
44
+ "@solana-mobile/mobile-wallet-adapter-protocol-web3js": "^0.9.2",
45
+ "@solana/wallet-adapter-base": "^0.9.17",
47
46
  "js-base64": "^3.7.2"
48
47
  },
49
48
  "devDependencies": {
49
+ "@solana/web3.js": "^1.58.0",
50
50
  "agadoo": "^2.0.0",
51
51
  "cross-env": "^7.0.3",
52
52
  "shx": "^0.3.4"
53
53
  },
54
- "gitHead": "e8d08469864173ec8480e4cf069849d663500883"
54
+ "gitHead": "2d6baf8692d29f164cec7f772f7a9779fe5f0220"
55
55
  }