@dynamic-labs/embedded-wallet-solana 3.0.0-alpha.10

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +3504 -0
  2. package/LICENSE +21 -0
  3. package/README.md +11 -0
  4. package/_virtual/_tslib.cjs +49 -0
  5. package/_virtual/_tslib.js +44 -0
  6. package/package.json +47 -0
  7. package/src/TurnkeySolanaWalletConnectors.cjs +19 -0
  8. package/src/TurnkeySolanaWalletConnectors.d.ts +2 -0
  9. package/src/TurnkeySolanaWalletConnectors.js +15 -0
  10. package/src/index.cjs +10 -0
  11. package/src/index.d.ts +2 -0
  12. package/src/index.js +2 -0
  13. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.cjs +60 -0
  14. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.d.ts +45 -0
  15. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.js +56 -0
  16. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.cjs +336 -0
  17. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.d.ts +55 -0
  18. package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.js +332 -0
  19. package/src/lib/TurnkeySolanaWalletConnector/index.d.ts +1 -0
  20. package/src/lib/constants.cjs +8 -0
  21. package/src/lib/constants.d.ts +1 -0
  22. package/src/lib/constants.js +4 -0
  23. package/src/lib/utils/createSolanaConnection/createSolanaConnection.cjs +14 -0
  24. package/src/lib/utils/createSolanaConnection/createSolanaConnection.d.ts +2 -0
  25. package/src/lib/utils/createSolanaConnection/createSolanaConnection.js +10 -0
  26. package/src/lib/utils/createSolanaConnection/index.d.ts +1 -0
  27. package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.cjs +10 -0
  28. package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.d.ts +1 -0
  29. package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.js +6 -0
  30. package/src/lib/utils/getGenesisHashLSKey/index.d.ts +1 -0
  31. package/src/lib/utils/index.d.ts +3 -0
  32. package/src/lib/utils/transactionDecoder/index.d.ts +1 -0
  33. package/src/lib/utils/transactionDecoder/transactionDecoder.cjs +140 -0
  34. package/src/lib/utils/transactionDecoder/transactionDecoder.d.ts +7 -0
  35. package/src/lib/utils/transactionDecoder/transactionDecoder.js +134 -0
@@ -0,0 +1,332 @@
1
+ 'use client'
2
+ import { __awaiter, __rest } from '../../../_virtual/_tslib.js';
3
+ import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
4
+ import { WebauthnStamper } from '@turnkey/webauthn-stamper';
5
+ import { TurnkeyClient } from '@turnkey/http';
6
+ import { TurnkeySigner } from '@turnkey/solana';
7
+ import { IframeStamper } from '@turnkey/iframe-stamper';
8
+ import { ProviderChain } from '@dynamic-labs/rpc-provider-solana';
9
+ import { DynamicError, getTLD, PlatformService, bufferToBase64 } from '@dynamic-labs/utils';
10
+ import { SolanaUiTransaction } from '@dynamic-labs/solana-utils';
11
+ import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredential, PasskeyService, TURNKEY_API_BASE_URL } from '@dynamic-labs/embedded-wallet';
12
+ import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
13
+ import { getGenesisHashLSKey } from '../utils/getGenesisHashLSKey/getGenesisHashLSKey.js';
14
+ import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
15
+ import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
16
+
17
+ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
18
+ constructor(nameAndKey, props) {
19
+ var _a;
20
+ super(nameAndKey, props);
21
+ // Public fields
22
+ this.connectedChain = 'SOL';
23
+ this.supportedChains = ['SOL'];
24
+ this.verifiedCredentialChain = 'solana';
25
+ this.solNetworks = props.solNetworks;
26
+ this.walletUiUtils = props.walletUiUtils;
27
+ this._turnkeyAccount = undefined;
28
+ this._connectionClient = undefined;
29
+ this.chainRpcProviders = props.chainRpcProviders;
30
+ (_a = this.chainRpcProviders) === null || _a === void 0 ? void 0 : _a.registerSolanaProviders();
31
+ this.__turnkeyClient = this.getTurnkeyClient();
32
+ }
33
+ getRpcUrl() {
34
+ var _a;
35
+ const [network] = this.solNetworks;
36
+ if (!network) {
37
+ throw new DynamicError('No enabled networks');
38
+ }
39
+ return ((_a = network.privateCustomerRpcUrls) === null || _a === void 0 ? void 0 : _a[0]) || network.rpcUrls[0];
40
+ }
41
+ getConnection(commitmentOrConfig) {
42
+ if (!this._connectionClient) {
43
+ const rpcUrl = this.getRpcUrl();
44
+ if (!rpcUrl)
45
+ throw new DynamicError('No rpcUrl');
46
+ this._connectionClient = createSolanaConnection(rpcUrl, commitmentOrConfig);
47
+ }
48
+ return this._connectionClient;
49
+ }
50
+ getWalletClient() {
51
+ return this.getConnection();
52
+ }
53
+ getNetwork() {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ const connection = this.getConnection();
56
+ let genesisHash = localStorage.getItem(getGenesisHashLSKey(connection.rpcEndpoint));
57
+ if (!genesisHash) {
58
+ genesisHash = yield connection.getGenesisHash();
59
+ localStorage.setItem(getGenesisHashLSKey(connection.rpcEndpoint), genesisHash);
60
+ }
61
+ genesisHash = genesisHash.substring(0, 32);
62
+ // see: https://github.com/ChainAgnostic/namespaces/blob/main/solana/caip2.md
63
+ if (genesisHash === '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') {
64
+ return 'mainnet';
65
+ }
66
+ else if (genesisHash === 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1') {
67
+ return 'devnet';
68
+ }
69
+ else {
70
+ return 'testnet';
71
+ }
72
+ });
73
+ }
74
+ getPublicClient() {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ var _a;
77
+ if (this.solNetworks.length === 0)
78
+ return;
79
+ const configurations = {
80
+ cosmos: [],
81
+ evm: undefined,
82
+ solana: this.solNetworks,
83
+ starknet: undefined,
84
+ };
85
+ if (!this.chainRpcProviders)
86
+ return undefined;
87
+ const providers = this.chainRpcProviders.getProviders(configurations);
88
+ return (_a = this.chainRpcProviders.getSolanaProviderByChainId(providers, '101')) === null || _a === void 0 ? void 0 : _a.provider;
89
+ });
90
+ }
91
+ supportsNetworkSwitching() {
92
+ return false;
93
+ }
94
+ setVerifiedCredentials(verifiedCredentials) {
95
+ const turnkeyVerifiedCredential = findTurnkeyVerifiedCredential(verifiedCredentials, ProviderChain.SOLANA);
96
+ const didTurnkeyVerifiedCredentialsChanged = JSON.stringify(this.verifiedCredential) !==
97
+ JSON.stringify(turnkeyVerifiedCredential);
98
+ if (!didTurnkeyVerifiedCredentialsChanged) {
99
+ return;
100
+ }
101
+ this.verifiedCredential = turnkeyVerifiedCredential;
102
+ this.refreshTurnkeyAccount();
103
+ }
104
+ getAccount() {
105
+ return this.turnkeyAddress;
106
+ }
107
+ endSession() {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ localStorage.removeItem(getGenesisHashLSKey(this.getRpcUrl()));
110
+ });
111
+ }
112
+ refreshTurnkeyAccount() {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ this._turnkeyAccount = undefined;
115
+ return this.getTurnkeyAccount();
116
+ });
117
+ }
118
+ getTurnkeyClient() {
119
+ var _a;
120
+ let rpId = getTLD();
121
+ if (!rpId) {
122
+ rpId = PlatformService.getHostname();
123
+ }
124
+ const passkeyStamper = PasskeyService.createWebauthnStamper({
125
+ rpId,
126
+ });
127
+ const apiKeyStamper = TurnkeyWalletConnectorBase === null || TurnkeyWalletConnectorBase === void 0 ? void 0 : TurnkeyWalletConnectorBase.apiKeyStamper;
128
+ const stamper = apiKeyStamper !== null && apiKeyStamper !== void 0 ? apiKeyStamper : passkeyStamper;
129
+ this.__turnkeyClient =
130
+ (_a = this.getAuthenticatorHandler().client) !== null && _a !== void 0 ? _a : new TurnkeyClient({
131
+ baseUrl: TURNKEY_API_BASE_URL,
132
+ }, stamper);
133
+ return this.__turnkeyClient;
134
+ }
135
+ createTurnkeyAccount(_a) {
136
+ return __awaiter(this, arguments, void 0, function* ({ organizationId, }) {
137
+ const turnkeyClient = this.getTurnkeyClient();
138
+ const signer = new TurnkeySigner({ client: turnkeyClient, organizationId });
139
+ return signer;
140
+ });
141
+ }
142
+ getTurnkeyAccount() {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ var _a, _b, _c, _d;
145
+ if (this._turnkeyAccount &&
146
+ ((this.getAuthenticatorHandler().recoveryType === 'passkey' &&
147
+ ((_a = this.__turnkeyClient) === null || _a === void 0 ? void 0 : _a.stamper) instanceof WebauthnStamper) ||
148
+ (this.getAuthenticatorHandler().recoveryType === 'email' &&
149
+ ((_b = this.__turnkeyClient) === null || _b === void 0 ? void 0 : _b.stamper) instanceof IframeStamper)) &&
150
+ this.__turnkeyClient === this.getAuthenticatorHandler().client) {
151
+ return this._turnkeyAccount;
152
+ }
153
+ const { turnkeySubOrganizationId } = (_c = this.walletProperties) !== null && _c !== void 0 ? _c : {};
154
+ const { address } = (_d = this.verifiedCredential) !== null && _d !== void 0 ? _d : {};
155
+ if (!turnkeySubOrganizationId || !address) {
156
+ return;
157
+ }
158
+ this._turnkeyAccount = yield this.createTurnkeyAccount({
159
+ organizationId: turnkeySubOrganizationId,
160
+ });
161
+ return this._turnkeyAccount;
162
+ });
163
+ }
164
+ getSigner() {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ if (this.isSessionKeyCompatible()) {
167
+ yield this.createOrRestoreSession();
168
+ }
169
+ return new TurnkeySolanaSigner({ walletConnector: this });
170
+ });
171
+ }
172
+ getBalance() {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ const address = this.getAccount();
175
+ if (!address) {
176
+ return undefined;
177
+ }
178
+ const connectionClient = this.getConnection();
179
+ const publicKey = new PublicKey(address);
180
+ const balance = yield connectionClient.getBalance(publicKey);
181
+ const solBalance = this.lamportsToSol(balance);
182
+ return solBalance.toString();
183
+ });
184
+ }
185
+ signMessage(messageToSign) {
186
+ return __awaiter(this, void 0, void 0, function* () {
187
+ if (!this.turnkeyAddress) {
188
+ throw new DynamicError('No turnkey account');
189
+ }
190
+ const address = this.turnkeyAddress;
191
+ const signedMessage = yield this.walletUiUtils.signMessage({
192
+ handler: () => __awaiter(this, void 0, void 0, function* () {
193
+ var _a;
194
+ const enc = new TextEncoder();
195
+ const encodedMessage = enc.encode(messageToSign);
196
+ const signedMessageRaw = yield ((_a = (yield this.getTurnkeyAccount())) === null || _a === void 0 ? void 0 : _a.signMessage(encodedMessage, address));
197
+ return bufferToBase64(signedMessageRaw || Buffer.from([]));
198
+ }),
199
+ message: messageToSign,
200
+ });
201
+ return signedMessage;
202
+ });
203
+ }
204
+ signTransaction(_a) {
205
+ return __awaiter(this, arguments, void 0, function* ({ transaction, }) {
206
+ const account = yield this.getTurnkeyAccount();
207
+ const address = this.turnkeyAddress;
208
+ if (!account || !address) {
209
+ throw new Error('No turnkey account');
210
+ }
211
+ yield account.addSignature(transaction, address);
212
+ return Buffer.from(transaction.serialize());
213
+ });
214
+ }
215
+ internalSignAndSendTransaction(transaction, options) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ var _a;
218
+ if (!this.turnkeyAddress)
219
+ throw new DynamicError('Solana wallet not found');
220
+ const currentConnection = this.getConnection('confirmed');
221
+ const blockhash = yield currentConnection.getLatestBlockhash();
222
+ if ('version' in transaction) {
223
+ transaction.message.recentBlockhash =
224
+ blockhash.blockhash;
225
+ }
226
+ else {
227
+ transaction.recentBlockhash = blockhash.blockhash;
228
+ transaction.feePayer =
229
+ (_a = transaction.feePayer) !== null && _a !== void 0 ? _a : new PublicKey(this.turnkeyAddress);
230
+ }
231
+ const signedTransaction = yield this.signTransaction({ transaction });
232
+ const signature = yield currentConnection.sendRawTransaction(signedTransaction, options);
233
+ // listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
234
+ return new Promise((resolve, reject) => {
235
+ const timeout = setTimeout(() => {
236
+ reject(new DynamicError('Transaction timed out'));
237
+ }, 60000);
238
+ currentConnection.onSignature(signature, (result) => {
239
+ clearTimeout(timeout);
240
+ if (result.err) {
241
+ reject(new DynamicError('Transaction failed'));
242
+ }
243
+ else {
244
+ resolve(signature);
245
+ }
246
+ }, 'confirmed');
247
+ });
248
+ });
249
+ }
250
+ signAndSendTransaction(transaction, options) {
251
+ return __awaiter(this, void 0, void 0, function* () {
252
+ if (!this.turnkeyAddress)
253
+ throw new DynamicError('Solana wallet not found');
254
+ const transactionsData = yield decodeTransaction(transaction, this.getConnection(), this.turnkeyAddress);
255
+ if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
256
+ throw new DynamicError('Incorrectly formatted transaction instructions');
257
+ }
258
+ let spent;
259
+ let insufficientFunds = false;
260
+ try {
261
+ spent = yield getTotalSolanaSpend(transaction, this.getConnection(), this.turnkeyAddress);
262
+ }
263
+ catch (e) {
264
+ if (e.message === 'Insufficient funds') {
265
+ insufficientFunds = true;
266
+ }
267
+ }
268
+ const to = summarizeTransactionDecodedData(transactionsData);
269
+ const uiTransaction = new SolanaUiTransaction({
270
+ connection: this.getConnection(),
271
+ from: this.turnkeyAddress,
272
+ onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction, options); }),
273
+ originalTransaction: transaction,
274
+ });
275
+ uiTransaction.to = to;
276
+ uiTransaction.value = spent;
277
+ if (insufficientFunds) {
278
+ uiTransaction.notEnoughFundsError = true;
279
+ }
280
+ return this.walletUiUtils.sendTransaction(this, uiTransaction);
281
+ });
282
+ }
283
+ sendTransaction(transaction_1, connection_1) {
284
+ return __awaiter(this, arguments, void 0, function* (transaction, connection, options = {}) {
285
+ var _a;
286
+ if (!this.turnkeyAddress)
287
+ throw new DynamicError('Solana wallet not found');
288
+ if (!transaction || !connection) {
289
+ throw new DynamicError('Transaction and connection are required');
290
+ }
291
+ const { signers } = options, sendOptions = __rest(options, ["signers"]);
292
+ const blockhash = yield connection.getLatestBlockhash({
293
+ commitment: options.preflightCommitment,
294
+ minContextSlot: options.minContextSlot,
295
+ });
296
+ if ('version' in transaction) {
297
+ (signers === null || signers === void 0 ? void 0 : signers.length) && transaction.sign(signers);
298
+ }
299
+ else {
300
+ transaction.feePayer =
301
+ transaction.feePayer || new PublicKey(this.turnkeyAddress);
302
+ transaction.recentBlockhash =
303
+ transaction.recentBlockhash || blockhash.blockhash;
304
+ (signers === null || signers === void 0 ? void 0 : signers.length) && transaction.partialSign(...signers);
305
+ }
306
+ sendOptions.preflightCommitment =
307
+ sendOptions.preflightCommitment || connection.commitment;
308
+ const signature = yield connection.sendRawTransaction(transaction.serialize(), options);
309
+ const transactionConfirmationStrategy = {
310
+ blockhash: blockhash.blockhash,
311
+ lastValidBlockHeight: blockhash.lastValidBlockHeight,
312
+ signature,
313
+ };
314
+ const result = yield (connection === null || connection === void 0 ? void 0 : connection.confirmTransaction(transactionConfirmationStrategy));
315
+ return ((_a = result === null || result === void 0 ? void 0 : result.value) === null || _a === void 0 ? void 0 : _a.err) ? JSON.stringify(result.value.err) : signature;
316
+ });
317
+ }
318
+ lamportsToSol(lamports) {
319
+ return lamports / LAMPORTS_PER_SOL;
320
+ }
321
+ createUiTransaction(from) {
322
+ return __awaiter(this, void 0, void 0, function* () {
323
+ return new SolanaUiTransaction({
324
+ connection: this.getConnection(),
325
+ from,
326
+ onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
327
+ });
328
+ });
329
+ }
330
+ }
331
+
332
+ export { TurnkeySolanaWalletConnector };
@@ -0,0 +1 @@
1
+ export { TurnkeySolanaWalletConnector } from './TurnkeySolanaWalletConnector';
@@ -0,0 +1,8 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ const SOLANA_GENESIS_HASH = 'genesis-hash';
7
+
8
+ exports.SOLANA_GENESIS_HASH = SOLANA_GENESIS_HASH;
@@ -0,0 +1 @@
1
+ export declare const SOLANA_GENESIS_HASH = "genesis-hash";
@@ -0,0 +1,4 @@
1
+ 'use client'
2
+ const SOLANA_GENESIS_HASH = 'genesis-hash';
3
+
4
+ export { SOLANA_GENESIS_HASH };
@@ -0,0 +1,14 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var web3_js = require('@solana/web3.js');
7
+
8
+ const createSolanaConnection = (rpcUrl, commitmentOrConfig) => {
9
+ if (!rpcUrl)
10
+ throw new Error('rpcUrl is required');
11
+ return new web3_js.Connection(rpcUrl, commitmentOrConfig);
12
+ };
13
+
14
+ exports.createSolanaConnection = createSolanaConnection;
@@ -0,0 +1,2 @@
1
+ import { Commitment, Connection, ConnectionConfig } from '@solana/web3.js';
2
+ export declare const createSolanaConnection: (rpcUrl: string, commitmentOrConfig?: Commitment | ConnectionConfig) => Connection;
@@ -0,0 +1,10 @@
1
+ 'use client'
2
+ import { Connection } from '@solana/web3.js';
3
+
4
+ const createSolanaConnection = (rpcUrl, commitmentOrConfig) => {
5
+ if (!rpcUrl)
6
+ throw new Error('rpcUrl is required');
7
+ return new Connection(rpcUrl, commitmentOrConfig);
8
+ };
9
+
10
+ export { createSolanaConnection };
@@ -0,0 +1 @@
1
+ export { createSolanaConnection } from './createSolanaConnection';
@@ -0,0 +1,10 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var constants = require('../../constants.cjs');
7
+
8
+ const getGenesisHashLSKey = (rpcEndpoint) => `${rpcEndpoint}_${constants.SOLANA_GENESIS_HASH}`;
9
+
10
+ exports.getGenesisHashLSKey = getGenesisHashLSKey;
@@ -0,0 +1 @@
1
+ export declare const getGenesisHashLSKey: (rpcEndpoint: string) => string;
@@ -0,0 +1,6 @@
1
+ 'use client'
2
+ import { SOLANA_GENESIS_HASH } from '../../constants.js';
3
+
4
+ const getGenesisHashLSKey = (rpcEndpoint) => `${rpcEndpoint}_${SOLANA_GENESIS_HASH}`;
5
+
6
+ export { getGenesisHashLSKey };
@@ -0,0 +1 @@
1
+ export { getGenesisHashLSKey } from './getGenesisHashLSKey';
@@ -0,0 +1,3 @@
1
+ export { createSolanaConnection } from './createSolanaConnection';
2
+ export { getGenesisHashLSKey } from './getGenesisHashLSKey';
3
+ export { decodeTransaction, summarizeTransactionDecodedData, getTotalSolanaSpend, } from './transactionDecoder';
@@ -0,0 +1 @@
1
+ export { decodeTransaction, summarizeTransactionDecodedData, getTotalSolanaSpend, } from './transactionDecoder';
@@ -0,0 +1,140 @@
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;
14
+ let simulation;
15
+ if ('version' in transaction) {
16
+ simulation = yield connection.simulateTransaction(transaction, {
17
+ accounts: { addresses: [thisAddress], encoding: 'base64' },
18
+ replaceRecentBlockhash: true,
19
+ });
20
+ }
21
+ else {
22
+ simulation = yield connection.simulateTransaction(transaction, undefined, [new web3_js.PublicKey(thisAddress)]);
23
+ }
24
+ const previousBalance = yield connection.getBalance(new web3_js.PublicKey(thisAddress));
25
+ 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)) {
26
+ walletConnectorCore.logger.debug('Transaction simulation failed', simulation);
27
+ const instructionError = JSON.stringify({
28
+ InstructionError: [
29
+ 0,
30
+ {
31
+ Custom: 1,
32
+ },
33
+ ],
34
+ });
35
+ const insufficientFundsForRent = JSON.stringify({
36
+ InsufficientFundsForRent: {
37
+ account_index: 0,
38
+ },
39
+ });
40
+ if (JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === instructionError ||
41
+ JSON.stringify(simulation === null || simulation === void 0 ? void 0 : simulation.value.err) === insufficientFundsForRent) {
42
+ throw new Error('Insufficient funds');
43
+ }
44
+ return undefined;
45
+ }
46
+ const totalSolTransfer = previousBalance - ((_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[0]) === null || _f === void 0 ? void 0 : _f.lamports);
47
+ return BigInt(totalSolTransfer);
48
+ });
49
+ const decodeTransaction = (transaction, connection, thisAddress) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
50
+ var _g;
51
+ if (!transaction) {
52
+ throw new utils.DynamicError('Transaction is required');
53
+ }
54
+ let decodedInstructions = [];
55
+ if ('version' in transaction) {
56
+ const lookupTableAddresses = transaction.message.addressTableLookups.map((lookup) => new web3_js.PublicKey(lookup.accountKey));
57
+ // for NON simple sol transfers we need to fetch the lookup table accounts
58
+ if (lookupTableAddresses.length > 0) {
59
+ const lookupTables = yield Promise.all(lookupTableAddresses.map((address) => connection.getAddressLookupTable(address)));
60
+ const lookupTableAccounts = lookupTables
61
+ .filter((result) => result !== null)
62
+ .map((result) => result.value);
63
+ if (lookupTableAccounts.length > 0) {
64
+ decodedInstructions = web3_js.TransactionMessage.decompile(transaction.message, {
65
+ addressLookupTableAccounts: lookupTableAccounts,
66
+ }).instructions;
67
+ }
68
+ }
69
+ else {
70
+ decodedInstructions = web3_js.TransactionMessage.decompile(transaction.message).instructions;
71
+ }
72
+ }
73
+ else if (!transaction.instructions) {
74
+ decodedInstructions = (_g = web3_js.Transaction.from(Buffer.from(transaction.serialize()))) === null || _g === void 0 ? void 0 : _g.instructions;
75
+ }
76
+ else {
77
+ decodedInstructions = transaction.instructions;
78
+ }
79
+ if (!(decodedInstructions === null || decodedInstructions === void 0 ? void 0 : decodedInstructions.length)) {
80
+ throw new utils.DynamicError('Bad formatted instruction');
81
+ }
82
+ const solTransfers = decodedInstructions.filter((instruction) => instruction.programId.equals(web3_js.SystemProgram.programId));
83
+ // non SPL transfers, just SOL
84
+ if (solTransfers.length > 0) {
85
+ return solTransfers.map((decodedInstruction) => {
86
+ const decodedTransferInstruction = web3_js.SystemInstruction.decodeTransfer(decodedInstruction);
87
+ return {
88
+ from: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.fromPubkey.toBase58(),
89
+ to: decodedTransferInstruction === null || decodedTransferInstruction === void 0 ? void 0 : decodedTransferInstruction.toPubkey.toBase58(),
90
+ };
91
+ });
92
+ }
93
+ // SPL transfers
94
+ return Promise.all(decodedInstructions.map((instruction) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
95
+ var _h, _j, _k, _l, _m, _o, _p;
96
+ if (instruction.programId.equals(splToken.TOKEN_PROGRAM_ID)) {
97
+ const decodedTokenInstruction = splToken.decodeTransferInstructionUnchecked(instruction);
98
+ const { source, destination } = decodedTokenInstruction.keys;
99
+ if (destination) {
100
+ // for contract interactions, ex. swaps, the destination is the turnkey address, flip sender and receiver
101
+ if ((destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58()) === thisAddress) {
102
+ return {
103
+ from: thisAddress,
104
+ to: source === null || source === void 0 ? void 0 : source.pubkey.toBase58(),
105
+ };
106
+ }
107
+ // Pure SPL transfers, get the address from the destination token account to display to user
108
+ const destinationAccountInfo = yield connection.getParsedAccountInfo(destination.pubkey);
109
+ const isTokenAccount = ((_k = (_j = (_h = destinationAccountInfo.value) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.parsed) === null || _k === void 0 ? void 0 : _k.type) === 'account';
110
+ const destinationOwner = isTokenAccount
111
+ ? (_p = (_o = (_m = (_l = destinationAccountInfo.value) === null || _l === void 0 ? void 0 : _l.data) === null || _m === void 0 ? void 0 : _m.parsed) === null || _o === void 0 ? void 0 : _o.info) === null || _p === void 0 ? void 0 : _p.owner
112
+ : null;
113
+ const toAddress = destinationOwner
114
+ ? destinationOwner
115
+ : destination === null || destination === void 0 ? void 0 : destination.pubkey.toBase58();
116
+ return {
117
+ from: thisAddress,
118
+ to: toAddress,
119
+ };
120
+ }
121
+ }
122
+ return null;
123
+ })));
124
+ });
125
+ const summarizeTransactionDecodedData = (transactionsData) => {
126
+ const recipients = new Set();
127
+ transactionsData.forEach((transactionData) => {
128
+ if (transactionData && transactionData.to) {
129
+ recipients.add(transactionData.to);
130
+ }
131
+ });
132
+ const to = recipients.size === 1
133
+ ? recipients.values().next().value
134
+ : 'dyn_send_transaction.multiple_recipients';
135
+ return to;
136
+ };
137
+
138
+ exports.decodeTransaction = decodeTransaction;
139
+ exports.getTotalSolanaSpend = getTotalSolanaSpend;
140
+ exports.summarizeTransactionDecodedData = summarizeTransactionDecodedData;
@@ -0,0 +1,7 @@
1
+ import { Transaction, VersionedTransaction, Connection } from '@solana/web3.js';
2
+ export declare const getTotalSolanaSpend: (transaction: Transaction | VersionedTransaction, connection: Connection, thisAddress: string) => Promise<bigint | undefined>;
3
+ export declare const decodeTransaction: (transaction: Transaction | VersionedTransaction, connection: Connection, thisAddress: string) => Promise<any>;
4
+ export declare const summarizeTransactionDecodedData: (transactionsData: {
5
+ to: string;
6
+ from: string;
7
+ }[]) => any;