@dynamic-labs/embedded-wallet-solana 4.0.0-alpha.27 → 4.0.0-alpha.29

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/CHANGELOG.md CHANGED
@@ -1,4 +1,25 @@
1
1
 
2
+ ## [4.0.0-alpha.29](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.28...v4.0.0-alpha.29) (2024-11-07)
3
+
4
+ ## [4.0.0-alpha.28](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.27...v4.0.0-alpha.28) (2024-11-07)
5
+
6
+
7
+ ### ⚠ BREAKING CHANGES
8
+
9
+ * upgrade to starknet v6
10
+ See this guide for more details: https://starknetjs.com/docs/guides/migrate/
11
+ There are no code changes required on the Dynamic SDK side, however if you have installed the `starknet` package, you will need to upgrade to >= v6.11.0.
12
+
13
+ ### Features
14
+
15
+ * new transaction modal and ui for sign/signAll ([#7296](https://github.com/dynamic-labs/dynamic-auth/issues/7296)) ([05a8af1](https://github.com/dynamic-labs/dynamic-auth/commit/05a8af1eb772b2b8087ed96a54caf4b6ae8b79d2)), closes [#7297](https://github.com/dynamic-labs/dynamic-auth/issues/7297) [#7298](https://github.com/dynamic-labs/dynamic-auth/issues/7298)
16
+ * upgrade to starknet v6 ([#7189](https://github.com/dynamic-labs/dynamic-auth/issues/7189)) ([2a6e24e](https://github.com/dynamic-labs/dynamic-auth/commit/2a6e24e4178fcee671b381c28f6a681f4ce52c62))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * transaction confirmation modal popup ([#7368](https://github.com/dynamic-labs/dynamic-auth/issues/7368)) ([3c48658](https://github.com/dynamic-labs/dynamic-auth/commit/3c48658a62874d908bba8f06fb092ff5983ede16))
22
+
2
23
  ## [4.0.0-alpha.27](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.26...v4.0.0-alpha.27) (2024-11-06)
3
24
 
4
25
 
package/package.cjs CHANGED
@@ -3,14 +3,13 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.0.0-alpha.27";
6
+ var version = "4.0.0-alpha.29";
7
7
  var dependencies = {
8
- "@dynamic-labs/utils": "4.0.0-alpha.27",
9
- "@dynamic-labs/logger": "4.0.0-alpha.27",
10
- "@dynamic-labs/types": "4.0.0-alpha.27",
11
- "@dynamic-labs/sdk-api-core": "0.0.559",
8
+ "@dynamic-labs/utils": "4.0.0-alpha.29",
9
+ "@dynamic-labs/logger": "4.0.0-alpha.29",
10
+ "@dynamic-labs/types": "4.0.0-alpha.29",
11
+ "@dynamic-labs/sdk-api-core": "0.0.563",
12
12
  eventemitter3: "5.0.1",
13
- "@solana/spl-token": "0.4.6",
14
13
  "@solana/web3.js": "1.92.1",
15
14
  "@turnkey/iframe-stamper": "2.0.0",
16
15
  "@turnkey/solana": "1.0.1",
package/package.js CHANGED
@@ -1,12 +1,11 @@
1
1
  'use client'
2
- var version = "4.0.0-alpha.27";
2
+ var version = "4.0.0-alpha.29";
3
3
  var dependencies = {
4
- "@dynamic-labs/utils": "4.0.0-alpha.27",
5
- "@dynamic-labs/logger": "4.0.0-alpha.27",
6
- "@dynamic-labs/types": "4.0.0-alpha.27",
7
- "@dynamic-labs/sdk-api-core": "0.0.559",
4
+ "@dynamic-labs/utils": "4.0.0-alpha.29",
5
+ "@dynamic-labs/logger": "4.0.0-alpha.29",
6
+ "@dynamic-labs/types": "4.0.0-alpha.29",
7
+ "@dynamic-labs/sdk-api-core": "0.0.563",
8
8
  eventemitter3: "5.0.1",
9
- "@solana/spl-token": "0.4.6",
10
9
  "@solana/web3.js": "1.92.1",
11
10
  "@turnkey/iframe-stamper": "2.0.0",
12
11
  "@turnkey/solana": "1.0.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/embedded-wallet-solana",
3
- "version": "4.0.0-alpha.27",
3
+ "version": "4.0.0-alpha.29",
4
4
  "description": "A React SDK for implementing wallet web3 authentication and authorization to your website.",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -18,23 +18,22 @@
18
18
  },
19
19
  "homepage": "https://www.dynamic.xyz/",
20
20
  "dependencies": {
21
- "@dynamic-labs/utils": "4.0.0-alpha.27",
22
- "@dynamic-labs/logger": "4.0.0-alpha.27",
23
- "@dynamic-labs/types": "4.0.0-alpha.27",
24
- "@dynamic-labs/sdk-api-core": "0.0.559",
21
+ "@dynamic-labs/utils": "4.0.0-alpha.29",
22
+ "@dynamic-labs/logger": "4.0.0-alpha.29",
23
+ "@dynamic-labs/types": "4.0.0-alpha.29",
24
+ "@dynamic-labs/sdk-api-core": "0.0.563",
25
25
  "eventemitter3": "5.0.1",
26
- "@solana/spl-token": "0.4.6",
27
26
  "@solana/web3.js": "1.92.1",
28
27
  "@turnkey/iframe-stamper": "2.0.0",
29
28
  "@turnkey/solana": "1.0.1",
30
29
  "@turnkey/webauthn-stamper": "0.5.0",
31
- "@dynamic-labs/assert-package-version": "4.0.0-alpha.27",
32
- "@dynamic-labs/embedded-wallet": "4.0.0-alpha.27",
33
- "@dynamic-labs/rpc-providers": "4.0.0-alpha.27",
34
- "@dynamic-labs/solana-core": "4.0.0-alpha.27",
35
- "@dynamic-labs/wallet-book": "4.0.0-alpha.27",
36
- "@dynamic-labs/wallet-connector-core": "4.0.0-alpha.27",
37
- "@dynamic-labs/webauthn": "4.0.0-alpha.27",
30
+ "@dynamic-labs/assert-package-version": "4.0.0-alpha.29",
31
+ "@dynamic-labs/embedded-wallet": "4.0.0-alpha.29",
32
+ "@dynamic-labs/rpc-providers": "4.0.0-alpha.29",
33
+ "@dynamic-labs/solana-core": "4.0.0-alpha.29",
34
+ "@dynamic-labs/wallet-book": "4.0.0-alpha.29",
35
+ "@dynamic-labs/wallet-connector-core": "4.0.0-alpha.29",
36
+ "@dynamic-labs/webauthn": "4.0.0-alpha.29",
38
37
  "react-dom": "18.2.0",
39
38
  "viem": "2.9.25"
40
39
  },
@@ -13,7 +13,6 @@ var utils = require('@dynamic-labs/utils');
13
13
  var solanaCore = require('@dynamic-labs/solana-core');
14
14
  var embeddedWallet = require('@dynamic-labs/embedded-wallet');
15
15
  var createSolanaConnection = require('../utils/createSolanaConnection/createSolanaConnection.cjs');
16
- var transactionDecoder = require('../utils/transactionDecoder/transactionDecoder.cjs');
17
16
  var api = require('../utils/api/api.cjs');
18
17
  var TurnkeySolanaSigner = require('./TurnkeySolanaSigner.cjs');
19
18
 
@@ -240,7 +239,7 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
240
239
  return utils.bufferToBase64(signedRawMessage);
241
240
  });
242
241
  }
243
- signTransaction(transaction) {
242
+ internalSignTransaction(transaction) {
244
243
  return _tslib.__awaiter(this, void 0, void 0, function* () {
245
244
  yield this.createOrRestoreSession();
246
245
  let account = yield this.getTurnkeyAccount();
@@ -268,7 +267,35 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
268
267
  return transaction;
269
268
  });
270
269
  }
271
- signAllTransactions(transactions) {
270
+ signTransaction(transaction) {
271
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
272
+ if (!this.turnkeyAddress)
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) {
272
299
  return _tslib.__awaiter(this, void 0, void 0, function* () {
273
300
  yield this.createOrRestoreSession();
274
301
  let account = yield this.getTurnkeyAccount();
@@ -297,13 +324,26 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
297
324
  }
298
325
  });
299
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
+ }
300
340
  internalSignAndSendTransaction(transaction, options) {
301
341
  return _tslib.__awaiter(this, void 0, void 0, function* () {
302
342
  var _a, _b;
303
343
  if (!this.turnkeyAddress)
304
344
  throw new utils.DynamicError('Solana wallet not found');
305
345
  const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
306
- const signedTransaction = yield this.signTransaction(transaction);
346
+ const signedTransaction = yield this.internalSignTransaction(transaction);
307
347
  const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
308
348
  // listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
309
349
  return new Promise((resolve, reject) => {
@@ -324,52 +364,15 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
324
364
  }
325
365
  signAndSendTransaction(transaction, options) {
326
366
  return _tslib.__awaiter(this, void 0, void 0, function* () {
327
- var _a;
328
367
  if (!this.turnkeyAddress)
329
368
  throw new utils.DynamicError('Solana wallet not found');
330
- let optimizedTransaction = transaction;
331
- let alreadySigned = false;
332
- if ('version' in transaction) {
333
- alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
334
- }
335
- else {
336
- alreadySigned = transaction.signatures.some((sig) => sig.signature);
337
- }
338
- try {
339
- // we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
340
- if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
341
- optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
342
- }
343
- }
344
- catch (e) {
345
- embeddedWallet.logger.warn('Failed to optimize transaction', e);
346
- }
347
- const transactionsData = yield transactionDecoder.decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
348
- if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
349
- throw new utils.DynamicError('Incorrectly formatted transaction instructions');
350
- }
351
- let spent;
352
- let insufficientFunds = false;
353
- try {
354
- spent = yield transactionDecoder.getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
355
- }
356
- catch (e) {
357
- if (e.message === 'Insufficient funds') {
358
- insufficientFunds = true;
359
- }
360
- }
361
- const to = transactionDecoder.summarizeTransactionDecodedData(transactionsData);
369
+ const optimizedTransaction = yield this.optimizeTransaction(transaction);
362
370
  const uiTransaction = new solanaCore.SolanaUiTransaction({
363
371
  connection: this.getConnection(),
364
372
  from: this.turnkeyAddress,
373
+ multipleTransactions: [optimizedTransaction],
365
374
  onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
366
- originalTransaction: optimizedTransaction,
367
375
  });
368
- uiTransaction.to = to;
369
- uiTransaction.value = spent;
370
- if (insufficientFunds) {
371
- uiTransaction.notEnoughFundsError = true;
372
- }
373
376
  // TODO: remove this. We should not be passing references to wallet connectors
374
377
  return this.walletUiUtils.sendTransaction(this, uiTransaction);
375
378
  });
@@ -412,16 +415,27 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
412
415
  lamportsToSol(lamports) {
413
416
  return lamports / web3_js.LAMPORTS_PER_SOL;
414
417
  }
415
- createUiTransaction(from) {
418
+ optimizeTransaction(transaction) {
416
419
  return _tslib.__awaiter(this, void 0, void 0, function* () {
417
- yield this.validateActiveWallet(from);
418
- const transaction = new solanaCore.SolanaUiTransaction({
419
- connection: this.getConnection(),
420
- from,
421
- onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
422
- });
423
- transaction.feeDeducted = true;
424
- 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;
425
439
  });
426
440
  }
427
441
  }
@@ -46,12 +46,15 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
46
46
  signUint8ArrayMessage(encodedMessage: Uint8Array): Promise<Uint8Array>;
47
47
  getEnvId: () => any;
48
48
  signMessage(messageToSign: string): Promise<string | undefined>;
49
+ internalSignTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
49
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[]>;
50
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>;
58
+ private optimizeTransaction;
56
59
  }
57
60
  export {};
@@ -9,7 +9,6 @@ import { DynamicError, bufferToBase64 } from '@dynamic-labs/utils';
9
9
  import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
10
10
  import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
11
11
  import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
12
- import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
13
12
  import { optimizeSolanaTransaction } from '../utils/api/api.js';
14
13
  import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
15
14
 
@@ -236,7 +235,7 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
236
235
  return bufferToBase64(signedRawMessage);
237
236
  });
238
237
  }
239
- signTransaction(transaction) {
238
+ internalSignTransaction(transaction) {
240
239
  return __awaiter(this, void 0, void 0, function* () {
241
240
  yield this.createOrRestoreSession();
242
241
  let account = yield this.getTurnkeyAccount();
@@ -264,7 +263,35 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
264
263
  return transaction;
265
264
  });
266
265
  }
267
- signAllTransactions(transactions) {
266
+ signTransaction(transaction) {
267
+ return __awaiter(this, void 0, void 0, function* () {
268
+ if (!this.turnkeyAddress)
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) {
268
295
  return __awaiter(this, void 0, void 0, function* () {
269
296
  yield this.createOrRestoreSession();
270
297
  let account = yield this.getTurnkeyAccount();
@@ -293,13 +320,26 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
293
320
  }
294
321
  });
295
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
+ }
296
336
  internalSignAndSendTransaction(transaction, options) {
297
337
  return __awaiter(this, void 0, void 0, function* () {
298
338
  var _a, _b;
299
339
  if (!this.turnkeyAddress)
300
340
  throw new DynamicError('Solana wallet not found');
301
341
  const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
302
- const signedTransaction = yield this.signTransaction(transaction);
342
+ const signedTransaction = yield this.internalSignTransaction(transaction);
303
343
  const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
304
344
  // listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
305
345
  return new Promise((resolve, reject) => {
@@ -320,52 +360,15 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
320
360
  }
321
361
  signAndSendTransaction(transaction, options) {
322
362
  return __awaiter(this, void 0, void 0, function* () {
323
- var _a;
324
363
  if (!this.turnkeyAddress)
325
364
  throw new DynamicError('Solana wallet not found');
326
- let optimizedTransaction = transaction;
327
- let alreadySigned = false;
328
- if ('version' in transaction) {
329
- alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
330
- }
331
- else {
332
- alreadySigned = transaction.signatures.some((sig) => sig.signature);
333
- }
334
- try {
335
- // we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
336
- if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
337
- optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
338
- }
339
- }
340
- catch (e) {
341
- logger.warn('Failed to optimize transaction', e);
342
- }
343
- const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
344
- if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
345
- throw new DynamicError('Incorrectly formatted transaction instructions');
346
- }
347
- let spent;
348
- let insufficientFunds = false;
349
- try {
350
- spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
351
- }
352
- catch (e) {
353
- if (e.message === 'Insufficient funds') {
354
- insufficientFunds = true;
355
- }
356
- }
357
- const to = summarizeTransactionDecodedData(transactionsData);
365
+ const optimizedTransaction = yield this.optimizeTransaction(transaction);
358
366
  const uiTransaction = new SolanaUiTransaction({
359
367
  connection: this.getConnection(),
360
368
  from: this.turnkeyAddress,
369
+ multipleTransactions: [optimizedTransaction],
361
370
  onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
362
- originalTransaction: optimizedTransaction,
363
371
  });
364
- uiTransaction.to = to;
365
- uiTransaction.value = spent;
366
- if (insufficientFunds) {
367
- uiTransaction.notEnoughFundsError = true;
368
- }
369
372
  // TODO: remove this. We should not be passing references to wallet connectors
370
373
  return this.walletUiUtils.sendTransaction(this, uiTransaction);
371
374
  });
@@ -408,16 +411,27 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
408
411
  lamportsToSol(lamports) {
409
412
  return lamports / LAMPORTS_PER_SOL;
410
413
  }
411
- createUiTransaction(from) {
414
+ optimizeTransaction(transaction) {
412
415
  return __awaiter(this, void 0, void 0, function* () {
413
- yield this.validateActiveWallet(from);
414
- const transaction = new SolanaUiTransaction({
415
- connection: this.getConnection(),
416
- from,
417
- onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
418
- });
419
- transaction.feeDeducted = true;
420
- 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;
421
435
  });
422
436
  }
423
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';
@@ -1,176 +0,0 @@
1
- 'use client'
2
- 'use strict';
3
-
4
- Object.defineProperty(exports, '__esModule', { value: true });
5
-
6
- var _tslib = require('../../../../_virtual/_tslib.cjs');
7
- var web3_js = require('@solana/web3.js');
8
- var splToken = require('@solana/spl-token');
9
- var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
10
- var utils = require('@dynamic-labs/utils');
11
-
12
- const getTotalSolanaSpend = (transaction, connection, thisAddress) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
13
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
14
- let simulation;
15
- let feePayer;
16
- if ('version' in transaction) {
17
- [feePayer] = transaction.message.staticAccountKeys;
18
- simulation = yield connection.simulateTransaction(transaction, {
19
- accounts: {
20
- addresses: feePayer.toBase58() && feePayer.toBase58() !== thisAddress
21
- ? [feePayer.toBase58(), thisAddress]
22
- : [thisAddress],
23
- encoding: 'base64',
24
- },
25
- replaceRecentBlockhash: true,
26
- });
27
- }
28
- else {
29
- feePayer =
30
- transaction.feePayer || transaction.instructions[0].keys[0].pubkey;
31
- simulation = yield connection.simulateTransaction(transaction, undefined, feePayer.toBase58() && feePayer.toBase58() !== thisAddress
32
- ? [feePayer, new web3_js.PublicKey(thisAddress)]
33
- : [new web3_js.PublicKey(thisAddress)]);
34
- }
35
- const previousBalance = yield connection.getBalance(new web3_js.PublicKey(thisAddress));
36
- if (!((_c = (_b = (_a = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _a === void 0 ? void 0 : _a.accounts) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.lamports)) {
37
- walletConnectorCore.logger.debug('Transaction simulation failed', simulation);
38
- const instructionError = JSON.stringify({
39
- InstructionError: [
40
- 0,
41
- {
42
- Custom: 1,
43
- },
44
- ],
45
- });
46
- const insufficientFundsForRent = JSON.stringify({
47
- InsufficientFundsForRent: {
48
- account_index: 0,
49
- },
50
- });
51
- if (JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === instructionError ||
52
- JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === insufficientFundsForRent) {
53
- throw new Error('Insufficient funds');
54
- }
55
- return undefined;
56
- }
57
- // the last account will be the embedded wallet,
58
- // if there are two addresses the first will be gas-sponsoring so we dont want to calculate sol for that
59
- const totalSolTransfer = previousBalance -
60
- ((_g = (_f = (_e = (_d = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _d === void 0 ? void 0 : _d.accounts) === null || _e === void 0 ? void 0 : _e[1]) === null || _f === void 0 ? void 0 : _f.lamports) !== null && _g !== void 0 ? _g : (_k = (_j = (_h = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _h === void 0 ? void 0 : _h.accounts) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.lamports);
61
- return BigInt(totalSolTransfer);
62
- });
63
- const decodeTransaction = (transaction, connection, thisAddress) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
64
- var _l;
65
- if (!transaction) {
66
- throw new utils.DynamicError('Transaction is required');
67
- }
68
- try {
69
- let decodedInstructions = [];
70
- if ('version' in transaction) {
71
- const lookupTableAddresses = transaction.message.addressTableLookups.map((lookup) => new web3_js.PublicKey(lookup.accountKey));
72
- // For non-simple SOL transfers, we need to fetch the lookup table accounts
73
- if (lookupTableAddresses.length > 0) {
74
- const lookupTables = yield Promise.all(lookupTableAddresses.map((address) => connection.getAddressLookupTable(address)));
75
- const lookupTableAccounts = lookupTables
76
- .filter((result) => result !== null)
77
- .map((result) => result.value);
78
- if (lookupTableAccounts.length > 0) {
79
- decodedInstructions = web3_js.TransactionMessage.decompile(transaction.message, {
80
- addressLookupTableAccounts: lookupTableAccounts,
81
- }).instructions;
82
- }
83
- }
84
- else {
85
- decodedInstructions = web3_js.TransactionMessage.decompile(transaction.message).instructions;
86
- }
87
- }
88
- else if (!transaction.instructions) {
89
- decodedInstructions = (_l = web3_js.Transaction.from(Buffer.from(transaction.serialize()))) === null || _l === void 0 ? void 0 : _l.instructions;
90
- }
91
- else {
92
- decodedInstructions = transaction.instructions;
93
- }
94
- if (!(decodedInstructions === null || decodedInstructions === void 0 ? void 0 : decodedInstructions.length)) {
95
- throw new utils.DynamicError('Bad formatted instruction');
96
- }
97
- const solTransfers = decodedInstructions.filter((instruction) => instruction.programId.equals(web3_js.SystemProgram.programId));
98
- // Non-SPL transfers, just SOL
99
- if (solTransfers.length > 0) {
100
- return solTransfers.map((decodedInstruction) => {
101
- let decodedTransferInstruction;
102
- try {
103
- decodedTransferInstruction =
104
- web3_js.SystemInstruction.decodeTransfer(decodedInstruction);
105
- }
106
- catch (e) {
107
- return { from: thisAddress, to: 'Unknown' };
108
- }
109
- return {
110
- from: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.fromPubkey.toBase58(),
111
- to: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.toPubkey.toBase58(),
112
- };
113
- });
114
- }
115
- // SPL transfers
116
- let splTransfers = yield Promise.all(decodedInstructions.map((instruction) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
117
- var _m, _o, _p, _q, _r, _s, _t;
118
- if (instruction.programId.equals(splToken.TOKEN_PROGRAM_ID)) {
119
- const decodedTokenInstruction = splToken.decodeTransferInstructionUnchecked(instruction);
120
- const { source, destination } = decodedTokenInstruction.keys;
121
- if (destination) {
122
- // For contract interactions, e.g., swaps, the destination is the turnkey address, flip sender and receiver
123
- if ((destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58()) === thisAddress) {
124
- return {
125
- from: thisAddress,
126
- to: source === null || source === void 0 ? void 0 : source.pubkey.toBase58(),
127
- };
128
- }
129
- // Pure SPL transfers, get the address from the destination token account to display to user
130
- const destinationAccountInfo = yield connection.getParsedAccountInfo(destination.pubkey);
131
- const isTokenAccount = ((_p = (_o = (_m = destinationAccountInfo.value) === null || _m === void 0 ? void 0 : _m.data) === null || _o === void 0 ? void 0 : _o.parsed) === null || _p === void 0 ? void 0 : _p.type) === 'account';
132
- const destinationOwner = isTokenAccount
133
- ? (_t = (_s = (_r = (_q = destinationAccountInfo.value) === null || _q === void 0 ? void 0 : _q.data) === null || _r === void 0 ? void 0 : _r.parsed) === null || _s === void 0 ? void 0 : _s.info) === null || _t === void 0 ? void 0 : _t.owner
134
- : null;
135
- const toAddress = destinationOwner
136
- ? destinationOwner
137
- : destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58();
138
- return {
139
- from: thisAddress,
140
- to: toAddress,
141
- };
142
- }
143
- }
144
- return null;
145
- })));
146
- splTransfers = splTransfers.filter((transfer) => transfer !== null);
147
- if (splTransfers === null || splTransfers === void 0 ? void 0 : splTransfers.length)
148
- return splTransfers;
149
- // Return program IDs for non-SOL and non-SPL transfers
150
- const noTransferDestinations = decodedInstructions.map((instruction) => ({
151
- from: thisAddress,
152
- to: instruction.programId.toBase58(),
153
- }));
154
- if (noTransferDestinations.length)
155
- return noTransferDestinations;
156
- return [{ from: thisAddress, to: 'Unknown' }];
157
- }
158
- catch (error) {
159
- walletConnectorCore.logger.warn('[decodeTransaction]', error);
160
- return [{ from: thisAddress, to: 'Unknown' }];
161
- }
162
- });
163
- const summarizeTransactionDecodedData = (transactionsData) => {
164
- const recipients = new Set();
165
- transactionsData.forEach((transactionData) => {
166
- if (transactionData && transactionData.to) {
167
- recipients.add(transactionData.to);
168
- }
169
- });
170
- const to = recipients.size === 1 ? recipients.values().next().value : 'Multiple';
171
- return to;
172
- };
173
-
174
- exports.decodeTransaction = decodeTransaction;
175
- exports.getTotalSolanaSpend = getTotalSolanaSpend;
176
- exports.summarizeTransactionDecodedData = summarizeTransactionDecodedData;
@@ -1,12 +0,0 @@
1
- import { Transaction, VersionedTransaction, Connection } from '@solana/web3.js';
2
- type DestinationAndFrom = {
3
- to: string;
4
- from: string;
5
- };
6
- export declare const getTotalSolanaSpend: (transaction: Transaction | VersionedTransaction, connection: Connection, thisAddress: string) => Promise<bigint | undefined>;
7
- export declare const decodeTransaction: (transaction: Transaction | VersionedTransaction, connection: Connection, thisAddress: string) => Promise<Array<DestinationAndFrom>>;
8
- export declare const summarizeTransactionDecodedData: (transactionsData: {
9
- to: string;
10
- from: string;
11
- }[]) => any;
12
- export {};
@@ -1,170 +0,0 @@
1
- 'use client'
2
- import { __awaiter } from '../../../../_virtual/_tslib.js';
3
- import { PublicKey, TransactionMessage, Transaction, SystemProgram, SystemInstruction } from '@solana/web3.js';
4
- import { TOKEN_PROGRAM_ID, decodeTransferInstructionUnchecked } from '@solana/spl-token';
5
- import { logger } from '@dynamic-labs/wallet-connector-core';
6
- import { DynamicError } from '@dynamic-labs/utils';
7
-
8
- const getTotalSolanaSpend = (transaction, connection, thisAddress) => __awaiter(void 0, void 0, void 0, function* () {
9
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
10
- let simulation;
11
- let feePayer;
12
- if ('version' in transaction) {
13
- [feePayer] = transaction.message.staticAccountKeys;
14
- simulation = yield connection.simulateTransaction(transaction, {
15
- accounts: {
16
- addresses: feePayer.toBase58() && feePayer.toBase58() !== thisAddress
17
- ? [feePayer.toBase58(), thisAddress]
18
- : [thisAddress],
19
- encoding: 'base64',
20
- },
21
- replaceRecentBlockhash: true,
22
- });
23
- }
24
- else {
25
- feePayer =
26
- transaction.feePayer || transaction.instructions[0].keys[0].pubkey;
27
- simulation = yield connection.simulateTransaction(transaction, undefined, feePayer.toBase58() && feePayer.toBase58() !== thisAddress
28
- ? [feePayer, new PublicKey(thisAddress)]
29
- : [new PublicKey(thisAddress)]);
30
- }
31
- const previousBalance = yield connection.getBalance(new PublicKey(thisAddress));
32
- if (!((_c = (_b = (_a = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _a === void 0 ? void 0 : _a.accounts) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.lamports)) {
33
- logger.debug('Transaction simulation failed', simulation);
34
- const instructionError = JSON.stringify({
35
- InstructionError: [
36
- 0,
37
- {
38
- Custom: 1,
39
- },
40
- ],
41
- });
42
- const insufficientFundsForRent = JSON.stringify({
43
- InsufficientFundsForRent: {
44
- account_index: 0,
45
- },
46
- });
47
- if (JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === instructionError ||
48
- JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === insufficientFundsForRent) {
49
- throw new Error('Insufficient funds');
50
- }
51
- return undefined;
52
- }
53
- // the last account will be the embedded wallet,
54
- // if there are two addresses the first will be gas-sponsoring so we dont want to calculate sol for that
55
- const totalSolTransfer = previousBalance -
56
- ((_g = (_f = (_e = (_d = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _d === void 0 ? void 0 : _d.accounts) === null || _e === void 0 ? void 0 : _e[1]) === null || _f === void 0 ? void 0 : _f.lamports) !== null && _g !== void 0 ? _g : (_k = (_j = (_h = simulation === null || simulation === void 0 ? void 0 : simulation.value) === null || _h === void 0 ? void 0 : _h.accounts) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.lamports);
57
- return BigInt(totalSolTransfer);
58
- });
59
- const decodeTransaction = (transaction, connection, thisAddress) => __awaiter(void 0, void 0, void 0, function* () {
60
- var _l;
61
- if (!transaction) {
62
- throw new DynamicError('Transaction is required');
63
- }
64
- try {
65
- let decodedInstructions = [];
66
- if ('version' in transaction) {
67
- const lookupTableAddresses = transaction.message.addressTableLookups.map((lookup) => new PublicKey(lookup.accountKey));
68
- // For non-simple SOL transfers, we need to fetch the lookup table accounts
69
- if (lookupTableAddresses.length > 0) {
70
- const lookupTables = yield Promise.all(lookupTableAddresses.map((address) => connection.getAddressLookupTable(address)));
71
- const lookupTableAccounts = lookupTables
72
- .filter((result) => result !== null)
73
- .map((result) => result.value);
74
- if (lookupTableAccounts.length > 0) {
75
- decodedInstructions = TransactionMessage.decompile(transaction.message, {
76
- addressLookupTableAccounts: lookupTableAccounts,
77
- }).instructions;
78
- }
79
- }
80
- else {
81
- decodedInstructions = TransactionMessage.decompile(transaction.message).instructions;
82
- }
83
- }
84
- else if (!transaction.instructions) {
85
- decodedInstructions = (_l = Transaction.from(Buffer.from(transaction.serialize()))) === null || _l === void 0 ? void 0 : _l.instructions;
86
- }
87
- else {
88
- decodedInstructions = transaction.instructions;
89
- }
90
- if (!(decodedInstructions === null || decodedInstructions === void 0 ? void 0 : decodedInstructions.length)) {
91
- throw new DynamicError('Bad formatted instruction');
92
- }
93
- const solTransfers = decodedInstructions.filter((instruction) => instruction.programId.equals(SystemProgram.programId));
94
- // Non-SPL transfers, just SOL
95
- if (solTransfers.length > 0) {
96
- return solTransfers.map((decodedInstruction) => {
97
- let decodedTransferInstruction;
98
- try {
99
- decodedTransferInstruction =
100
- SystemInstruction.decodeTransfer(decodedInstruction);
101
- }
102
- catch (e) {
103
- return { from: thisAddress, to: 'Unknown' };
104
- }
105
- return {
106
- from: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.fromPubkey.toBase58(),
107
- to: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.toPubkey.toBase58(),
108
- };
109
- });
110
- }
111
- // SPL transfers
112
- let splTransfers = yield Promise.all(decodedInstructions.map((instruction) => __awaiter(void 0, void 0, void 0, function* () {
113
- var _m, _o, _p, _q, _r, _s, _t;
114
- if (instruction.programId.equals(TOKEN_PROGRAM_ID)) {
115
- const decodedTokenInstruction = decodeTransferInstructionUnchecked(instruction);
116
- const { source, destination } = decodedTokenInstruction.keys;
117
- if (destination) {
118
- // For contract interactions, e.g., swaps, the destination is the turnkey address, flip sender and receiver
119
- if ((destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58()) === thisAddress) {
120
- return {
121
- from: thisAddress,
122
- to: source === null || source === void 0 ? void 0 : source.pubkey.toBase58(),
123
- };
124
- }
125
- // Pure SPL transfers, get the address from the destination token account to display to user
126
- const destinationAccountInfo = yield connection.getParsedAccountInfo(destination.pubkey);
127
- const isTokenAccount = ((_p = (_o = (_m = destinationAccountInfo.value) === null || _m === void 0 ? void 0 : _m.data) === null || _o === void 0 ? void 0 : _o.parsed) === null || _p === void 0 ? void 0 : _p.type) === 'account';
128
- const destinationOwner = isTokenAccount
129
- ? (_t = (_s = (_r = (_q = destinationAccountInfo.value) === null || _q === void 0 ? void 0 : _q.data) === null || _r === void 0 ? void 0 : _r.parsed) === null || _s === void 0 ? void 0 : _s.info) === null || _t === void 0 ? void 0 : _t.owner
130
- : null;
131
- const toAddress = destinationOwner
132
- ? destinationOwner
133
- : destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58();
134
- return {
135
- from: thisAddress,
136
- to: toAddress,
137
- };
138
- }
139
- }
140
- return null;
141
- })));
142
- splTransfers = splTransfers.filter((transfer) => transfer !== null);
143
- if (splTransfers === null || splTransfers === void 0 ? void 0 : splTransfers.length)
144
- return splTransfers;
145
- // Return program IDs for non-SOL and non-SPL transfers
146
- const noTransferDestinations = decodedInstructions.map((instruction) => ({
147
- from: thisAddress,
148
- to: instruction.programId.toBase58(),
149
- }));
150
- if (noTransferDestinations.length)
151
- return noTransferDestinations;
152
- return [{ from: thisAddress, to: 'Unknown' }];
153
- }
154
- catch (error) {
155
- logger.warn('[decodeTransaction]', error);
156
- return [{ from: thisAddress, to: 'Unknown' }];
157
- }
158
- });
159
- const summarizeTransactionDecodedData = (transactionsData) => {
160
- const recipients = new Set();
161
- transactionsData.forEach((transactionData) => {
162
- if (transactionData && transactionData.to) {
163
- recipients.add(transactionData.to);
164
- }
165
- });
166
- const to = recipients.size === 1 ? recipients.values().next().value : 'Multiple';
167
- return to;
168
- };
169
-
170
- export { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData };