@dynamic-labs/embedded-wallet-solana 4.0.0-alpha.3 → 4.0.0-alpha.31

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.
@@ -6,7 +6,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
6
6
  var _tslib = require('../../../_virtual/_tslib.cjs');
7
7
  var web3_js = require('@solana/web3.js');
8
8
  var webauthnStamper = require('@turnkey/webauthn-stamper');
9
- var http = require('@turnkey/http');
10
9
  var solana = require('@turnkey/solana');
11
10
  var iframeStamper = require('@turnkey/iframe-stamper');
12
11
  var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
@@ -14,7 +13,6 @@ var utils = require('@dynamic-labs/utils');
14
13
  var solanaCore = require('@dynamic-labs/solana-core');
15
14
  var embeddedWallet = require('@dynamic-labs/embedded-wallet');
16
15
  var createSolanaConnection = require('../utils/createSolanaConnection/createSolanaConnection.cjs');
17
- var transactionDecoder = require('../utils/transactionDecoder/transactionDecoder.cjs');
18
16
  var api = require('../utils/api/api.cjs');
19
17
  var TurnkeySolanaSigner = require('./TurnkeySolanaSigner.cjs');
20
18
 
@@ -44,17 +42,13 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
44
42
  }
45
43
  throw new Error('Failed to get environment id');
46
44
  };
47
- this.stampCreateWalletAccountRequest = (_b) => _tslib.__awaiter(this, [_b], void 0, function* ({ request, }) {
48
- yield this.createOrRestoreSession();
49
- const turnkeyClient = this.getTurnkeyClient();
50
- return turnkeyClient.stampCreateWalletAccounts(request);
51
- });
52
45
  this.solNetworks = props.solNetworks;
53
46
  this.walletUiUtils = props.walletUiUtils;
54
47
  this._turnkeyAccount = undefined;
55
48
  this._connectionClient = undefined;
49
+ this.connectionConfig = props.connectionConfig;
56
50
  this.chainRpcProviders = props.chainRpcProviders;
57
- (_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders();
51
+ (_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
58
52
  this.__turnkeyClient = this.getTurnkeyClient();
59
53
  }
60
54
  getRpcUrl() {
@@ -70,7 +64,9 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
70
64
  const rpcUrl = this.getRpcUrl();
71
65
  if (!rpcUrl)
72
66
  throw new utils.DynamicError('No rpcUrl');
73
- this._connectionClient = createSolanaConnection.createSolanaConnection(rpcUrl, commitmentOrConfig);
67
+ const config = typeof commitmentOrConfig === 'string'
68
+ ? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
69
+ this._connectionClient = createSolanaConnection.createSolanaConnection(rpcUrl, config);
74
70
  }
75
71
  return this._connectionClient;
76
72
  }
@@ -159,23 +155,6 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
159
155
  return this.getTurnkeyAccount();
160
156
  });
161
157
  }
162
- getTurnkeyClient() {
163
- var _a;
164
- let rpId = utils.getTLD();
165
- if (!rpId) {
166
- rpId = utils.PlatformService.getHostname();
167
- }
168
- const passkeyStamper = embeddedWallet.PasskeyService.createWebauthnStamper({
169
- rpId,
170
- });
171
- const apiKeyStamper = embeddedWallet.TurnkeyWalletConnectorBase === null || embeddedWallet.TurnkeyWalletConnectorBase === void 0 ? void 0 : embeddedWallet.TurnkeyWalletConnectorBase.apiKeyStamper;
172
- const stamper = apiKeyStamper !== null && apiKeyStamper !== void 0 ? apiKeyStamper : passkeyStamper;
173
- this.__turnkeyClient =
174
- (_a = this.getAuthenticatorHandler().client) !== null && _a !== void 0 ? _a : new http.TurnkeyClient({
175
- baseUrl: embeddedWallet.TURNKEY_API_BASE_URL,
176
- }, stamper);
177
- return this.__turnkeyClient;
178
- }
179
158
  createTurnkeyAccount(_a) {
180
159
  return _tslib.__awaiter(this, arguments, void 0, function* ({ organizationId, }) {
181
160
  const turnkeyClient = this.getTurnkeyClient();
@@ -260,7 +239,7 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
260
239
  return utils.bufferToBase64(signedRawMessage);
261
240
  });
262
241
  }
263
- signTransaction(transaction) {
242
+ internalSignTransaction(transaction) {
264
243
  return _tslib.__awaiter(this, void 0, void 0, function* () {
265
244
  yield this.createOrRestoreSession();
266
245
  let account = yield this.getTurnkeyAccount();
@@ -288,27 +267,84 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
288
267
  return transaction;
289
268
  });
290
269
  }
291
- internalSignAndSendTransaction(transaction, options) {
270
+ signTransaction(transaction) {
292
271
  return _tslib.__awaiter(this, void 0, void 0, function* () {
293
- var _a;
294
272
  if (!this.turnkeyAddress)
295
- throw new utils.DynamicError('Solana wallet not found');
296
- const currentConnection = this.getConnection('confirmed');
297
- const blockhash = yield currentConnection.getLatestBlockhash();
298
- if ('version' in transaction) {
299
- transaction.message.recentBlockhash =
300
- blockhash.blockhash;
273
+ throw new utils.DynamicError('No turnkey account');
274
+ const uiTransaction = new solanaCore.SolanaUiTransaction({
275
+ connection: this.getConnection(),
276
+ from: this.turnkeyAddress,
277
+ multipleTransactions: [transaction],
278
+ onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
279
+ });
280
+ return this.walletUiUtils.signTransaction(this, uiTransaction);
281
+ });
282
+ }
283
+ createUiTransaction(from) {
284
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
285
+ yield this.validateActiveWallet(from);
286
+ const transaction = new solanaCore.SolanaUiTransaction({
287
+ connection: this.getConnection(),
288
+ from,
289
+ onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () {
290
+ if (!transaction)
291
+ return undefined;
292
+ return this.internalSignAndSendTransaction(transaction);
293
+ }),
294
+ });
295
+ return transaction;
296
+ });
297
+ }
298
+ internalSignAllTransactions(transactions) {
299
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
300
+ yield this.createOrRestoreSession();
301
+ let account = yield this.getTurnkeyAccount();
302
+ const address = this.turnkeyAddress;
303
+ if (!account || !address) {
304
+ throw new Error('No turnkey account');
301
305
  }
302
- else {
303
- transaction.recentBlockhash = blockhash.blockhash;
304
- transaction.feePayer =
305
- (_a = transaction.feePayer) !== null && _a !== void 0 ? _a : new web3_js.PublicKey(this.turnkeyAddress);
306
+ try {
307
+ const signedTransactions = yield account.signAllTransactions(transactions, address);
308
+ return signedTransactions;
309
+ }
310
+ catch (err) {
311
+ if (embeddedWallet.TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS.some((errorMsg) => err.message.includes(errorMsg))) {
312
+ yield this.removeSessionKeys();
313
+ yield this.createOrRestoreSession({
314
+ ignoreRestore: true,
315
+ });
316
+ account = (yield this.getTurnkeyAccount());
317
+ const signedTransactions = yield account.signAllTransactions(transactions, address);
318
+ return signedTransactions;
319
+ }
320
+ else {
321
+ embeddedWallet.logger.error('[TK] failed to perform SignAllTransactions activity', err);
322
+ throw err;
323
+ }
306
324
  }
307
- const signedTransaction = yield this.signTransaction(transaction);
308
- const signature = yield currentConnection.sendRawTransaction(Buffer.from(signedTransaction.serialize({
309
- requireAllSignatures: false,
310
- verifySignatures: false,
311
- })), options);
325
+ });
326
+ }
327
+ signAllTransactions(transactions) {
328
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
329
+ if (!this.turnkeyAddress)
330
+ throw new utils.DynamicError('No turnkey account');
331
+ const uiTransaction = new solanaCore.SolanaUiTransaction({
332
+ connection: this.getConnection(),
333
+ from: this.turnkeyAddress,
334
+ multipleTransactions: transactions,
335
+ onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
336
+ });
337
+ return this.walletUiUtils.signTransaction(this, uiTransaction);
338
+ });
339
+ }
340
+ internalSignAndSendTransaction(transaction, options) {
341
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
342
+ var _a, _b;
343
+ if (!this.turnkeyAddress)
344
+ throw new utils.DynamicError('Solana wallet not found');
345
+ const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
346
+ const signedTransaction = yield this.internalSignTransaction(transaction);
347
+ const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
312
348
  // listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
313
349
  return new Promise((resolve, reject) => {
314
350
  const timeout = setTimeout(() => {
@@ -328,44 +364,15 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
328
364
  }
329
365
  signAndSendTransaction(transaction, options) {
330
366
  return _tslib.__awaiter(this, void 0, void 0, function* () {
331
- var _a;
332
367
  if (!this.turnkeyAddress)
333
368
  throw new utils.DynamicError('Solana wallet not found');
334
- let optimizedTransaction = transaction;
335
- try {
336
- if ((yield this.getNetwork()) === 'mainnet') {
337
- optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
338
- }
339
- }
340
- catch (e) {
341
- embeddedWallet.logger.warn('Failed to optimize transaction', e);
342
- }
343
- const transactionsData = yield transactionDecoder.decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
344
- if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
345
- throw new utils.DynamicError('Incorrectly formatted transaction instructions');
346
- }
347
- let spent;
348
- let insufficientFunds = false;
349
- try {
350
- spent = yield transactionDecoder.getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
351
- }
352
- catch (e) {
353
- if (e.message === 'Insufficient funds') {
354
- insufficientFunds = true;
355
- }
356
- }
357
- const to = transactionDecoder.summarizeTransactionDecodedData(transactionsData);
369
+ const optimizedTransaction = yield this.optimizeTransaction(transaction);
358
370
  const uiTransaction = new solanaCore.SolanaUiTransaction({
359
371
  connection: this.getConnection(),
360
372
  from: this.turnkeyAddress,
373
+ multipleTransactions: [optimizedTransaction],
361
374
  onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
362
- originalTransaction: optimizedTransaction,
363
375
  });
364
- uiTransaction.to = to;
365
- uiTransaction.value = spent;
366
- if (insufficientFunds) {
367
- uiTransaction.notEnoughFundsError = true;
368
- }
369
376
  // TODO: remove this. We should not be passing references to wallet connectors
370
377
  return this.walletUiUtils.sendTransaction(this, uiTransaction);
371
378
  });
@@ -408,16 +415,27 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
408
415
  lamportsToSol(lamports) {
409
416
  return lamports / web3_js.LAMPORTS_PER_SOL;
410
417
  }
411
- createUiTransaction(from) {
418
+ optimizeTransaction(transaction) {
412
419
  return _tslib.__awaiter(this, void 0, void 0, function* () {
413
- yield this.validateActiveWallet(from);
414
- const transaction = new solanaCore.SolanaUiTransaction({
415
- connection: this.getConnection(),
416
- from,
417
- onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
418
- });
419
- transaction.feeDeducted = true;
420
- return transaction;
420
+ var _a;
421
+ let optimizedTransaction = transaction;
422
+ let alreadySigned = false;
423
+ if ('version' in transaction) {
424
+ alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
425
+ }
426
+ else {
427
+ alreadySigned = transaction.signatures.some((sig) => sig.signature);
428
+ }
429
+ try {
430
+ // we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
431
+ if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
432
+ optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
433
+ }
434
+ }
435
+ catch (e) {
436
+ embeddedWallet.logger.warn('Failed to optimize transaction', e);
437
+ }
438
+ return optimizedTransaction;
421
439
  });
422
440
  }
423
441
  }
@@ -1,5 +1,4 @@
1
1
  import { Commitment, Connection, ConnectionConfig, Transaction, VersionedTransaction, ConfirmOptions, Signer, SendOptions } from '@solana/web3.js';
2
- import { TurnkeyApiTypes } from '@turnkey/http';
3
2
  import { GenericNetwork, IUITransaction, WalletUiUtils } from '@dynamic-labs/types';
4
3
  import { Chain, ISendBalanceWalletConnector, InternalWalletConnector } from '@dynamic-labs/wallet-connector-core';
5
4
  import { WalletBookSchema } from '@dynamic-labs/wallet-book';
@@ -16,6 +15,7 @@ export type TurnkeySolanaConnectorProps = {
16
15
  solNetworks: GenericNetwork[];
17
16
  appName?: string;
18
17
  chainRpcProviders: IChainRpcProviders;
18
+ connectionConfig?: ConnectionConfig;
19
19
  };
20
20
  export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase implements ISendBalanceWalletConnector {
21
21
  ChainWallet: typeof SolanaWallet;
@@ -26,7 +26,7 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
26
26
  private walletUiUtils;
27
27
  private _turnkeyAccount;
28
28
  private _connectionClient;
29
- private __turnkeyClient;
29
+ private connectionConfig;
30
30
  constructor(nameAndKey: TurnkeyWalletConnectorNameAndKey, props: TurnkeySolanaConnectorProps);
31
31
  getRpcUrl(): string;
32
32
  getConnection(commitmentOrConfig?: Commitment | ConnectionConfig): Connection;
@@ -39,7 +39,6 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
39
39
  getAccount(): string | undefined;
40
40
  endSession(): Promise<void>;
41
41
  private refreshTurnkeyAccount;
42
- private getTurnkeyClient;
43
42
  private createTurnkeyAccount;
44
43
  private getTurnkeyAccount;
45
44
  getSigner(): Promise<TurnkeySolanaSigner | undefined>;
@@ -47,14 +46,15 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
47
46
  signUint8ArrayMessage(encodedMessage: Uint8Array): Promise<Uint8Array>;
48
47
  getEnvId: () => any;
49
48
  signMessage(messageToSign: string): Promise<string | undefined>;
49
+ internalSignTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
50
50
  signTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
51
+ createUiTransaction(from: string): Promise<IUITransaction>;
52
+ internalSignAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
53
+ signAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
51
54
  internalSignAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
52
55
  signAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
53
56
  sendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendTransactionOptions): Promise<string>;
54
57
  private lamportsToSol;
55
- createUiTransaction(from: string): Promise<IUITransaction>;
56
- stampCreateWalletAccountRequest: ({ request, }: {
57
- request: TurnkeyApiTypes['v1CreateWalletAccountsRequest'];
58
- }) => Promise<import("@turnkey/http").TSignedRequest>;
58
+ private optimizeTransaction;
59
59
  }
60
60
  export {};
@@ -2,15 +2,13 @@
2
2
  import { __awaiter, __rest } from '../../../_virtual/_tslib.js';
3
3
  import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
4
4
  import { WebauthnStamper } from '@turnkey/webauthn-stamper';
5
- import { TurnkeyClient } from '@turnkey/http';
6
5
  import { TurnkeySigner } from '@turnkey/solana';
7
6
  import { IframeStamper } from '@turnkey/iframe-stamper';
8
7
  import { isSameAddress } from '@dynamic-labs/wallet-connector-core';
9
- import { DynamicError, getTLD, PlatformService, bufferToBase64 } from '@dynamic-labs/utils';
8
+ import { DynamicError, bufferToBase64 } from '@dynamic-labs/utils';
10
9
  import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
11
- import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, PasskeyService, TURNKEY_API_BASE_URL, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
10
+ import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
12
11
  import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
13
- import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
14
12
  import { optimizeSolanaTransaction } from '../utils/api/api.js';
15
13
  import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
16
14
 
@@ -40,17 +38,13 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
40
38
  }
41
39
  throw new Error('Failed to get environment id');
42
40
  };
43
- this.stampCreateWalletAccountRequest = (_b) => __awaiter(this, [_b], void 0, function* ({ request, }) {
44
- yield this.createOrRestoreSession();
45
- const turnkeyClient = this.getTurnkeyClient();
46
- return turnkeyClient.stampCreateWalletAccounts(request);
47
- });
48
41
  this.solNetworks = props.solNetworks;
49
42
  this.walletUiUtils = props.walletUiUtils;
50
43
  this._turnkeyAccount = undefined;
51
44
  this._connectionClient = undefined;
45
+ this.connectionConfig = props.connectionConfig;
52
46
  this.chainRpcProviders = props.chainRpcProviders;
53
- (_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders();
47
+ (_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
54
48
  this.__turnkeyClient = this.getTurnkeyClient();
55
49
  }
56
50
  getRpcUrl() {
@@ -66,7 +60,9 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
66
60
  const rpcUrl = this.getRpcUrl();
67
61
  if (!rpcUrl)
68
62
  throw new DynamicError('No rpcUrl');
69
- this._connectionClient = createSolanaConnection(rpcUrl, commitmentOrConfig);
63
+ const config = typeof commitmentOrConfig === 'string'
64
+ ? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
65
+ this._connectionClient = createSolanaConnection(rpcUrl, config);
70
66
  }
71
67
  return this._connectionClient;
72
68
  }
@@ -155,23 +151,6 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
155
151
  return this.getTurnkeyAccount();
156
152
  });
157
153
  }
158
- getTurnkeyClient() {
159
- var _a;
160
- let rpId = getTLD();
161
- if (!rpId) {
162
- rpId = PlatformService.getHostname();
163
- }
164
- const passkeyStamper = PasskeyService.createWebauthnStamper({
165
- rpId,
166
- });
167
- const apiKeyStamper = TurnkeyWalletConnectorBase === null || TurnkeyWalletConnectorBase === void 0 ? void 0 : TurnkeyWalletConnectorBase.apiKeyStamper;
168
- const stamper = apiKeyStamper !== null && apiKeyStamper !== void 0 ? apiKeyStamper : passkeyStamper;
169
- this.__turnkeyClient =
170
- (_a = this.getAuthenticatorHandler().client) !== null && _a !== void 0 ? _a : new TurnkeyClient({
171
- baseUrl: TURNKEY_API_BASE_URL,
172
- }, stamper);
173
- return this.__turnkeyClient;
174
- }
175
154
  createTurnkeyAccount(_a) {
176
155
  return __awaiter(this, arguments, void 0, function* ({ organizationId, }) {
177
156
  const turnkeyClient = this.getTurnkeyClient();
@@ -256,7 +235,7 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
256
235
  return bufferToBase64(signedRawMessage);
257
236
  });
258
237
  }
259
- signTransaction(transaction) {
238
+ internalSignTransaction(transaction) {
260
239
  return __awaiter(this, void 0, void 0, function* () {
261
240
  yield this.createOrRestoreSession();
262
241
  let account = yield this.getTurnkeyAccount();
@@ -284,27 +263,84 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
284
263
  return transaction;
285
264
  });
286
265
  }
287
- internalSignAndSendTransaction(transaction, options) {
266
+ signTransaction(transaction) {
288
267
  return __awaiter(this, void 0, void 0, function* () {
289
- var _a;
290
268
  if (!this.turnkeyAddress)
291
- throw new DynamicError('Solana wallet not found');
292
- const currentConnection = this.getConnection('confirmed');
293
- const blockhash = yield currentConnection.getLatestBlockhash();
294
- if ('version' in transaction) {
295
- transaction.message.recentBlockhash =
296
- blockhash.blockhash;
269
+ throw new DynamicError('No turnkey account');
270
+ const uiTransaction = new SolanaUiTransaction({
271
+ connection: this.getConnection(),
272
+ from: this.turnkeyAddress,
273
+ multipleTransactions: [transaction],
274
+ onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
275
+ });
276
+ return this.walletUiUtils.signTransaction(this, uiTransaction);
277
+ });
278
+ }
279
+ createUiTransaction(from) {
280
+ return __awaiter(this, void 0, void 0, function* () {
281
+ yield this.validateActiveWallet(from);
282
+ const transaction = new SolanaUiTransaction({
283
+ connection: this.getConnection(),
284
+ from,
285
+ onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () {
286
+ if (!transaction)
287
+ return undefined;
288
+ return this.internalSignAndSendTransaction(transaction);
289
+ }),
290
+ });
291
+ return transaction;
292
+ });
293
+ }
294
+ internalSignAllTransactions(transactions) {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ yield this.createOrRestoreSession();
297
+ let account = yield this.getTurnkeyAccount();
298
+ const address = this.turnkeyAddress;
299
+ if (!account || !address) {
300
+ throw new Error('No turnkey account');
297
301
  }
298
- else {
299
- transaction.recentBlockhash = blockhash.blockhash;
300
- transaction.feePayer =
301
- (_a = transaction.feePayer) !== null && _a !== void 0 ? _a : new PublicKey(this.turnkeyAddress);
302
+ try {
303
+ const signedTransactions = yield account.signAllTransactions(transactions, address);
304
+ return signedTransactions;
305
+ }
306
+ catch (err) {
307
+ if (TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS.some((errorMsg) => err.message.includes(errorMsg))) {
308
+ yield this.removeSessionKeys();
309
+ yield this.createOrRestoreSession({
310
+ ignoreRestore: true,
311
+ });
312
+ account = (yield this.getTurnkeyAccount());
313
+ const signedTransactions = yield account.signAllTransactions(transactions, address);
314
+ return signedTransactions;
315
+ }
316
+ else {
317
+ logger.error('[TK] failed to perform SignAllTransactions activity', err);
318
+ throw err;
319
+ }
302
320
  }
303
- const signedTransaction = yield this.signTransaction(transaction);
304
- const signature = yield currentConnection.sendRawTransaction(Buffer.from(signedTransaction.serialize({
305
- requireAllSignatures: false,
306
- verifySignatures: false,
307
- })), options);
321
+ });
322
+ }
323
+ signAllTransactions(transactions) {
324
+ return __awaiter(this, void 0, void 0, function* () {
325
+ if (!this.turnkeyAddress)
326
+ throw new DynamicError('No turnkey account');
327
+ const uiTransaction = new SolanaUiTransaction({
328
+ connection: this.getConnection(),
329
+ from: this.turnkeyAddress,
330
+ multipleTransactions: transactions,
331
+ onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
332
+ });
333
+ return this.walletUiUtils.signTransaction(this, uiTransaction);
334
+ });
335
+ }
336
+ internalSignAndSendTransaction(transaction, options) {
337
+ return __awaiter(this, void 0, void 0, function* () {
338
+ var _a, _b;
339
+ if (!this.turnkeyAddress)
340
+ throw new DynamicError('Solana wallet not found');
341
+ const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
342
+ const signedTransaction = yield this.internalSignTransaction(transaction);
343
+ const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
308
344
  // listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
309
345
  return new Promise((resolve, reject) => {
310
346
  const timeout = setTimeout(() => {
@@ -324,44 +360,15 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
324
360
  }
325
361
  signAndSendTransaction(transaction, options) {
326
362
  return __awaiter(this, void 0, void 0, function* () {
327
- var _a;
328
363
  if (!this.turnkeyAddress)
329
364
  throw new DynamicError('Solana wallet not found');
330
- let optimizedTransaction = transaction;
331
- try {
332
- if ((yield this.getNetwork()) === 'mainnet') {
333
- optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
334
- }
335
- }
336
- catch (e) {
337
- logger.warn('Failed to optimize transaction', e);
338
- }
339
- const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
340
- if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
341
- throw new DynamicError('Incorrectly formatted transaction instructions');
342
- }
343
- let spent;
344
- let insufficientFunds = false;
345
- try {
346
- spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
347
- }
348
- catch (e) {
349
- if (e.message === 'Insufficient funds') {
350
- insufficientFunds = true;
351
- }
352
- }
353
- const to = summarizeTransactionDecodedData(transactionsData);
365
+ const optimizedTransaction = yield this.optimizeTransaction(transaction);
354
366
  const uiTransaction = new SolanaUiTransaction({
355
367
  connection: this.getConnection(),
356
368
  from: this.turnkeyAddress,
369
+ multipleTransactions: [optimizedTransaction],
357
370
  onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
358
- originalTransaction: optimizedTransaction,
359
371
  });
360
- uiTransaction.to = to;
361
- uiTransaction.value = spent;
362
- if (insufficientFunds) {
363
- uiTransaction.notEnoughFundsError = true;
364
- }
365
372
  // TODO: remove this. We should not be passing references to wallet connectors
366
373
  return this.walletUiUtils.sendTransaction(this, uiTransaction);
367
374
  });
@@ -404,16 +411,27 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
404
411
  lamportsToSol(lamports) {
405
412
  return lamports / LAMPORTS_PER_SOL;
406
413
  }
407
- createUiTransaction(from) {
414
+ optimizeTransaction(transaction) {
408
415
  return __awaiter(this, void 0, void 0, function* () {
409
- yield this.validateActiveWallet(from);
410
- const transaction = new SolanaUiTransaction({
411
- connection: this.getConnection(),
412
- from,
413
- onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
414
- });
415
- transaction.feeDeducted = true;
416
- return transaction;
416
+ var _a;
417
+ let optimizedTransaction = transaction;
418
+ let alreadySigned = false;
419
+ if ('version' in transaction) {
420
+ alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
421
+ }
422
+ else {
423
+ alreadySigned = transaction.signatures.some((sig) => sig.signature);
424
+ }
425
+ try {
426
+ // we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
427
+ if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
428
+ optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
429
+ }
430
+ }
431
+ catch (e) {
432
+ logger.warn('Failed to optimize transaction', e);
433
+ }
434
+ return optimizedTransaction;
417
435
  });
418
436
  }
419
437
  }
@@ -1,2 +1 @@
1
1
  export { createSolanaConnection } from './createSolanaConnection';
2
- export { decodeTransaction, summarizeTransactionDecodedData, getTotalSolanaSpend, } from './transactionDecoder';
@@ -1 +0,0 @@
1
- export { decodeTransaction, summarizeTransactionDecodedData, getTotalSolanaSpend, } from './transactionDecoder';