@solana-mobile/wallet-adapter-mobile 0.0.1-alpha.8 → 0.9.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.
package/README.md CHANGED
@@ -10,6 +10,7 @@ Create an instance of the mobile wallet adapter like this.
10
10
 
11
11
  ```typescript
12
12
  new SolanaMobileWalletAdapter({
13
+ addressSelector: createDefaultAddressSelector(),
13
14
  appIdentity: {
14
15
  name: 'My app',
15
16
  uri: 'https://myapp.io',
@@ -24,6 +25,7 @@ Use that adapter instance alongside the other adapters used by your app.
24
25
  ```typescript
25
26
  const wallets = useMemo(() => [
26
27
  new SolanaMobileWalletAdapter({
28
+ addressSelector: createDefaultAddressSelector(),
27
29
  appIdentity: {
28
30
  name: 'My app',
29
31
  uri: 'https://myapp.io',
@@ -60,6 +60,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
60
60
  this._connecting = false;
61
61
  this._readyState = getIsSupported() ? walletAdapterBase.WalletReadyState.Loadable : walletAdapterBase.WalletReadyState.Unsupported;
62
62
  this._authorizationResultCache = config.authorizationResultCache;
63
+ this._addressSelector = config.addressSelector;
63
64
  this._appIdentity = config.appIdentity;
64
65
  this._cluster = config.cluster;
65
66
  if (this._readyState !== walletAdapterBase.WalletReadyState.Unsupported) {
@@ -74,11 +75,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
74
75
  }
75
76
  }
76
77
  get publicKey() {
77
- if (this._publicKey == null && this._authorizationResult != null) {
78
+ if (this._publicKey == null && this._selectedAddress != null) {
78
79
  try {
79
- this._publicKey = getPublicKeyFromAddress(
80
- // TODO(#44): support multiple addresses
81
- this._authorizationResult.addresses[0]);
80
+ this._publicKey = getPublicKeyFromAddress(this._selectedAddress);
82
81
  }
83
82
  catch (e) {
84
83
  throw new walletAdapterBase.WalletPublicKeyError((e instanceof Error && (e === null || e === void 0 ? void 0 : e.message)) || 'Unknown error', e);
@@ -120,8 +119,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
120
119
  if (this._readyState !== walletAdapterBase.WalletReadyState.Installed) {
121
120
  this.emit('readyStateChange', (this._readyState = walletAdapterBase.WalletReadyState.Installed));
122
121
  }
122
+ this._selectedAddress = yield this._addressSelector.select(cachedAuthorizationResult.accounts.map(({ address }) => address));
123
123
  this.emit('connect',
124
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
124
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
125
125
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
126
  this.publicKey);
127
127
  return;
@@ -147,23 +147,33 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
147
147
  handleAuthorizationResult(authorizationResult) {
148
148
  var _a;
149
149
  return __awaiter(this, void 0, void 0, function* () {
150
- const didPublicKeyChange = ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.addresses[0]) !== authorizationResult.addresses[0]; // TODO(#44): support multiple addresses
150
+ const didPublicKeysChange =
151
+ // Case 1: We started from having no authorization.
152
+ this._authorizationResult == null ||
153
+ // Case 2: The number of authorized accounts changed.
154
+ ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.accounts.length) !== authorizationResult.accounts.length ||
155
+ // Case 3: The new list of addresses isn't exactly the same as the old list, in the same order.
156
+ this._authorizationResult.accounts.some((account, ii) => account.address !== authorizationResult.accounts[ii].address);
151
157
  this._authorizationResult = authorizationResult;
152
- if (didPublicKeyChange) {
153
- delete this._publicKey;
154
- this.emit('connect',
155
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
156
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
157
- this.publicKey);
158
+ if (didPublicKeysChange) {
159
+ const nextSelectedAddress = yield this._addressSelector.select(authorizationResult.accounts.map(({ address }) => address));
160
+ if (nextSelectedAddress !== this._selectedAddress) {
161
+ this._selectedAddress = nextSelectedAddress;
162
+ delete this._publicKey;
163
+ this.emit('connect',
164
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
165
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
166
+ this.publicKey);
167
+ }
158
168
  }
159
169
  yield this._authorizationResultCache.set(authorizationResult);
160
170
  });
161
171
  }
162
- performReauthorization(wallet, currentAuthorizationResult) {
172
+ performReauthorization(wallet, authToken) {
163
173
  return __awaiter(this, void 0, void 0, function* () {
164
174
  try {
165
175
  const authorizationResult = yield wallet.reauthorize({
166
- auth_token: currentAuthorizationResult.auth_token,
176
+ auth_token: authToken,
167
177
  });
168
178
  this.handleAuthorizationResult(authorizationResult); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
169
179
  }
@@ -178,6 +188,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
178
188
  this._authorizationResultCache.clear(); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
179
189
  delete this._authorizationResult;
180
190
  delete this._publicKey;
191
+ delete this._selectedAddress;
181
192
  this.emit('disconnect');
182
193
  });
183
194
  }
@@ -190,17 +201,19 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
190
201
  });
191
202
  }
192
203
  assertIsAuthorized() {
193
- const authorizationResult = this._authorizationResult;
194
- if (!authorizationResult)
204
+ if (!this._authorizationResult || !this._selectedAddress)
195
205
  throw new walletAdapterBase.WalletNotConnectedError();
196
- return authorizationResult;
206
+ return {
207
+ authToken: this._authorizationResult.auth_token,
208
+ selectedAddress: this._selectedAddress,
209
+ };
197
210
  }
198
211
  performSignTransactions(transactions) {
199
212
  return __awaiter(this, void 0, void 0, function* () {
200
- const authorizationResult = this.assertIsAuthorized();
213
+ const { authToken } = this.assertIsAuthorized();
201
214
  try {
202
215
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
203
- yield this.performReauthorization(wallet, authorizationResult);
216
+ yield this.performReauthorization(wallet, authToken);
204
217
  const signedTransactions = yield wallet.signTransactions({
205
218
  transactions,
206
219
  });
@@ -212,16 +225,58 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
212
225
  }
213
226
  });
214
227
  }
215
- sendTransaction(transaction, connection, _options) {
228
+ sendTransaction(transaction, connection, options) {
216
229
  return __awaiter(this, void 0, void 0, function* () {
217
230
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
218
- const authorizationResult = this.assertIsAuthorized();
231
+ const { authToken } = this.assertIsAuthorized();
232
+ const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
219
233
  try {
220
234
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
221
- yield this.performReauthorization(wallet, authorizationResult);
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
+ yield Promise.all([
259
+ 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
+ }))(),
276
+ ]);
277
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
222
278
  const signatures = yield wallet.signAndSendTransactions({
223
- connection,
224
- fee_payer: transaction.feePayer,
279
+ minContextSlot,
225
280
  transactions: [transaction],
226
281
  });
227
282
  return signatures[0];
@@ -252,11 +307,12 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
252
307
  signMessage(message) {
253
308
  return __awaiter(this, void 0, void 0, function* () {
254
309
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
255
- const authorizationResult = this.assertIsAuthorized();
310
+ const { authToken, selectedAddress } = this.assertIsAuthorized();
256
311
  try {
257
312
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
258
- yield this.performReauthorization(wallet, authorizationResult);
313
+ yield this.performReauthorization(wallet, authToken);
259
314
  const [signedMessage] = yield wallet.signMessages({
315
+ addresses: [selectedAddress],
260
316
  payloads: [message],
261
317
  });
262
318
  const signature = signedMessage.slice(-SIGNATURE_LENGTH_IN_BYTES);
@@ -271,6 +327,16 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
271
327
  }
272
328
  }
273
329
 
330
+ function createDefaultAddressSelector() {
331
+ return {
332
+ select(addresses) {
333
+ return __awaiter(this, void 0, void 0, function* () {
334
+ return addresses[0];
335
+ });
336
+ },
337
+ };
338
+ }
339
+
274
340
  const CACHE_KEY = 'SolanaMobileWalletAdapterDefaultAuthorizationCache';
275
341
  function createDefaultAuthorizationResultCache() {
276
342
  let storage;
@@ -321,4 +387,5 @@ function createDefaultAuthorizationResultCache() {
321
387
 
322
388
  exports.SolanaMobileWalletAdapter = SolanaMobileWalletAdapter;
323
389
  exports.SolanaMobileWalletAdapterWalletName = SolanaMobileWalletAdapterWalletName;
390
+ exports.createDefaultAddressSelector = createDefaultAddressSelector;
324
391
  exports.createDefaultAuthorizationResultCache = createDefaultAuthorizationResultCache;
package/lib/cjs/index.js CHANGED
@@ -60,6 +60,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
60
60
  this._connecting = false;
61
61
  this._readyState = getIsSupported() ? walletAdapterBase.WalletReadyState.Loadable : walletAdapterBase.WalletReadyState.Unsupported;
62
62
  this._authorizationResultCache = config.authorizationResultCache;
63
+ this._addressSelector = config.addressSelector;
63
64
  this._appIdentity = config.appIdentity;
64
65
  this._cluster = config.cluster;
65
66
  if (this._readyState !== walletAdapterBase.WalletReadyState.Unsupported) {
@@ -74,11 +75,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
74
75
  }
75
76
  }
76
77
  get publicKey() {
77
- if (this._publicKey == null && this._authorizationResult != null) {
78
+ if (this._publicKey == null && this._selectedAddress != null) {
78
79
  try {
79
- this._publicKey = getPublicKeyFromAddress(
80
- // TODO(#44): support multiple addresses
81
- this._authorizationResult.addresses[0]);
80
+ this._publicKey = getPublicKeyFromAddress(this._selectedAddress);
82
81
  }
83
82
  catch (e) {
84
83
  throw new walletAdapterBase.WalletPublicKeyError((e instanceof Error && (e === null || e === void 0 ? void 0 : e.message)) || 'Unknown error', e);
@@ -120,8 +119,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
120
119
  if (this._readyState !== walletAdapterBase.WalletReadyState.Installed) {
121
120
  this.emit('readyStateChange', (this._readyState = walletAdapterBase.WalletReadyState.Installed));
122
121
  }
122
+ this._selectedAddress = yield this._addressSelector.select(cachedAuthorizationResult.accounts.map(({ address }) => address));
123
123
  this.emit('connect',
124
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
124
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
125
125
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
126
  this.publicKey);
127
127
  return;
@@ -147,23 +147,33 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
147
147
  handleAuthorizationResult(authorizationResult) {
148
148
  var _a;
149
149
  return __awaiter(this, void 0, void 0, function* () {
150
- const didPublicKeyChange = ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.addresses[0]) !== authorizationResult.addresses[0]; // TODO(#44): support multiple addresses
150
+ const didPublicKeysChange =
151
+ // Case 1: We started from having no authorization.
152
+ this._authorizationResult == null ||
153
+ // Case 2: The number of authorized accounts changed.
154
+ ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.accounts.length) !== authorizationResult.accounts.length ||
155
+ // Case 3: The new list of addresses isn't exactly the same as the old list, in the same order.
156
+ this._authorizationResult.accounts.some((account, ii) => account.address !== authorizationResult.accounts[ii].address);
151
157
  this._authorizationResult = authorizationResult;
152
- if (didPublicKeyChange) {
153
- delete this._publicKey;
154
- this.emit('connect',
155
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
156
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
157
- this.publicKey);
158
+ if (didPublicKeysChange) {
159
+ const nextSelectedAddress = yield this._addressSelector.select(authorizationResult.accounts.map(({ address }) => address));
160
+ if (nextSelectedAddress !== this._selectedAddress) {
161
+ this._selectedAddress = nextSelectedAddress;
162
+ delete this._publicKey;
163
+ this.emit('connect',
164
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
165
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
166
+ this.publicKey);
167
+ }
158
168
  }
159
169
  yield this._authorizationResultCache.set(authorizationResult);
160
170
  });
161
171
  }
162
- performReauthorization(wallet, currentAuthorizationResult) {
172
+ performReauthorization(wallet, authToken) {
163
173
  return __awaiter(this, void 0, void 0, function* () {
164
174
  try {
165
175
  const authorizationResult = yield wallet.reauthorize({
166
- auth_token: currentAuthorizationResult.auth_token,
176
+ auth_token: authToken,
167
177
  });
168
178
  this.handleAuthorizationResult(authorizationResult); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
169
179
  }
@@ -178,6 +188,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
178
188
  this._authorizationResultCache.clear(); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
179
189
  delete this._authorizationResult;
180
190
  delete this._publicKey;
191
+ delete this._selectedAddress;
181
192
  this.emit('disconnect');
182
193
  });
183
194
  }
@@ -190,17 +201,19 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
190
201
  });
191
202
  }
192
203
  assertIsAuthorized() {
193
- const authorizationResult = this._authorizationResult;
194
- if (!authorizationResult)
204
+ if (!this._authorizationResult || !this._selectedAddress)
195
205
  throw new walletAdapterBase.WalletNotConnectedError();
196
- return authorizationResult;
206
+ return {
207
+ authToken: this._authorizationResult.auth_token,
208
+ selectedAddress: this._selectedAddress,
209
+ };
197
210
  }
198
211
  performSignTransactions(transactions) {
199
212
  return __awaiter(this, void 0, void 0, function* () {
200
- const authorizationResult = this.assertIsAuthorized();
213
+ const { authToken } = this.assertIsAuthorized();
201
214
  try {
202
215
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
203
- yield this.performReauthorization(wallet, authorizationResult);
216
+ yield this.performReauthorization(wallet, authToken);
204
217
  const signedTransactions = yield wallet.signTransactions({
205
218
  transactions,
206
219
  });
@@ -212,16 +225,58 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
212
225
  }
213
226
  });
214
227
  }
215
- sendTransaction(transaction, connection, _options) {
228
+ sendTransaction(transaction, connection, options) {
216
229
  return __awaiter(this, void 0, void 0, function* () {
217
230
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
218
- const authorizationResult = this.assertIsAuthorized();
231
+ const { authToken } = this.assertIsAuthorized();
232
+ const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
219
233
  try {
220
234
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
221
- yield this.performReauthorization(wallet, authorizationResult);
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
+ yield Promise.all([
259
+ 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
+ }))(),
276
+ ]);
277
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
222
278
  const signatures = yield wallet.signAndSendTransactions({
223
- connection,
224
- fee_payer: transaction.feePayer,
279
+ minContextSlot,
225
280
  transactions: [transaction],
226
281
  });
227
282
  return signatures[0];
@@ -252,11 +307,12 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
252
307
  signMessage(message) {
253
308
  return __awaiter(this, void 0, void 0, function* () {
254
309
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
255
- const authorizationResult = this.assertIsAuthorized();
310
+ const { authToken, selectedAddress } = this.assertIsAuthorized();
256
311
  try {
257
312
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
258
- yield this.performReauthorization(wallet, authorizationResult);
313
+ yield this.performReauthorization(wallet, authToken);
259
314
  const [signedMessage] = yield wallet.signMessages({
315
+ addresses: [selectedAddress],
260
316
  payloads: [message],
261
317
  });
262
318
  const signature = signedMessage.slice(-SIGNATURE_LENGTH_IN_BYTES);
@@ -271,6 +327,16 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
271
327
  }
272
328
  }
273
329
 
330
+ function createDefaultAddressSelector() {
331
+ return {
332
+ select(addresses) {
333
+ return __awaiter(this, void 0, void 0, function* () {
334
+ return addresses[0];
335
+ });
336
+ },
337
+ };
338
+ }
339
+
274
340
  const CACHE_KEY = 'SolanaMobileWalletAdapterDefaultAuthorizationCache';
275
341
  function createDefaultAuthorizationResultCache() {
276
342
  let storage;
@@ -321,4 +387,5 @@ function createDefaultAuthorizationResultCache() {
321
387
 
322
388
  exports.SolanaMobileWalletAdapter = SolanaMobileWalletAdapter;
323
389
  exports.SolanaMobileWalletAdapterWalletName = SolanaMobileWalletAdapterWalletName;
390
+ exports.createDefaultAddressSelector = createDefaultAddressSelector;
324
391
  exports.createDefaultAuthorizationResultCache = createDefaultAuthorizationResultCache;
@@ -57,6 +57,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
57
57
  this._connecting = false;
58
58
  this._readyState = getIsSupported() ? walletAdapterBase.WalletReadyState.Loadable : walletAdapterBase.WalletReadyState.Unsupported;
59
59
  this._authorizationResultCache = config.authorizationResultCache;
60
+ this._addressSelector = config.addressSelector;
60
61
  this._appIdentity = config.appIdentity;
61
62
  this._cluster = config.cluster;
62
63
  if (this._readyState !== walletAdapterBase.WalletReadyState.Unsupported) {
@@ -71,11 +72,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
71
72
  }
72
73
  }
73
74
  get publicKey() {
74
- if (this._publicKey == null && this._authorizationResult != null) {
75
+ if (this._publicKey == null && this._selectedAddress != null) {
75
76
  try {
76
- this._publicKey = getPublicKeyFromAddress(
77
- // TODO(#44): support multiple addresses
78
- this._authorizationResult.addresses[0]);
77
+ this._publicKey = getPublicKeyFromAddress(this._selectedAddress);
79
78
  }
80
79
  catch (e) {
81
80
  throw new walletAdapterBase.WalletPublicKeyError((e instanceof Error && (e === null || e === void 0 ? void 0 : e.message)) || 'Unknown error', e);
@@ -117,8 +116,9 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
117
116
  if (this._readyState !== walletAdapterBase.WalletReadyState.Installed) {
118
117
  this.emit('readyStateChange', (this._readyState = walletAdapterBase.WalletReadyState.Installed));
119
118
  }
119
+ this._selectedAddress = yield this._addressSelector.select(cachedAuthorizationResult.accounts.map(({ address }) => address));
120
120
  this.emit('connect',
121
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
121
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
122
122
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
123
123
  this.publicKey);
124
124
  return;
@@ -144,23 +144,33 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
144
144
  handleAuthorizationResult(authorizationResult) {
145
145
  var _a;
146
146
  return __awaiter(this, void 0, void 0, function* () {
147
- const didPublicKeyChange = ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.addresses[0]) !== authorizationResult.addresses[0]; // TODO(#44): support multiple addresses
147
+ const didPublicKeysChange =
148
+ // Case 1: We started from having no authorization.
149
+ this._authorizationResult == null ||
150
+ // Case 2: The number of authorized accounts changed.
151
+ ((_a = this._authorizationResult) === null || _a === void 0 ? void 0 : _a.accounts.length) !== authorizationResult.accounts.length ||
152
+ // Case 3: The new list of addresses isn't exactly the same as the old list, in the same order.
153
+ this._authorizationResult.accounts.some((account, ii) => account.address !== authorizationResult.accounts[ii].address);
148
154
  this._authorizationResult = authorizationResult;
149
- if (didPublicKeyChange) {
150
- delete this._publicKey;
151
- this.emit('connect',
152
- // Having just set an `authorizationResult`, `this.publicKey` is definitely non-null
153
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
154
- this.publicKey);
155
+ if (didPublicKeysChange) {
156
+ const nextSelectedAddress = yield this._addressSelector.select(authorizationResult.accounts.map(({ address }) => address));
157
+ if (nextSelectedAddress !== this._selectedAddress) {
158
+ this._selectedAddress = nextSelectedAddress;
159
+ delete this._publicKey;
160
+ this.emit('connect',
161
+ // Having just set `this._selectedAddress`, `this.publicKey` is definitely non-null
162
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
163
+ this.publicKey);
164
+ }
155
165
  }
156
166
  yield this._authorizationResultCache.set(authorizationResult);
157
167
  });
158
168
  }
159
- performReauthorization(wallet, currentAuthorizationResult) {
169
+ performReauthorization(wallet, authToken) {
160
170
  return __awaiter(this, void 0, void 0, function* () {
161
171
  try {
162
172
  const authorizationResult = yield wallet.reauthorize({
163
- auth_token: currentAuthorizationResult.auth_token,
173
+ auth_token: authToken,
164
174
  });
165
175
  this.handleAuthorizationResult(authorizationResult); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
166
176
  }
@@ -175,6 +185,7 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
175
185
  this._authorizationResultCache.clear(); // TODO: Evaluate whether there's any threat to not `awaiting` this expression
176
186
  delete this._authorizationResult;
177
187
  delete this._publicKey;
188
+ delete this._selectedAddress;
178
189
  this.emit('disconnect');
179
190
  });
180
191
  }
@@ -187,17 +198,19 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
187
198
  });
188
199
  }
189
200
  assertIsAuthorized() {
190
- const authorizationResult = this._authorizationResult;
191
- if (!authorizationResult)
201
+ if (!this._authorizationResult || !this._selectedAddress)
192
202
  throw new walletAdapterBase.WalletNotConnectedError();
193
- return authorizationResult;
203
+ return {
204
+ authToken: this._authorizationResult.auth_token,
205
+ selectedAddress: this._selectedAddress,
206
+ };
194
207
  }
195
208
  performSignTransactions(transactions) {
196
209
  return __awaiter(this, void 0, void 0, function* () {
197
- const authorizationResult = this.assertIsAuthorized();
210
+ const { authToken } = this.assertIsAuthorized();
198
211
  try {
199
212
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
200
- yield this.performReauthorization(wallet, authorizationResult);
213
+ yield this.performReauthorization(wallet, authToken);
201
214
  const signedTransactions = yield wallet.signTransactions({
202
215
  transactions,
203
216
  });
@@ -209,16 +222,58 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
209
222
  }
210
223
  });
211
224
  }
212
- sendTransaction(transaction, connection, _options) {
225
+ sendTransaction(transaction, connection, options) {
213
226
  return __awaiter(this, void 0, void 0, function* () {
214
227
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
215
- const authorizationResult = this.assertIsAuthorized();
228
+ const { authToken } = this.assertIsAuthorized();
229
+ const minContextSlot = options === null || options === void 0 ? void 0 : options.minContextSlot;
216
230
  try {
217
231
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
218
- yield this.performReauthorization(wallet, authorizationResult);
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
+ yield Promise.all([
256
+ 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
+ }))(),
273
+ ]);
274
+ transaction.feePayer || (transaction.feePayer = (_a = this.publicKey) !== null && _a !== void 0 ? _a : undefined);
219
275
  const signatures = yield wallet.signAndSendTransactions({
220
- connection,
221
- fee_payer: transaction.feePayer,
276
+ minContextSlot,
222
277
  transactions: [transaction],
223
278
  });
224
279
  return signatures[0];
@@ -249,11 +304,12 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
249
304
  signMessage(message) {
250
305
  return __awaiter(this, void 0, void 0, function* () {
251
306
  return yield this.runWithGuard(() => __awaiter(this, void 0, void 0, function* () {
252
- const authorizationResult = this.assertIsAuthorized();
307
+ const { authToken, selectedAddress } = this.assertIsAuthorized();
253
308
  try {
254
309
  return yield this.transact((wallet) => __awaiter(this, void 0, void 0, function* () {
255
- yield this.performReauthorization(wallet, authorizationResult);
310
+ yield this.performReauthorization(wallet, authToken);
256
311
  const [signedMessage] = yield wallet.signMessages({
312
+ addresses: [selectedAddress],
257
313
  payloads: [message],
258
314
  });
259
315
  const signature = signedMessage.slice(-SIGNATURE_LENGTH_IN_BYTES);
@@ -268,6 +324,16 @@ class SolanaMobileWalletAdapter extends walletAdapterBase.BaseMessageSignerWalle
268
324
  }
269
325
  }
270
326
 
327
+ function createDefaultAddressSelector() {
328
+ return {
329
+ select(addresses) {
330
+ return __awaiter(this, void 0, void 0, function* () {
331
+ return addresses[0];
332
+ });
333
+ },
334
+ };
335
+ }
336
+
271
337
  const CACHE_KEY = 'SolanaMobileWalletAdapterDefaultAuthorizationCache';
272
338
  function createDefaultAuthorizationResultCache() {
273
339
  return {
@@ -303,4 +369,5 @@ function createDefaultAuthorizationResultCache() {
303
369
 
304
370
  exports.SolanaMobileWalletAdapter = SolanaMobileWalletAdapter;
305
371
  exports.SolanaMobileWalletAdapterWalletName = SolanaMobileWalletAdapterWalletName;
372
+ exports.createDefaultAddressSelector = createDefaultAddressSelector;
306
373
  exports.createDefaultAuthorizationResultCache = createDefaultAuthorizationResultCache;