@dynamic-labs/embedded-wallet-solana 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/package.cjs +4 -5
- package/package.js +4 -5
- package/package.json +11 -12
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.cjs +77 -60
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.d.ts +11 -6
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.js +77 -60
- 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,24 @@
|
|
|
1
1
|
|
|
2
|
+
## [3.6.0](https://github.com/dynamic-labs/DynamicAuth/compare/v3.5.1...v3.6.0) (2024-11-07)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* 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))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* 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))
|
|
13
|
+
* 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))
|
|
14
|
+
|
|
15
|
+
### [3.5.1](https://github.com/dynamic-labs/DynamicAuth/compare/v3.5.0...v3.5.1) (2024-11-05)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* allow passing connection config to solana wallet connectors ([#7364](https://github.com/dynamic-labs/DynamicAuth/issues/7364)) ([5dd5176](https://github.com/dynamic-labs/DynamicAuth/commit/5dd5176e6f91d9771ce1d1af031ab1adb25f5b74))
|
|
21
|
+
|
|
2
22
|
## [3.5.0](https://github.com/dynamic-labs/DynamicAuth/compare/v3.4.6...v3.5.0) (2024-11-05)
|
|
3
23
|
|
|
4
24
|
|
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.0";
|
|
7
7
|
var dependencies = {
|
|
8
8
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
9
|
-
"@dynamic-labs/utils": "3.
|
|
10
|
-
"@dynamic-labs/logger": "3.
|
|
11
|
-
"@dynamic-labs/types": "3.
|
|
9
|
+
"@dynamic-labs/utils": "3.6.0",
|
|
10
|
+
"@dynamic-labs/logger": "3.6.0",
|
|
11
|
+
"@dynamic-labs/types": "3.6.0",
|
|
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.0";
|
|
3
3
|
var dependencies = {
|
|
4
4
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
5
|
-
"@dynamic-labs/utils": "3.
|
|
6
|
-
"@dynamic-labs/logger": "3.
|
|
7
|
-
"@dynamic-labs/types": "3.
|
|
5
|
+
"@dynamic-labs/utils": "3.6.0",
|
|
6
|
+
"@dynamic-labs/logger": "3.6.0",
|
|
7
|
+
"@dynamic-labs/types": "3.6.0",
|
|
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.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/dynamic-labs/dynamic-auth.git",
|
|
@@ -27,23 +27,22 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
30
|
-
"@dynamic-labs/utils": "3.
|
|
31
|
-
"@dynamic-labs/logger": "3.
|
|
32
|
-
"@dynamic-labs/types": "3.
|
|
30
|
+
"@dynamic-labs/utils": "3.6.0",
|
|
31
|
+
"@dynamic-labs/logger": "3.6.0",
|
|
32
|
+
"@dynamic-labs/types": "3.6.0",
|
|
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.0",
|
|
40
|
+
"@dynamic-labs/embedded-wallet": "3.6.0",
|
|
41
|
+
"@dynamic-labs/rpc-providers": "3.6.0",
|
|
42
|
+
"@dynamic-labs/solana-core": "3.6.0",
|
|
43
|
+
"@dynamic-labs/wallet-book": "3.6.0",
|
|
44
|
+
"@dynamic-labs/wallet-connector-core": "3.6.0",
|
|
45
|
+
"@dynamic-labs/webauthn": "3.6.0",
|
|
47
46
|
"react-dom": "18.2.0",
|
|
48
47
|
"viem": "2.9.25"
|
|
49
48
|
},
|
|
@@ -5,16 +5,15 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
|
|
6
6
|
var _tslib = require('../../../_virtual/_tslib.cjs');
|
|
7
7
|
var web3_js = require('@solana/web3.js');
|
|
8
|
-
var webauthnStamper = require('@turnkey/webauthn-stamper');
|
|
9
8
|
var http = require('@turnkey/http');
|
|
10
|
-
var solana = require('@turnkey/solana');
|
|
11
9
|
var iframeStamper = require('@turnkey/iframe-stamper');
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
var solanaCore = require('@dynamic-labs/solana-core');
|
|
10
|
+
var solana = require('@turnkey/solana');
|
|
11
|
+
var webauthnStamper = require('@turnkey/webauthn-stamper');
|
|
15
12
|
var embeddedWallet = require('@dynamic-labs/embedded-wallet');
|
|
13
|
+
var solanaCore = require('@dynamic-labs/solana-core');
|
|
14
|
+
var utils = require('@dynamic-labs/utils');
|
|
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
|
|
|
@@ -54,7 +53,8 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
54
53
|
this._turnkeyAccount = undefined;
|
|
55
54
|
this._connectionClient = undefined;
|
|
56
55
|
this.chainRpcProviders = props.chainRpcProviders;
|
|
57
|
-
|
|
56
|
+
this.connectionConfig = props.connectionConfig;
|
|
57
|
+
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
|
|
58
58
|
this.__turnkeyClient = this.getTurnkeyClient();
|
|
59
59
|
}
|
|
60
60
|
getRpcUrl() {
|
|
@@ -70,7 +70,9 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
70
70
|
const rpcUrl = this.getRpcUrl();
|
|
71
71
|
if (!rpcUrl)
|
|
72
72
|
throw new utils.DynamicError('No rpcUrl');
|
|
73
|
-
|
|
73
|
+
const config = typeof commitmentOrConfig === 'string'
|
|
74
|
+
? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
|
|
75
|
+
this._connectionClient = createSolanaConnection.createSolanaConnection(rpcUrl, config);
|
|
74
76
|
}
|
|
75
77
|
return this._connectionClient;
|
|
76
78
|
}
|
|
@@ -260,7 +262,7 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
260
262
|
return utils.bufferToBase64(signedRawMessage);
|
|
261
263
|
});
|
|
262
264
|
}
|
|
263
|
-
|
|
265
|
+
internalSignTransaction(transaction) {
|
|
264
266
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
265
267
|
yield this.createOrRestoreSession();
|
|
266
268
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -288,7 +290,34 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
288
290
|
return transaction;
|
|
289
291
|
});
|
|
290
292
|
}
|
|
291
|
-
|
|
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
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
301
|
+
});
|
|
302
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
createUiTransaction(from) {
|
|
306
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
307
|
+
yield this.validateActiveWallet(from);
|
|
308
|
+
const transaction = new solanaCore.SolanaUiTransaction({
|
|
309
|
+
connection: this.getConnection(),
|
|
310
|
+
from,
|
|
311
|
+
onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
312
|
+
if (!transaction)
|
|
313
|
+
return undefined;
|
|
314
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
315
|
+
}),
|
|
316
|
+
});
|
|
317
|
+
return transaction;
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
internalSignAllTransactions(transactions) {
|
|
292
321
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
293
322
|
yield this.createOrRestoreSession();
|
|
294
323
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -317,12 +346,26 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
317
346
|
}
|
|
318
347
|
});
|
|
319
348
|
}
|
|
349
|
+
signAllTransactions(transactions) {
|
|
350
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
351
|
+
if (!this.turnkeyAddress)
|
|
352
|
+
throw new utils.DynamicError('No turnkey account');
|
|
353
|
+
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
354
|
+
connection: this.getConnection(),
|
|
355
|
+
from: this.turnkeyAddress,
|
|
356
|
+
multipleTransactions: transactions,
|
|
357
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
358
|
+
});
|
|
359
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
320
362
|
internalSignAndSendTransaction(transaction, options) {
|
|
321
363
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
364
|
+
var _a, _b;
|
|
322
365
|
if (!this.turnkeyAddress)
|
|
323
366
|
throw new utils.DynamicError('Solana wallet not found');
|
|
324
|
-
const currentConnection = this.getConnection('confirmed');
|
|
325
|
-
const signedTransaction = yield this.
|
|
367
|
+
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
368
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
326
369
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
327
370
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
328
371
|
return new Promise((resolve, reject) => {
|
|
@@ -343,52 +386,15 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
343
386
|
}
|
|
344
387
|
signAndSendTransaction(transaction, options) {
|
|
345
388
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
346
|
-
var _a;
|
|
347
389
|
if (!this.turnkeyAddress)
|
|
348
390
|
throw new utils.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 api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
365
|
-
}
|
|
366
|
-
const transactionsData = yield transactionDecoder.decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
367
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
368
|
-
throw new utils.DynamicError('Incorrectly formatted transaction instructions');
|
|
369
|
-
}
|
|
370
|
-
let spent;
|
|
371
|
-
let insufficientFunds = false;
|
|
372
|
-
try {
|
|
373
|
-
spent = yield transactionDecoder.getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
374
|
-
}
|
|
375
|
-
catch (e) {
|
|
376
|
-
if (e.message === 'Insufficient funds') {
|
|
377
|
-
insufficientFunds = true;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
const to = transactionDecoder.summarizeTransactionDecodedData(transactionsData);
|
|
391
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
381
392
|
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
382
393
|
connection: this.getConnection(),
|
|
383
394
|
from: this.turnkeyAddress,
|
|
395
|
+
multipleTransactions: [optimizedTransaction],
|
|
384
396
|
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
385
|
-
originalTransaction: optimizedTransaction,
|
|
386
397
|
});
|
|
387
|
-
uiTransaction.to = to;
|
|
388
|
-
uiTransaction.value = spent;
|
|
389
|
-
if (insufficientFunds) {
|
|
390
|
-
uiTransaction.notEnoughFundsError = true;
|
|
391
|
-
}
|
|
392
398
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
393
399
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
394
400
|
});
|
|
@@ -431,16 +437,27 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
431
437
|
lamportsToSol(lamports) {
|
|
432
438
|
return lamports / web3_js.LAMPORTS_PER_SOL;
|
|
433
439
|
}
|
|
434
|
-
|
|
440
|
+
optimizeTransaction(transaction) {
|
|
435
441
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
|
|
442
|
+
var _a;
|
|
443
|
+
let optimizedTransaction = transaction;
|
|
444
|
+
let alreadySigned = false;
|
|
445
|
+
if ('version' in transaction) {
|
|
446
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
453
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
454
|
+
optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
catch (e) {
|
|
458
|
+
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
459
|
+
}
|
|
460
|
+
return optimizedTransaction;
|
|
444
461
|
});
|
|
445
462
|
}
|
|
446
463
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Commitment, Connection, ConnectionConfig,
|
|
1
|
+
import { Commitment, ConfirmOptions, Connection, ConnectionConfig, SendOptions, Signer, Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
2
2
|
import { TurnkeyApiTypes } from '@turnkey/http';
|
|
3
|
-
import {
|
|
4
|
-
import { Chain, ISendBalanceWalletConnector, InternalWalletConnector } from '@dynamic-labs/wallet-connector-core';
|
|
5
|
-
import { WalletBookSchema } from '@dynamic-labs/wallet-book';
|
|
3
|
+
import { TurnkeyWalletConnectorBase, TurnkeyWalletConnectorNameAndKey } from '@dynamic-labs/embedded-wallet';
|
|
6
4
|
import { JwtVerifiedCredential } from '@dynamic-labs/sdk-api-core';
|
|
7
5
|
import { IChainRpcProviders, SolanaWallet } from '@dynamic-labs/solana-core';
|
|
8
|
-
import {
|
|
6
|
+
import { GenericNetwork, IUITransaction, WalletUiUtils } from '@dynamic-labs/types';
|
|
7
|
+
import { WalletBookSchema } from '@dynamic-labs/wallet-book';
|
|
8
|
+
import { Chain, InternalWalletConnector, ISendBalanceWalletConnector } from '@dynamic-labs/wallet-connector-core';
|
|
9
9
|
import { TurnkeySolanaSigner } from './TurnkeySolanaSigner';
|
|
10
10
|
type SendTransactionOptions = ConfirmOptions & {
|
|
11
11
|
signers?: Signer[];
|
|
@@ -16,6 +16,7 @@ export type TurnkeySolanaConnectorProps = {
|
|
|
16
16
|
solNetworks: GenericNetwork[];
|
|
17
17
|
appName?: string;
|
|
18
18
|
chainRpcProviders: IChainRpcProviders;
|
|
19
|
+
connectionConfig?: ConnectionConfig;
|
|
19
20
|
};
|
|
20
21
|
export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase implements ISendBalanceWalletConnector {
|
|
21
22
|
ChainWallet: typeof SolanaWallet;
|
|
@@ -27,6 +28,7 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
|
|
|
27
28
|
private _turnkeyAccount;
|
|
28
29
|
private _connectionClient;
|
|
29
30
|
private __turnkeyClient;
|
|
31
|
+
private connectionConfig;
|
|
30
32
|
constructor(nameAndKey: TurnkeyWalletConnectorNameAndKey, props: TurnkeySolanaConnectorProps);
|
|
31
33
|
getRpcUrl(): string;
|
|
32
34
|
getConnection(commitmentOrConfig?: Commitment | ConnectionConfig): Connection;
|
|
@@ -47,13 +49,16 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
|
|
|
47
49
|
signUint8ArrayMessage(encodedMessage: Uint8Array): Promise<Uint8Array>;
|
|
48
50
|
getEnvId: () => any;
|
|
49
51
|
signMessage(messageToSign: string): Promise<string | undefined>;
|
|
52
|
+
internalSignTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
|
|
50
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[]>;
|
|
51
56
|
signAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
|
|
52
57
|
internalSignAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
53
58
|
signAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
54
59
|
sendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendTransactionOptions): Promise<string>;
|
|
55
60
|
private lamportsToSol;
|
|
56
|
-
|
|
61
|
+
private optimizeTransaction;
|
|
57
62
|
stampCreateWalletAccountRequest: ({ request, }: {
|
|
58
63
|
request: TurnkeyApiTypes['v1CreateWalletAccountsRequest'];
|
|
59
64
|
}) => Promise<import("@turnkey/http").TSignedRequest>;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import { __awaiter, __rest } from '../../../_virtual/_tslib.js';
|
|
3
3
|
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
|
|
4
|
-
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
|
5
4
|
import { TurnkeyClient } from '@turnkey/http';
|
|
6
|
-
import { TurnkeySigner } from '@turnkey/solana';
|
|
7
5
|
import { IframeStamper } from '@turnkey/iframe-stamper';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
|
|
6
|
+
import { TurnkeySigner } from '@turnkey/solana';
|
|
7
|
+
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
|
11
8
|
import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, PasskeyService, TURNKEY_API_BASE_URL, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
|
|
9
|
+
import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
|
|
10
|
+
import { DynamicError, getTLD, PlatformService, bufferToBase64 } from '@dynamic-labs/utils';
|
|
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
|
|
|
@@ -50,7 +49,8 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
50
49
|
this._turnkeyAccount = undefined;
|
|
51
50
|
this._connectionClient = undefined;
|
|
52
51
|
this.chainRpcProviders = props.chainRpcProviders;
|
|
53
|
-
|
|
52
|
+
this.connectionConfig = props.connectionConfig;
|
|
53
|
+
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
|
|
54
54
|
this.__turnkeyClient = this.getTurnkeyClient();
|
|
55
55
|
}
|
|
56
56
|
getRpcUrl() {
|
|
@@ -66,7 +66,9 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
66
66
|
const rpcUrl = this.getRpcUrl();
|
|
67
67
|
if (!rpcUrl)
|
|
68
68
|
throw new DynamicError('No rpcUrl');
|
|
69
|
-
|
|
69
|
+
const config = typeof commitmentOrConfig === 'string'
|
|
70
|
+
? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
|
|
71
|
+
this._connectionClient = createSolanaConnection(rpcUrl, config);
|
|
70
72
|
}
|
|
71
73
|
return this._connectionClient;
|
|
72
74
|
}
|
|
@@ -256,7 +258,7 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
256
258
|
return bufferToBase64(signedRawMessage);
|
|
257
259
|
});
|
|
258
260
|
}
|
|
259
|
-
|
|
261
|
+
internalSignTransaction(transaction) {
|
|
260
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
261
263
|
yield this.createOrRestoreSession();
|
|
262
264
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -284,7 +286,34 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
284
286
|
return transaction;
|
|
285
287
|
});
|
|
286
288
|
}
|
|
287
|
-
|
|
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
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
297
|
+
});
|
|
298
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
createUiTransaction(from) {
|
|
302
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
303
|
+
yield this.validateActiveWallet(from);
|
|
304
|
+
const transaction = new SolanaUiTransaction({
|
|
305
|
+
connection: this.getConnection(),
|
|
306
|
+
from,
|
|
307
|
+
onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () {
|
|
308
|
+
if (!transaction)
|
|
309
|
+
return undefined;
|
|
310
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
311
|
+
}),
|
|
312
|
+
});
|
|
313
|
+
return transaction;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
internalSignAllTransactions(transactions) {
|
|
288
317
|
return __awaiter(this, void 0, void 0, function* () {
|
|
289
318
|
yield this.createOrRestoreSession();
|
|
290
319
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -313,12 +342,26 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
313
342
|
}
|
|
314
343
|
});
|
|
315
344
|
}
|
|
345
|
+
signAllTransactions(transactions) {
|
|
346
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
347
|
+
if (!this.turnkeyAddress)
|
|
348
|
+
throw new DynamicError('No turnkey account');
|
|
349
|
+
const uiTransaction = new SolanaUiTransaction({
|
|
350
|
+
connection: this.getConnection(),
|
|
351
|
+
from: this.turnkeyAddress,
|
|
352
|
+
multipleTransactions: transactions,
|
|
353
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
354
|
+
});
|
|
355
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
316
358
|
internalSignAndSendTransaction(transaction, options) {
|
|
317
359
|
return __awaiter(this, void 0, void 0, function* () {
|
|
360
|
+
var _a, _b;
|
|
318
361
|
if (!this.turnkeyAddress)
|
|
319
362
|
throw new DynamicError('Solana wallet not found');
|
|
320
|
-
const currentConnection = this.getConnection('confirmed');
|
|
321
|
-
const signedTransaction = yield this.
|
|
363
|
+
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
364
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
322
365
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
323
366
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
324
367
|
return new Promise((resolve, reject) => {
|
|
@@ -339,52 +382,15 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
339
382
|
}
|
|
340
383
|
signAndSendTransaction(transaction, options) {
|
|
341
384
|
return __awaiter(this, void 0, void 0, function* () {
|
|
342
|
-
var _a;
|
|
343
385
|
if (!this.turnkeyAddress)
|
|
344
386
|
throw new DynamicError('Solana wallet not found');
|
|
345
|
-
|
|
346
|
-
let alreadySigned = false;
|
|
347
|
-
if ('version' in transaction) {
|
|
348
|
-
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
352
|
-
}
|
|
353
|
-
try {
|
|
354
|
-
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
355
|
-
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
356
|
-
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
catch (e) {
|
|
360
|
-
logger.warn('Failed to optimize transaction', e);
|
|
361
|
-
}
|
|
362
|
-
const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
363
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
364
|
-
throw new DynamicError('Incorrectly formatted transaction instructions');
|
|
365
|
-
}
|
|
366
|
-
let spent;
|
|
367
|
-
let insufficientFunds = false;
|
|
368
|
-
try {
|
|
369
|
-
spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
370
|
-
}
|
|
371
|
-
catch (e) {
|
|
372
|
-
if (e.message === 'Insufficient funds') {
|
|
373
|
-
insufficientFunds = true;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
const to = summarizeTransactionDecodedData(transactionsData);
|
|
387
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
377
388
|
const uiTransaction = new SolanaUiTransaction({
|
|
378
389
|
connection: this.getConnection(),
|
|
379
390
|
from: this.turnkeyAddress,
|
|
391
|
+
multipleTransactions: [optimizedTransaction],
|
|
380
392
|
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
381
|
-
originalTransaction: optimizedTransaction,
|
|
382
393
|
});
|
|
383
|
-
uiTransaction.to = to;
|
|
384
|
-
uiTransaction.value = spent;
|
|
385
|
-
if (insufficientFunds) {
|
|
386
|
-
uiTransaction.notEnoughFundsError = true;
|
|
387
|
-
}
|
|
388
394
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
389
395
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
390
396
|
});
|
|
@@ -427,16 +433,27 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
427
433
|
lamportsToSol(lamports) {
|
|
428
434
|
return lamports / LAMPORTS_PER_SOL;
|
|
429
435
|
}
|
|
430
|
-
|
|
436
|
+
optimizeTransaction(transaction) {
|
|
431
437
|
return __awaiter(this, void 0, void 0, function* () {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
|
|
438
|
+
var _a;
|
|
439
|
+
let optimizedTransaction = transaction;
|
|
440
|
+
let alreadySigned = false;
|
|
441
|
+
if ('version' in transaction) {
|
|
442
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
449
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
450
|
+
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
catch (e) {
|
|
454
|
+
logger.warn('Failed to optimize transaction', e);
|
|
455
|
+
}
|
|
456
|
+
return optimizedTransaction;
|
|
440
457
|
});
|
|
441
458
|
}
|
|
442
459
|
}
|
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 };
|