@dynamic-labs/embedded-wallet-solana 3.5.1 → 3.6.1
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 +21 -0
- package/package.cjs +5 -6
- package/package.js +5 -6
- package/package.json +12 -13
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.cjs +66 -52
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.d.ts +4 -1
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.js +66 -52
- package/src/lib/utils/index.d.ts +0 -1
- package/src/lib/utils/transactionDecoder/index.d.ts +0 -1
- package/src/lib/utils/transactionDecoder/transactionDecoder.cjs +0 -176
- package/src/lib/utils/transactionDecoder/transactionDecoder.d.ts +0 -12
- package/src/lib/utils/transactionDecoder/transactionDecoder.js +0 -170
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
|
|
2
|
+
### [3.6.1](https://github.com/dynamic-labs/DynamicAuth/compare/v3.6.0...v3.6.1) (2024-11-08)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* when confirmation ui disabled for solana signall and signTransaction, it was returning a string instead of a transaction ([#7404](https://github.com/dynamic-labs/DynamicAuth/issues/7404)) ([9c17d83](https://github.com/dynamic-labs/DynamicAuth/commit/9c17d83e808f576bd319892b9726e5692534b31d))
|
|
8
|
+
* solana sign transaction was throwing with destination not found for embedded wallets ([#7394](https://github.com/dynamic-labs/DynamicAuth/issues/7394)) ([5bc21cd](https://github.com/dynamic-labs/DynamicAuth/commit/5bc21cdc2aee3dd70fc455e54e586d695392702b))
|
|
9
|
+
|
|
10
|
+
## [3.6.0](https://github.com/dynamic-labs/DynamicAuth/compare/v3.5.1...v3.6.0) (2024-11-07)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* Add a confirmation UI modal for signAllTransactions and signTransaction for Solana Embedded wallets. UI update to the embedded wallet confirmation UI modal.([#7381](https://github.com/dynamic-labs/DynamicAuth/issues/7381)) ([abac247](https://github.com/dynamic-labs/DynamicAuth/commit/abac247c53171dc05443ce20b4f152e5f25f27e5))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* confirmation modal popup after send balance flow ([#7382](https://github.com/dynamic-labs/DynamicAuth/issues/7382)) ([72d5848](https://github.com/dynamic-labs/DynamicAuth/commit/72d5848be2466879f2b3efbaf5c13885752513b0))
|
|
21
|
+
* network switch in global connectivity prevented publicClient call ([#7377](https://github.com/dynamic-labs/DynamicAuth/issues/7377)) ([a588497](https://github.com/dynamic-labs/DynamicAuth/commit/a5884978cbe3f875cef7560a004a0b127432ea9e))
|
|
22
|
+
|
|
2
23
|
### [3.5.1](https://github.com/dynamic-labs/DynamicAuth/compare/v3.5.0...v3.5.1) (2024-11-05)
|
|
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 = "3.
|
|
6
|
+
var version = "3.6.1";
|
|
7
7
|
var dependencies = {
|
|
8
|
-
"@dynamic-labs/sdk-api-core": "0.0.
|
|
9
|
-
"@dynamic-labs/utils": "3.
|
|
10
|
-
"@dynamic-labs/logger": "3.
|
|
11
|
-
"@dynamic-labs/types": "3.
|
|
8
|
+
"@dynamic-labs/sdk-api-core": "0.0.563",
|
|
9
|
+
"@dynamic-labs/utils": "3.6.1",
|
|
10
|
+
"@dynamic-labs/logger": "3.6.1",
|
|
11
|
+
"@dynamic-labs/types": "3.6.1",
|
|
12
12
|
eventemitter3: "5.0.1",
|
|
13
|
-
"@solana/spl-token": "0.4.6",
|
|
14
13
|
"@solana/web3.js": "1.92.1",
|
|
15
14
|
"@turnkey/http": "2.12.2",
|
|
16
15
|
"@turnkey/iframe-stamper": "2.0.0",
|
package/package.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
var version = "3.
|
|
2
|
+
var version = "3.6.1";
|
|
3
3
|
var dependencies = {
|
|
4
|
-
"@dynamic-labs/sdk-api-core": "0.0.
|
|
5
|
-
"@dynamic-labs/utils": "3.
|
|
6
|
-
"@dynamic-labs/logger": "3.
|
|
7
|
-
"@dynamic-labs/types": "3.
|
|
4
|
+
"@dynamic-labs/sdk-api-core": "0.0.563",
|
|
5
|
+
"@dynamic-labs/utils": "3.6.1",
|
|
6
|
+
"@dynamic-labs/logger": "3.6.1",
|
|
7
|
+
"@dynamic-labs/types": "3.6.1",
|
|
8
8
|
eventemitter3: "5.0.1",
|
|
9
|
-
"@solana/spl-token": "0.4.6",
|
|
10
9
|
"@solana/web3.js": "1.92.1",
|
|
11
10
|
"@turnkey/http": "2.12.2",
|
|
12
11
|
"@turnkey/iframe-stamper": "2.0.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/embedded-wallet-solana",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/dynamic-labs/dynamic-auth.git",
|
|
@@ -26,24 +26,23 @@
|
|
|
26
26
|
"./package.json": "./package.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@dynamic-labs/sdk-api-core": "0.0.
|
|
30
|
-
"@dynamic-labs/utils": "3.
|
|
31
|
-
"@dynamic-labs/logger": "3.
|
|
32
|
-
"@dynamic-labs/types": "3.
|
|
29
|
+
"@dynamic-labs/sdk-api-core": "0.0.563",
|
|
30
|
+
"@dynamic-labs/utils": "3.6.1",
|
|
31
|
+
"@dynamic-labs/logger": "3.6.1",
|
|
32
|
+
"@dynamic-labs/types": "3.6.1",
|
|
33
33
|
"eventemitter3": "5.0.1",
|
|
34
|
-
"@solana/spl-token": "0.4.6",
|
|
35
34
|
"@solana/web3.js": "1.92.1",
|
|
36
35
|
"@turnkey/http": "2.12.2",
|
|
37
36
|
"@turnkey/iframe-stamper": "2.0.0",
|
|
38
37
|
"@turnkey/solana": "0.3.9",
|
|
39
38
|
"@turnkey/webauthn-stamper": "0.5.0",
|
|
40
|
-
"@dynamic-labs/assert-package-version": "3.
|
|
41
|
-
"@dynamic-labs/embedded-wallet": "3.
|
|
42
|
-
"@dynamic-labs/rpc-providers": "3.
|
|
43
|
-
"@dynamic-labs/solana-core": "3.
|
|
44
|
-
"@dynamic-labs/wallet-book": "3.
|
|
45
|
-
"@dynamic-labs/wallet-connector-core": "3.
|
|
46
|
-
"@dynamic-labs/webauthn": "3.
|
|
39
|
+
"@dynamic-labs/assert-package-version": "3.6.1",
|
|
40
|
+
"@dynamic-labs/embedded-wallet": "3.6.1",
|
|
41
|
+
"@dynamic-labs/rpc-providers": "3.6.1",
|
|
42
|
+
"@dynamic-labs/solana-core": "3.6.1",
|
|
43
|
+
"@dynamic-labs/wallet-book": "3.6.1",
|
|
44
|
+
"@dynamic-labs/wallet-connector-core": "3.6.1",
|
|
45
|
+
"@dynamic-labs/webauthn": "3.6.1",
|
|
47
46
|
"react-dom": "18.2.0",
|
|
48
47
|
"viem": "2.9.25"
|
|
49
48
|
},
|
|
@@ -14,7 +14,6 @@ var solanaCore = require('@dynamic-labs/solana-core');
|
|
|
14
14
|
var utils = require('@dynamic-labs/utils');
|
|
15
15
|
var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
|
|
16
16
|
var createSolanaConnection = require('../utils/createSolanaConnection/createSolanaConnection.cjs');
|
|
17
|
-
var transactionDecoder = require('../utils/transactionDecoder/transactionDecoder.cjs');
|
|
18
17
|
var api = require('../utils/api/api.cjs');
|
|
19
18
|
var TurnkeySolanaSigner = require('./TurnkeySolanaSigner.cjs');
|
|
20
19
|
|
|
@@ -263,7 +262,7 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
263
262
|
return utils.bufferToBase64(signedRawMessage);
|
|
264
263
|
});
|
|
265
264
|
}
|
|
266
|
-
|
|
265
|
+
internalSignTransaction(transaction) {
|
|
267
266
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
268
267
|
yield this.createOrRestoreSession();
|
|
269
268
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -291,7 +290,35 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
291
290
|
return transaction;
|
|
292
291
|
});
|
|
293
292
|
}
|
|
294
|
-
|
|
293
|
+
signTransaction(transaction) {
|
|
294
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
295
|
+
if (!this.turnkeyAddress)
|
|
296
|
+
throw new utils.DynamicError('No turnkey account');
|
|
297
|
+
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
298
|
+
connection: this.getConnection(),
|
|
299
|
+
from: this.turnkeyAddress,
|
|
300
|
+
multipleTransactions: [transaction],
|
|
301
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
302
|
+
});
|
|
303
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
createUiTransaction(from) {
|
|
307
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
308
|
+
yield this.validateActiveWallet(from);
|
|
309
|
+
const transaction = new solanaCore.SolanaUiTransaction({
|
|
310
|
+
connection: this.getConnection(),
|
|
311
|
+
from,
|
|
312
|
+
onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
if (!transaction)
|
|
314
|
+
return undefined;
|
|
315
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
316
|
+
}),
|
|
317
|
+
});
|
|
318
|
+
return transaction;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
internalSignAllTransactions(transactions) {
|
|
295
322
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
296
323
|
yield this.createOrRestoreSession();
|
|
297
324
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -320,13 +347,26 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
320
347
|
}
|
|
321
348
|
});
|
|
322
349
|
}
|
|
350
|
+
signAllTransactions(transactions) {
|
|
351
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
352
|
+
if (!this.turnkeyAddress)
|
|
353
|
+
throw new utils.DynamicError('No turnkey account');
|
|
354
|
+
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
355
|
+
connection: this.getConnection(),
|
|
356
|
+
from: this.turnkeyAddress,
|
|
357
|
+
multipleTransactions: transactions,
|
|
358
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
359
|
+
});
|
|
360
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
323
363
|
internalSignAndSendTransaction(transaction, options) {
|
|
324
364
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
325
365
|
var _a, _b;
|
|
326
366
|
if (!this.turnkeyAddress)
|
|
327
367
|
throw new utils.DynamicError('Solana wallet not found');
|
|
328
368
|
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
329
|
-
const signedTransaction = yield this.
|
|
369
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
330
370
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
331
371
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
332
372
|
return new Promise((resolve, reject) => {
|
|
@@ -347,52 +387,15 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
347
387
|
}
|
|
348
388
|
signAndSendTransaction(transaction, options) {
|
|
349
389
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
350
|
-
var _a;
|
|
351
390
|
if (!this.turnkeyAddress)
|
|
352
391
|
throw new utils.DynamicError('Solana wallet not found');
|
|
353
|
-
|
|
354
|
-
let alreadySigned = false;
|
|
355
|
-
if ('version' in transaction) {
|
|
356
|
-
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
360
|
-
}
|
|
361
|
-
try {
|
|
362
|
-
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
363
|
-
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
364
|
-
optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
catch (e) {
|
|
368
|
-
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
369
|
-
}
|
|
370
|
-
const transactionsData = yield transactionDecoder.decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
371
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
372
|
-
throw new utils.DynamicError('Incorrectly formatted transaction instructions');
|
|
373
|
-
}
|
|
374
|
-
let spent;
|
|
375
|
-
let insufficientFunds = false;
|
|
376
|
-
try {
|
|
377
|
-
spent = yield transactionDecoder.getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
378
|
-
}
|
|
379
|
-
catch (e) {
|
|
380
|
-
if (e.message === 'Insufficient funds') {
|
|
381
|
-
insufficientFunds = true;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
const to = transactionDecoder.summarizeTransactionDecodedData(transactionsData);
|
|
392
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
385
393
|
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
386
394
|
connection: this.getConnection(),
|
|
387
395
|
from: this.turnkeyAddress,
|
|
396
|
+
multipleTransactions: [optimizedTransaction],
|
|
388
397
|
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
389
|
-
originalTransaction: optimizedTransaction,
|
|
390
398
|
});
|
|
391
|
-
uiTransaction.to = to;
|
|
392
|
-
uiTransaction.value = spent;
|
|
393
|
-
if (insufficientFunds) {
|
|
394
|
-
uiTransaction.notEnoughFundsError = true;
|
|
395
|
-
}
|
|
396
399
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
397
400
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
398
401
|
});
|
|
@@ -435,16 +438,27 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
435
438
|
lamportsToSol(lamports) {
|
|
436
439
|
return lamports / web3_js.LAMPORTS_PER_SOL;
|
|
437
440
|
}
|
|
438
|
-
|
|
441
|
+
optimizeTransaction(transaction) {
|
|
439
442
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
443
|
+
var _a;
|
|
444
|
+
let optimizedTransaction = transaction;
|
|
445
|
+
let alreadySigned = false;
|
|
446
|
+
if ('version' in transaction) {
|
|
447
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
454
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
455
|
+
optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch (e) {
|
|
459
|
+
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
460
|
+
}
|
|
461
|
+
return optimizedTransaction;
|
|
448
462
|
});
|
|
449
463
|
}
|
|
450
464
|
}
|
|
@@ -49,13 +49,16 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
|
|
|
49
49
|
signUint8ArrayMessage(encodedMessage: Uint8Array): Promise<Uint8Array>;
|
|
50
50
|
getEnvId: () => any;
|
|
51
51
|
signMessage(messageToSign: string): Promise<string | undefined>;
|
|
52
|
+
internalSignTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
|
|
52
53
|
signTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
|
|
54
|
+
createUiTransaction(from: string): Promise<IUITransaction>;
|
|
55
|
+
internalSignAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
|
|
53
56
|
signAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
|
|
54
57
|
internalSignAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
55
58
|
signAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
56
59
|
sendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendTransactionOptions): Promise<string>;
|
|
57
60
|
private lamportsToSol;
|
|
58
|
-
|
|
61
|
+
private optimizeTransaction;
|
|
59
62
|
stampCreateWalletAccountRequest: ({ request, }: {
|
|
60
63
|
request: TurnkeyApiTypes['v1CreateWalletAccountsRequest'];
|
|
61
64
|
}) => Promise<import("@turnkey/http").TSignedRequest>;
|
|
@@ -10,7 +10,6 @@ import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction }
|
|
|
10
10
|
import { DynamicError, getTLD, PlatformService, bufferToBase64 } from '@dynamic-labs/utils';
|
|
11
11
|
import { isSameAddress } from '@dynamic-labs/wallet-connector-core';
|
|
12
12
|
import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
|
|
13
|
-
import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
|
|
14
13
|
import { optimizeSolanaTransaction } from '../utils/api/api.js';
|
|
15
14
|
import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
|
|
16
15
|
|
|
@@ -259,7 +258,7 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
259
258
|
return bufferToBase64(signedRawMessage);
|
|
260
259
|
});
|
|
261
260
|
}
|
|
262
|
-
|
|
261
|
+
internalSignTransaction(transaction) {
|
|
263
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
264
263
|
yield this.createOrRestoreSession();
|
|
265
264
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -287,7 +286,35 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
287
286
|
return transaction;
|
|
288
287
|
});
|
|
289
288
|
}
|
|
290
|
-
|
|
289
|
+
signTransaction(transaction) {
|
|
290
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
291
|
+
if (!this.turnkeyAddress)
|
|
292
|
+
throw new DynamicError('No turnkey account');
|
|
293
|
+
const uiTransaction = new SolanaUiTransaction({
|
|
294
|
+
connection: this.getConnection(),
|
|
295
|
+
from: this.turnkeyAddress,
|
|
296
|
+
multipleTransactions: [transaction],
|
|
297
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
298
|
+
});
|
|
299
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
createUiTransaction(from) {
|
|
303
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
304
|
+
yield this.validateActiveWallet(from);
|
|
305
|
+
const transaction = new SolanaUiTransaction({
|
|
306
|
+
connection: this.getConnection(),
|
|
307
|
+
from,
|
|
308
|
+
onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () {
|
|
309
|
+
if (!transaction)
|
|
310
|
+
return undefined;
|
|
311
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
312
|
+
}),
|
|
313
|
+
});
|
|
314
|
+
return transaction;
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
internalSignAllTransactions(transactions) {
|
|
291
318
|
return __awaiter(this, void 0, void 0, function* () {
|
|
292
319
|
yield this.createOrRestoreSession();
|
|
293
320
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -316,13 +343,26 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
316
343
|
}
|
|
317
344
|
});
|
|
318
345
|
}
|
|
346
|
+
signAllTransactions(transactions) {
|
|
347
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
348
|
+
if (!this.turnkeyAddress)
|
|
349
|
+
throw new DynamicError('No turnkey account');
|
|
350
|
+
const uiTransaction = new SolanaUiTransaction({
|
|
351
|
+
connection: this.getConnection(),
|
|
352
|
+
from: this.turnkeyAddress,
|
|
353
|
+
multipleTransactions: transactions,
|
|
354
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
355
|
+
});
|
|
356
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
319
359
|
internalSignAndSendTransaction(transaction, options) {
|
|
320
360
|
return __awaiter(this, void 0, void 0, function* () {
|
|
321
361
|
var _a, _b;
|
|
322
362
|
if (!this.turnkeyAddress)
|
|
323
363
|
throw new DynamicError('Solana wallet not found');
|
|
324
364
|
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
325
|
-
const signedTransaction = yield this.
|
|
365
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
326
366
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
327
367
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
328
368
|
return new Promise((resolve, reject) => {
|
|
@@ -343,52 +383,15 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
343
383
|
}
|
|
344
384
|
signAndSendTransaction(transaction, options) {
|
|
345
385
|
return __awaiter(this, void 0, void 0, function* () {
|
|
346
|
-
var _a;
|
|
347
386
|
if (!this.turnkeyAddress)
|
|
348
387
|
throw new DynamicError('Solana wallet not found');
|
|
349
|
-
|
|
350
|
-
let alreadySigned = false;
|
|
351
|
-
if ('version' in transaction) {
|
|
352
|
-
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
356
|
-
}
|
|
357
|
-
try {
|
|
358
|
-
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
359
|
-
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
360
|
-
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
logger.warn('Failed to optimize transaction', e);
|
|
365
|
-
}
|
|
366
|
-
const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
367
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
368
|
-
throw new DynamicError('Incorrectly formatted transaction instructions');
|
|
369
|
-
}
|
|
370
|
-
let spent;
|
|
371
|
-
let insufficientFunds = false;
|
|
372
|
-
try {
|
|
373
|
-
spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
374
|
-
}
|
|
375
|
-
catch (e) {
|
|
376
|
-
if (e.message === 'Insufficient funds') {
|
|
377
|
-
insufficientFunds = true;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
const to = summarizeTransactionDecodedData(transactionsData);
|
|
388
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
381
389
|
const uiTransaction = new SolanaUiTransaction({
|
|
382
390
|
connection: this.getConnection(),
|
|
383
391
|
from: this.turnkeyAddress,
|
|
392
|
+
multipleTransactions: [optimizedTransaction],
|
|
384
393
|
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
385
|
-
originalTransaction: optimizedTransaction,
|
|
386
394
|
});
|
|
387
|
-
uiTransaction.to = to;
|
|
388
|
-
uiTransaction.value = spent;
|
|
389
|
-
if (insufficientFunds) {
|
|
390
|
-
uiTransaction.notEnoughFundsError = true;
|
|
391
|
-
}
|
|
392
395
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
393
396
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
394
397
|
});
|
|
@@ -431,16 +434,27 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
431
434
|
lamportsToSol(lamports) {
|
|
432
435
|
return lamports / LAMPORTS_PER_SOL;
|
|
433
436
|
}
|
|
434
|
-
|
|
437
|
+
optimizeTransaction(transaction) {
|
|
435
438
|
return __awaiter(this, void 0, void 0, function* () {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
|
|
439
|
+
var _a;
|
|
440
|
+
let optimizedTransaction = transaction;
|
|
441
|
+
let alreadySigned = false;
|
|
442
|
+
if ('version' in transaction) {
|
|
443
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
450
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
451
|
+
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
catch (e) {
|
|
455
|
+
logger.warn('Failed to optimize transaction', e);
|
|
456
|
+
}
|
|
457
|
+
return optimizedTransaction;
|
|
444
458
|
});
|
|
445
459
|
}
|
|
446
460
|
}
|
package/src/lib/utils/index.d.ts
CHANGED
|
@@ -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 };
|