@dynamic-labs/embedded-wallet-solana 4.0.0-alpha.26 → 4.0.0-alpha.28
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 +33 -0
- package/package.cjs +4 -5
- package/package.js +4 -5
- package/package.json +11 -12
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.cjs +72 -55
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.d.ts +6 -1
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.js +72 -55
- 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,37 @@
|
|
|
1
1
|
|
|
2
|
+
## [4.0.0-alpha.28](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.27...v4.0.0-alpha.28) (2024-11-07)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### ⚠ BREAKING CHANGES
|
|
6
|
+
|
|
7
|
+
* upgrade to starknet v6
|
|
8
|
+
See this guide for more details: https://starknetjs.com/docs/guides/migrate/
|
|
9
|
+
There are no code changes required on the Dynamic SDK side, however if you have installed the `starknet` package, you will need to upgrade to >= v6.11.0.
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* new transaction modal and ui for sign/signAll ([#7296](https://github.com/dynamic-labs/dynamic-auth/issues/7296)) ([05a8af1](https://github.com/dynamic-labs/dynamic-auth/commit/05a8af1eb772b2b8087ed96a54caf4b6ae8b79d2)), closes [#7297](https://github.com/dynamic-labs/dynamic-auth/issues/7297) [#7298](https://github.com/dynamic-labs/dynamic-auth/issues/7298)
|
|
14
|
+
* upgrade to starknet v6 ([#7189](https://github.com/dynamic-labs/dynamic-auth/issues/7189)) ([2a6e24e](https://github.com/dynamic-labs/dynamic-auth/commit/2a6e24e4178fcee671b381c28f6a681f4ce52c62))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* transaction confirmation modal popup ([#7368](https://github.com/dynamic-labs/dynamic-auth/issues/7368)) ([3c48658](https://github.com/dynamic-labs/dynamic-auth/commit/3c48658a62874d908bba8f06fb092ff5983ede16))
|
|
20
|
+
|
|
21
|
+
## [4.0.0-alpha.27](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.26...v4.0.0-alpha.27) (2024-11-06)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* allows adding connection configuration for solana connectors ([#7354](https://github.com/dynamic-labs/dynamic-auth/issues/7354)) ([01e35ee](https://github.com/dynamic-labs/dynamic-auth/commit/01e35ee5bfe4605df48e4188a753111efe483048))
|
|
27
|
+
* allows passing solana connection config to dynamic client ([#7357](https://github.com/dynamic-labs/dynamic-auth/issues/7357)) ([6da14ce](https://github.com/dynamic-labs/dynamic-auth/commit/6da14ceb481147aea31d192fe268be43a8af80e9))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
* check legacy vs eip1599 tx in global connectivity ([#7341](https://github.com/dynamic-labs/dynamic-auth/issues/7341)) ([b223ea7](https://github.com/dynamic-labs/dynamic-auth/commit/b223ea7a5ed5637e11da1040c631c48bc23ba76d))
|
|
33
|
+
* global connectivity multiple transactions in a row ([#7342](https://github.com/dynamic-labs/dynamic-auth/issues/7342)) ([d13c1af](https://github.com/dynamic-labs/dynamic-auth/commit/d13c1afec6b3680961621d8317f55549b3ed428f))
|
|
34
|
+
|
|
2
35
|
## [4.0.0-alpha.26](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.25...v4.0.0-alpha.26) (2024-11-04)
|
|
3
36
|
|
|
4
37
|
## [4.0.0-alpha.25](https://github.com/dynamic-labs/dynamic-auth/compare/v4.0.0-alpha.24...v4.0.0-alpha.25) (2024-11-01)
|
package/package.cjs
CHANGED
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
5
|
|
|
6
|
-
var version = "4.0.0-alpha.
|
|
6
|
+
var version = "4.0.0-alpha.28";
|
|
7
7
|
var dependencies = {
|
|
8
|
-
"@dynamic-labs/utils": "4.0.0-alpha.
|
|
9
|
-
"@dynamic-labs/logger": "4.0.0-alpha.
|
|
10
|
-
"@dynamic-labs/types": "4.0.0-alpha.
|
|
8
|
+
"@dynamic-labs/utils": "4.0.0-alpha.28",
|
|
9
|
+
"@dynamic-labs/logger": "4.0.0-alpha.28",
|
|
10
|
+
"@dynamic-labs/types": "4.0.0-alpha.28",
|
|
11
11
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
12
12
|
eventemitter3: "5.0.1",
|
|
13
|
-
"@solana/spl-token": "0.4.6",
|
|
14
13
|
"@solana/web3.js": "1.92.1",
|
|
15
14
|
"@turnkey/iframe-stamper": "2.0.0",
|
|
16
15
|
"@turnkey/solana": "1.0.1",
|
package/package.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
var version = "4.0.0-alpha.
|
|
2
|
+
var version = "4.0.0-alpha.28";
|
|
3
3
|
var dependencies = {
|
|
4
|
-
"@dynamic-labs/utils": "4.0.0-alpha.
|
|
5
|
-
"@dynamic-labs/logger": "4.0.0-alpha.
|
|
6
|
-
"@dynamic-labs/types": "4.0.0-alpha.
|
|
4
|
+
"@dynamic-labs/utils": "4.0.0-alpha.28",
|
|
5
|
+
"@dynamic-labs/logger": "4.0.0-alpha.28",
|
|
6
|
+
"@dynamic-labs/types": "4.0.0-alpha.28",
|
|
7
7
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
8
8
|
eventemitter3: "5.0.1",
|
|
9
|
-
"@solana/spl-token": "0.4.6",
|
|
10
9
|
"@solana/web3.js": "1.92.1",
|
|
11
10
|
"@turnkey/iframe-stamper": "2.0.0",
|
|
12
11
|
"@turnkey/solana": "1.0.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/embedded-wallet-solana",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.28",
|
|
4
4
|
"description": "A React SDK for implementing wallet web3 authentication and authorization to your website.",
|
|
5
5
|
"author": "Dynamic Labs, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,23 +18,22 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://www.dynamic.xyz/",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@dynamic-labs/utils": "4.0.0-alpha.
|
|
22
|
-
"@dynamic-labs/logger": "4.0.0-alpha.
|
|
23
|
-
"@dynamic-labs/types": "4.0.0-alpha.
|
|
21
|
+
"@dynamic-labs/utils": "4.0.0-alpha.28",
|
|
22
|
+
"@dynamic-labs/logger": "4.0.0-alpha.28",
|
|
23
|
+
"@dynamic-labs/types": "4.0.0-alpha.28",
|
|
24
24
|
"@dynamic-labs/sdk-api-core": "0.0.559",
|
|
25
25
|
"eventemitter3": "5.0.1",
|
|
26
|
-
"@solana/spl-token": "0.4.6",
|
|
27
26
|
"@solana/web3.js": "1.92.1",
|
|
28
27
|
"@turnkey/iframe-stamper": "2.0.0",
|
|
29
28
|
"@turnkey/solana": "1.0.1",
|
|
30
29
|
"@turnkey/webauthn-stamper": "0.5.0",
|
|
31
|
-
"@dynamic-labs/assert-package-version": "4.0.0-alpha.
|
|
32
|
-
"@dynamic-labs/embedded-wallet": "4.0.0-alpha.
|
|
33
|
-
"@dynamic-labs/rpc-providers": "4.0.0-alpha.
|
|
34
|
-
"@dynamic-labs/solana-core": "4.0.0-alpha.
|
|
35
|
-
"@dynamic-labs/wallet-book": "4.0.0-alpha.
|
|
36
|
-
"@dynamic-labs/wallet-connector-core": "4.0.0-alpha.
|
|
37
|
-
"@dynamic-labs/webauthn": "4.0.0-alpha.
|
|
30
|
+
"@dynamic-labs/assert-package-version": "4.0.0-alpha.28",
|
|
31
|
+
"@dynamic-labs/embedded-wallet": "4.0.0-alpha.28",
|
|
32
|
+
"@dynamic-labs/rpc-providers": "4.0.0-alpha.28",
|
|
33
|
+
"@dynamic-labs/solana-core": "4.0.0-alpha.28",
|
|
34
|
+
"@dynamic-labs/wallet-book": "4.0.0-alpha.28",
|
|
35
|
+
"@dynamic-labs/wallet-connector-core": "4.0.0-alpha.28",
|
|
36
|
+
"@dynamic-labs/webauthn": "4.0.0-alpha.28",
|
|
38
37
|
"react-dom": "18.2.0",
|
|
39
38
|
"viem": "2.9.25"
|
|
40
39
|
},
|
|
@@ -13,7 +13,6 @@ var utils = require('@dynamic-labs/utils');
|
|
|
13
13
|
var solanaCore = require('@dynamic-labs/solana-core');
|
|
14
14
|
var embeddedWallet = require('@dynamic-labs/embedded-wallet');
|
|
15
15
|
var createSolanaConnection = require('../utils/createSolanaConnection/createSolanaConnection.cjs');
|
|
16
|
-
var transactionDecoder = require('../utils/transactionDecoder/transactionDecoder.cjs');
|
|
17
16
|
var api = require('../utils/api/api.cjs');
|
|
18
17
|
var TurnkeySolanaSigner = require('./TurnkeySolanaSigner.cjs');
|
|
19
18
|
|
|
@@ -47,8 +46,9 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
47
46
|
this.walletUiUtils = props.walletUiUtils;
|
|
48
47
|
this._turnkeyAccount = undefined;
|
|
49
48
|
this._connectionClient = undefined;
|
|
49
|
+
this.connectionConfig = props.connectionConfig;
|
|
50
50
|
this.chainRpcProviders = props.chainRpcProviders;
|
|
51
|
-
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders();
|
|
51
|
+
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
|
|
52
52
|
this.__turnkeyClient = this.getTurnkeyClient();
|
|
53
53
|
}
|
|
54
54
|
getRpcUrl() {
|
|
@@ -64,7 +64,9 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
64
64
|
const rpcUrl = this.getRpcUrl();
|
|
65
65
|
if (!rpcUrl)
|
|
66
66
|
throw new utils.DynamicError('No rpcUrl');
|
|
67
|
-
|
|
67
|
+
const config = typeof commitmentOrConfig === 'string'
|
|
68
|
+
? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
|
|
69
|
+
this._connectionClient = createSolanaConnection.createSolanaConnection(rpcUrl, config);
|
|
68
70
|
}
|
|
69
71
|
return this._connectionClient;
|
|
70
72
|
}
|
|
@@ -237,7 +239,7 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
237
239
|
return utils.bufferToBase64(signedRawMessage);
|
|
238
240
|
});
|
|
239
241
|
}
|
|
240
|
-
|
|
242
|
+
internalSignTransaction(transaction) {
|
|
241
243
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
242
244
|
yield this.createOrRestoreSession();
|
|
243
245
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -265,7 +267,34 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
265
267
|
return transaction;
|
|
266
268
|
});
|
|
267
269
|
}
|
|
268
|
-
|
|
270
|
+
signTransaction(transaction) {
|
|
271
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
272
|
+
if (!this.turnkeyAddress)
|
|
273
|
+
throw new utils.DynamicError('No turnkey account');
|
|
274
|
+
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
275
|
+
connection: this.getConnection(),
|
|
276
|
+
from: this.turnkeyAddress,
|
|
277
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
278
|
+
});
|
|
279
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
createUiTransaction(from) {
|
|
283
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
284
|
+
yield this.validateActiveWallet(from);
|
|
285
|
+
const transaction = new solanaCore.SolanaUiTransaction({
|
|
286
|
+
connection: this.getConnection(),
|
|
287
|
+
from,
|
|
288
|
+
onSubmit: (transaction) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
289
|
+
if (!transaction)
|
|
290
|
+
return undefined;
|
|
291
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
292
|
+
}),
|
|
293
|
+
});
|
|
294
|
+
return transaction;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
internalSignAllTransactions(transactions) {
|
|
269
298
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
270
299
|
yield this.createOrRestoreSession();
|
|
271
300
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -294,12 +323,26 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
294
323
|
}
|
|
295
324
|
});
|
|
296
325
|
}
|
|
326
|
+
signAllTransactions(transactions) {
|
|
327
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
328
|
+
if (!this.turnkeyAddress)
|
|
329
|
+
throw new utils.DynamicError('No turnkey account');
|
|
330
|
+
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
331
|
+
connection: this.getConnection(),
|
|
332
|
+
from: this.turnkeyAddress,
|
|
333
|
+
multipleTransactions: transactions,
|
|
334
|
+
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
335
|
+
});
|
|
336
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
297
339
|
internalSignAndSendTransaction(transaction, options) {
|
|
298
340
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
341
|
+
var _a, _b;
|
|
299
342
|
if (!this.turnkeyAddress)
|
|
300
343
|
throw new utils.DynamicError('Solana wallet not found');
|
|
301
|
-
const currentConnection = this.getConnection('confirmed');
|
|
302
|
-
const signedTransaction = yield this.
|
|
344
|
+
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
345
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
303
346
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
304
347
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
305
348
|
return new Promise((resolve, reject) => {
|
|
@@ -320,52 +363,15 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
320
363
|
}
|
|
321
364
|
signAndSendTransaction(transaction, options) {
|
|
322
365
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
323
|
-
var _a;
|
|
324
366
|
if (!this.turnkeyAddress)
|
|
325
367
|
throw new utils.DynamicError('Solana wallet not found');
|
|
326
|
-
|
|
327
|
-
let alreadySigned = false;
|
|
328
|
-
if ('version' in transaction) {
|
|
329
|
-
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
333
|
-
}
|
|
334
|
-
try {
|
|
335
|
-
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
336
|
-
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
337
|
-
optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
catch (e) {
|
|
341
|
-
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
342
|
-
}
|
|
343
|
-
const transactionsData = yield transactionDecoder.decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
344
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
345
|
-
throw new utils.DynamicError('Incorrectly formatted transaction instructions');
|
|
346
|
-
}
|
|
347
|
-
let spent;
|
|
348
|
-
let insufficientFunds = false;
|
|
349
|
-
try {
|
|
350
|
-
spent = yield transactionDecoder.getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
351
|
-
}
|
|
352
|
-
catch (e) {
|
|
353
|
-
if (e.message === 'Insufficient funds') {
|
|
354
|
-
insufficientFunds = true;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
const to = transactionDecoder.summarizeTransactionDecodedData(transactionsData);
|
|
368
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
358
369
|
const uiTransaction = new solanaCore.SolanaUiTransaction({
|
|
359
370
|
connection: this.getConnection(),
|
|
360
371
|
from: this.turnkeyAddress,
|
|
372
|
+
multipleTransactions: [optimizedTransaction],
|
|
361
373
|
onSubmit: () => _tslib.__awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
362
|
-
originalTransaction: optimizedTransaction,
|
|
363
374
|
});
|
|
364
|
-
uiTransaction.to = to;
|
|
365
|
-
uiTransaction.value = spent;
|
|
366
|
-
if (insufficientFunds) {
|
|
367
|
-
uiTransaction.notEnoughFundsError = true;
|
|
368
|
-
}
|
|
369
375
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
370
376
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
371
377
|
});
|
|
@@ -408,16 +414,27 @@ class TurnkeySolanaWalletConnector extends embeddedWallet.TurnkeyWalletConnector
|
|
|
408
414
|
lamportsToSol(lamports) {
|
|
409
415
|
return lamports / web3_js.LAMPORTS_PER_SOL;
|
|
410
416
|
}
|
|
411
|
-
|
|
417
|
+
optimizeTransaction(transaction) {
|
|
412
418
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
|
|
419
|
+
var _a;
|
|
420
|
+
let optimizedTransaction = transaction;
|
|
421
|
+
let alreadySigned = false;
|
|
422
|
+
if ('version' in transaction) {
|
|
423
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
430
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
431
|
+
optimizedTransaction = (yield api.optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
catch (e) {
|
|
435
|
+
embeddedWallet.logger.warn('Failed to optimize transaction', e);
|
|
436
|
+
}
|
|
437
|
+
return optimizedTransaction;
|
|
421
438
|
});
|
|
422
439
|
}
|
|
423
440
|
}
|
|
@@ -15,6 +15,7 @@ export type TurnkeySolanaConnectorProps = {
|
|
|
15
15
|
solNetworks: GenericNetwork[];
|
|
16
16
|
appName?: string;
|
|
17
17
|
chainRpcProviders: IChainRpcProviders;
|
|
18
|
+
connectionConfig?: ConnectionConfig;
|
|
18
19
|
};
|
|
19
20
|
export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase implements ISendBalanceWalletConnector {
|
|
20
21
|
ChainWallet: typeof SolanaWallet;
|
|
@@ -25,6 +26,7 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
|
|
|
25
26
|
private walletUiUtils;
|
|
26
27
|
private _turnkeyAccount;
|
|
27
28
|
private _connectionClient;
|
|
29
|
+
private connectionConfig;
|
|
28
30
|
constructor(nameAndKey: TurnkeyWalletConnectorNameAndKey, props: TurnkeySolanaConnectorProps);
|
|
29
31
|
getRpcUrl(): string;
|
|
30
32
|
getConnection(commitmentOrConfig?: Commitment | ConnectionConfig): Connection;
|
|
@@ -44,12 +46,15 @@ export declare class TurnkeySolanaWalletConnector extends TurnkeyWalletConnector
|
|
|
44
46
|
signUint8ArrayMessage(encodedMessage: Uint8Array): Promise<Uint8Array>;
|
|
45
47
|
getEnvId: () => any;
|
|
46
48
|
signMessage(messageToSign: string): Promise<string | undefined>;
|
|
49
|
+
internalSignTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
|
|
47
50
|
signTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T>;
|
|
51
|
+
createUiTransaction(from: string): Promise<IUITransaction>;
|
|
52
|
+
internalSignAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
|
|
48
53
|
signAllTransactions<T extends Transaction | VersionedTransaction>(transactions: T[]): Promise<T[]>;
|
|
49
54
|
internalSignAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
50
55
|
signAndSendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, options?: SendOptions): Promise<string>;
|
|
51
56
|
sendTransaction<T extends Transaction | VersionedTransaction>(transaction: T, connection: Connection, options?: SendTransactionOptions): Promise<string>;
|
|
52
57
|
private lamportsToSol;
|
|
53
|
-
|
|
58
|
+
private optimizeTransaction;
|
|
54
59
|
}
|
|
55
60
|
export {};
|
|
@@ -9,7 +9,6 @@ import { DynamicError, bufferToBase64 } from '@dynamic-labs/utils';
|
|
|
9
9
|
import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
|
|
10
10
|
import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
|
|
11
11
|
import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
|
|
12
|
-
import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
|
|
13
12
|
import { optimizeSolanaTransaction } from '../utils/api/api.js';
|
|
14
13
|
import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
|
|
15
14
|
|
|
@@ -43,8 +42,9 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
43
42
|
this.walletUiUtils = props.walletUiUtils;
|
|
44
43
|
this._turnkeyAccount = undefined;
|
|
45
44
|
this._connectionClient = undefined;
|
|
45
|
+
this.connectionConfig = props.connectionConfig;
|
|
46
46
|
this.chainRpcProviders = props.chainRpcProviders;
|
|
47
|
-
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders();
|
|
47
|
+
(_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders(this.connectionConfig);
|
|
48
48
|
this.__turnkeyClient = this.getTurnkeyClient();
|
|
49
49
|
}
|
|
50
50
|
getRpcUrl() {
|
|
@@ -60,7 +60,9 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
60
60
|
const rpcUrl = this.getRpcUrl();
|
|
61
61
|
if (!rpcUrl)
|
|
62
62
|
throw new DynamicError('No rpcUrl');
|
|
63
|
-
|
|
63
|
+
const config = typeof commitmentOrConfig === 'string'
|
|
64
|
+
? Object.assign(Object.assign({}, this.connectionConfig), { commitment: commitmentOrConfig }) : Object.assign(Object.assign({}, this.connectionConfig), commitmentOrConfig);
|
|
65
|
+
this._connectionClient = createSolanaConnection(rpcUrl, config);
|
|
64
66
|
}
|
|
65
67
|
return this._connectionClient;
|
|
66
68
|
}
|
|
@@ -233,7 +235,7 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
233
235
|
return bufferToBase64(signedRawMessage);
|
|
234
236
|
});
|
|
235
237
|
}
|
|
236
|
-
|
|
238
|
+
internalSignTransaction(transaction) {
|
|
237
239
|
return __awaiter(this, void 0, void 0, function* () {
|
|
238
240
|
yield this.createOrRestoreSession();
|
|
239
241
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -261,7 +263,34 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
261
263
|
return transaction;
|
|
262
264
|
});
|
|
263
265
|
}
|
|
264
|
-
|
|
266
|
+
signTransaction(transaction) {
|
|
267
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
268
|
+
if (!this.turnkeyAddress)
|
|
269
|
+
throw new DynamicError('No turnkey account');
|
|
270
|
+
const uiTransaction = new SolanaUiTransaction({
|
|
271
|
+
connection: this.getConnection(),
|
|
272
|
+
from: this.turnkeyAddress,
|
|
273
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignTransaction(transaction); }),
|
|
274
|
+
});
|
|
275
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
createUiTransaction(from) {
|
|
279
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
280
|
+
yield this.validateActiveWallet(from);
|
|
281
|
+
const transaction = new SolanaUiTransaction({
|
|
282
|
+
connection: this.getConnection(),
|
|
283
|
+
from,
|
|
284
|
+
onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () {
|
|
285
|
+
if (!transaction)
|
|
286
|
+
return undefined;
|
|
287
|
+
return this.internalSignAndSendTransaction(transaction);
|
|
288
|
+
}),
|
|
289
|
+
});
|
|
290
|
+
return transaction;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
internalSignAllTransactions(transactions) {
|
|
265
294
|
return __awaiter(this, void 0, void 0, function* () {
|
|
266
295
|
yield this.createOrRestoreSession();
|
|
267
296
|
let account = yield this.getTurnkeyAccount();
|
|
@@ -290,12 +319,26 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
290
319
|
}
|
|
291
320
|
});
|
|
292
321
|
}
|
|
322
|
+
signAllTransactions(transactions) {
|
|
323
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
if (!this.turnkeyAddress)
|
|
325
|
+
throw new DynamicError('No turnkey account');
|
|
326
|
+
const uiTransaction = new SolanaUiTransaction({
|
|
327
|
+
connection: this.getConnection(),
|
|
328
|
+
from: this.turnkeyAddress,
|
|
329
|
+
multipleTransactions: transactions,
|
|
330
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAllTransactions(transactions); }),
|
|
331
|
+
});
|
|
332
|
+
return this.walletUiUtils.signTransaction(this, uiTransaction);
|
|
333
|
+
});
|
|
334
|
+
}
|
|
293
335
|
internalSignAndSendTransaction(transaction, options) {
|
|
294
336
|
return __awaiter(this, void 0, void 0, function* () {
|
|
337
|
+
var _a, _b;
|
|
295
338
|
if (!this.turnkeyAddress)
|
|
296
339
|
throw new DynamicError('Solana wallet not found');
|
|
297
|
-
const currentConnection = this.getConnection('confirmed');
|
|
298
|
-
const signedTransaction = yield this.
|
|
340
|
+
const currentConnection = this.getConnection((_b = (_a = this.connectionConfig) === null || _a === void 0 ? void 0 : _a.commitment) !== null && _b !== void 0 ? _b : 'confirmed');
|
|
341
|
+
const signedTransaction = yield this.internalSignTransaction(transaction);
|
|
299
342
|
const signature = yield currentConnection.sendRawTransaction(signedTransaction.serialize(), options);
|
|
300
343
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
301
344
|
return new Promise((resolve, reject) => {
|
|
@@ -316,52 +359,15 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
316
359
|
}
|
|
317
360
|
signAndSendTransaction(transaction, options) {
|
|
318
361
|
return __awaiter(this, void 0, void 0, function* () {
|
|
319
|
-
var _a;
|
|
320
362
|
if (!this.turnkeyAddress)
|
|
321
363
|
throw new DynamicError('Solana wallet not found');
|
|
322
|
-
|
|
323
|
-
let alreadySigned = false;
|
|
324
|
-
if ('version' in transaction) {
|
|
325
|
-
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
332
|
-
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
333
|
-
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
catch (e) {
|
|
337
|
-
logger.warn('Failed to optimize transaction', e);
|
|
338
|
-
}
|
|
339
|
-
const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
340
|
-
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
341
|
-
throw new DynamicError('Incorrectly formatted transaction instructions');
|
|
342
|
-
}
|
|
343
|
-
let spent;
|
|
344
|
-
let insufficientFunds = false;
|
|
345
|
-
try {
|
|
346
|
-
spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
347
|
-
}
|
|
348
|
-
catch (e) {
|
|
349
|
-
if (e.message === 'Insufficient funds') {
|
|
350
|
-
insufficientFunds = true;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
const to = summarizeTransactionDecodedData(transactionsData);
|
|
364
|
+
const optimizedTransaction = yield this.optimizeTransaction(transaction);
|
|
354
365
|
const uiTransaction = new SolanaUiTransaction({
|
|
355
366
|
connection: this.getConnection(),
|
|
356
367
|
from: this.turnkeyAddress,
|
|
368
|
+
multipleTransactions: [optimizedTransaction],
|
|
357
369
|
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
358
|
-
originalTransaction: optimizedTransaction,
|
|
359
370
|
});
|
|
360
|
-
uiTransaction.to = to;
|
|
361
|
-
uiTransaction.value = spent;
|
|
362
|
-
if (insufficientFunds) {
|
|
363
|
-
uiTransaction.notEnoughFundsError = true;
|
|
364
|
-
}
|
|
365
371
|
// TODO: remove this. We should not be passing references to wallet connectors
|
|
366
372
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
367
373
|
});
|
|
@@ -404,16 +410,27 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
404
410
|
lamportsToSol(lamports) {
|
|
405
411
|
return lamports / LAMPORTS_PER_SOL;
|
|
406
412
|
}
|
|
407
|
-
|
|
413
|
+
optimizeTransaction(transaction) {
|
|
408
414
|
return __awaiter(this, void 0, void 0, function* () {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
var _a;
|
|
416
|
+
let optimizedTransaction = transaction;
|
|
417
|
+
let alreadySigned = false;
|
|
418
|
+
if ('version' in transaction) {
|
|
419
|
+
alreadySigned = transaction.signatures.some((sig) => !sig.every((byte) => byte === 0));
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
alreadySigned = transaction.signatures.some((sig) => sig.signature);
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
// we cannot optimize partially signed transactions as once a tx is modified the signatures are no longer valid
|
|
426
|
+
if ((yield this.getNetwork()) === 'mainnet' && !alreadySigned) {
|
|
427
|
+
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
catch (e) {
|
|
431
|
+
logger.warn('Failed to optimize transaction', e);
|
|
432
|
+
}
|
|
433
|
+
return optimizedTransaction;
|
|
417
434
|
});
|
|
418
435
|
}
|
|
419
436
|
}
|
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 };
|