@dynamic-labs/embedded-wallet-solana 3.0.0-alpha.8 → 3.0.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 +622 -0
- package/package.cjs +22 -0
- package/package.js +17 -0
- package/package.json +15 -12
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.cjs +4 -7
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.d.ts +6 -5
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaSigner.js +4 -7
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.cjs +138 -39
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.d.ts +16 -11
- package/src/lib/TurnkeySolanaWalletConnector/TurnkeySolanaWalletConnector.js +136 -37
- package/src/lib/utils/api/api.cjs +38 -0
- package/src/lib/utils/api/api.d.ts +4 -0
- package/src/lib/utils/api/api.js +32 -0
- package/src/lib/utils/api/events/DynamicEvents.d.ts +6 -0
- package/src/lib/utils/api/events/auth.d.ts +49 -0
- package/src/lib/utils/api/utils/ApiEndpoint.cjs +41 -0
- package/src/lib/utils/api/utils/ApiEndpoint.d.ts +7 -0
- package/src/lib/utils/api/utils/ApiEndpoint.js +39 -0
- package/src/lib/utils/api/utils/SdkApi.cjs +35 -0
- package/src/lib/utils/api/utils/SdkApi.d.ts +2 -0
- package/src/lib/utils/api/utils/SdkApi.js +31 -0
- package/src/lib/utils/api/utils/helpers.cjs +92 -0
- package/src/lib/utils/api/utils/helpers.d.ts +12 -0
- package/src/lib/utils/api/utils/helpers.js +81 -0
- package/src/lib/utils/api/utils/version.cjs +12 -0
- package/src/lib/utils/api/utils/version.d.ts +2 -0
- package/src/lib/utils/api/utils/version.js +7 -0
- package/src/lib/utils/index.d.ts +1 -2
- package/src/lib/utils/transactionDecoder/index.d.ts +1 -1
- package/src/lib/utils/transactionDecoder/transactionDecoder.cjs +127 -71
- package/src/lib/utils/transactionDecoder/transactionDecoder.d.ts +8 -6
- package/src/lib/utils/transactionDecoder/transactionDecoder.js +127 -72
- package/src/lib/constants.cjs +0 -8
- package/src/lib/constants.d.ts +0 -1
- package/src/lib/constants.js +0 -4
- package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.cjs +0 -10
- package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.d.ts +0 -1
- package/src/lib/utils/getGenesisHashLSKey/getGenesisHashLSKey.js +0 -6
- package/src/lib/utils/getGenesisHashLSKey/index.d.ts +0 -1
|
@@ -5,13 +5,13 @@ import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
|
|
5
5
|
import { TurnkeyClient } from '@turnkey/http';
|
|
6
6
|
import { TurnkeySigner } from '@turnkey/solana';
|
|
7
7
|
import { IframeStamper } from '@turnkey/iframe-stamper';
|
|
8
|
-
import {
|
|
8
|
+
import { isSameAddress } from '@dynamic-labs/wallet-connector-core';
|
|
9
9
|
import { DynamicError, getTLD, PlatformService, bufferToBase64 } from '@dynamic-labs/utils';
|
|
10
|
-
import { SolanaUiTransaction } from '@dynamic-labs/solana-
|
|
11
|
-
import { TurnkeyWalletConnectorBase,
|
|
10
|
+
import { SolanaWallet, ProviderChain, getGenesisHashLSKey, SolanaUiTransaction } from '@dynamic-labs/solana-core';
|
|
11
|
+
import { TurnkeyWalletConnectorBase, findTurnkeyVerifiedCredentials, PasskeyService, TURNKEY_API_BASE_URL, TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS, logger } from '@dynamic-labs/embedded-wallet';
|
|
12
12
|
import { createSolanaConnection } from '../utils/createSolanaConnection/createSolanaConnection.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { decodeTransaction, getTotalSolanaSpend, summarizeTransactionDecodedData } from '../utils/transactionDecoder/transactionDecoder.js';
|
|
14
|
+
import { optimizeSolanaTransaction } from '../utils/api/api.js';
|
|
15
15
|
import { TurnkeySolanaSigner } from './TurnkeySolanaSigner.js';
|
|
16
16
|
|
|
17
17
|
class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
@@ -19,9 +19,32 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
19
19
|
var _a;
|
|
20
20
|
super(nameAndKey, props);
|
|
21
21
|
// Public fields
|
|
22
|
+
this.ChainWallet = SolanaWallet;
|
|
22
23
|
this.connectedChain = 'SOL';
|
|
23
24
|
this.supportedChains = ['SOL'];
|
|
24
25
|
this.verifiedCredentialChain = 'solana';
|
|
26
|
+
this.getEnvId = () => {
|
|
27
|
+
const dynamicNonce = localStorage.getItem('dynamic_nonce');
|
|
28
|
+
if (dynamicNonce) {
|
|
29
|
+
const parsed = JSON.parse(dynamicNonce);
|
|
30
|
+
if (parsed && parsed.environmentId) {
|
|
31
|
+
return parsed.environmentId;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const dynamicNonceDemo = localStorage.getItem('dynamic_nonce_demo');
|
|
35
|
+
if (dynamicNonceDemo) {
|
|
36
|
+
const parsed = JSON.parse(dynamicNonceDemo);
|
|
37
|
+
if (parsed && parsed.environmentId) {
|
|
38
|
+
return parsed.environmentId;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw new Error('Failed to get environment id');
|
|
42
|
+
};
|
|
43
|
+
this.stampCreateWalletAccountRequest = (_b) => __awaiter(this, [_b], void 0, function* ({ request, }) {
|
|
44
|
+
yield this.createOrRestoreSession();
|
|
45
|
+
const turnkeyClient = this.getTurnkeyClient();
|
|
46
|
+
return turnkeyClient.stampCreateWalletAccounts(request);
|
|
47
|
+
});
|
|
25
48
|
this.solNetworks = props.solNetworks;
|
|
26
49
|
this.walletUiUtils = props.walletUiUtils;
|
|
27
50
|
this._turnkeyAccount = undefined;
|
|
@@ -92,15 +115,32 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
92
115
|
return false;
|
|
93
116
|
}
|
|
94
117
|
setVerifiedCredentials(verifiedCredentials) {
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
118
|
+
const turnkeyVerifiedCredentials = findTurnkeyVerifiedCredentials(verifiedCredentials, ProviderChain.SOLANA);
|
|
119
|
+
const [turnkeyVerifiedCredential] = turnkeyVerifiedCredentials;
|
|
120
|
+
const didTurnkeyVerifiedCredentialsChanged = JSON.stringify(this.verifiedCredentials) !==
|
|
121
|
+
JSON.stringify(turnkeyVerifiedCredentials);
|
|
98
122
|
if (!didTurnkeyVerifiedCredentialsChanged) {
|
|
99
123
|
return;
|
|
100
124
|
}
|
|
101
125
|
this.verifiedCredential = turnkeyVerifiedCredential;
|
|
126
|
+
this.verifiedCredentials = turnkeyVerifiedCredentials;
|
|
102
127
|
this.refreshTurnkeyAccount();
|
|
103
128
|
}
|
|
129
|
+
validateActiveWallet(expectedAddress) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
var _a, _b;
|
|
132
|
+
const activeAddress = ((_a = this.verifiedCredential) === null || _a === void 0 ? void 0 : _a.address) || '';
|
|
133
|
+
const isWalletActive = isSameAddress(activeAddress, expectedAddress, this.connectedChain);
|
|
134
|
+
if (!isWalletActive) {
|
|
135
|
+
const targetActiveAccount = (_b = this.verifiedCredentials) === null || _b === void 0 ? void 0 : _b.find((vc) => (vc === null || vc === void 0 ? void 0 : vc.address) === expectedAddress);
|
|
136
|
+
if (!targetActiveAccount) {
|
|
137
|
+
throw new DynamicError('Account not found');
|
|
138
|
+
}
|
|
139
|
+
this.verifiedCredential = targetActiveAccount;
|
|
140
|
+
this.refreshTurnkeyAccount();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
104
144
|
getAccount() {
|
|
105
145
|
return this.turnkeyAddress;
|
|
106
146
|
}
|
|
@@ -158,23 +198,17 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
158
198
|
this._turnkeyAccount = yield this.createTurnkeyAccount({
|
|
159
199
|
organizationId: turnkeySubOrganizationId,
|
|
160
200
|
});
|
|
201
|
+
this.setLoggerMetadata();
|
|
161
202
|
return this._turnkeyAccount;
|
|
162
203
|
});
|
|
163
204
|
}
|
|
164
205
|
getSigner() {
|
|
165
206
|
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
if (this.isSessionKeyCompatible()) {
|
|
167
|
-
yield this.createOrRestoreSession();
|
|
168
|
-
}
|
|
169
207
|
return new TurnkeySolanaSigner({ walletConnector: this });
|
|
170
208
|
});
|
|
171
209
|
}
|
|
172
|
-
getBalance() {
|
|
210
|
+
getBalance(address) {
|
|
173
211
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
const address = this.getAccount();
|
|
175
|
-
if (!address) {
|
|
176
|
-
return undefined;
|
|
177
|
-
}
|
|
178
212
|
const connectionClient = this.getConnection();
|
|
179
213
|
const publicKey = new PublicKey(address);
|
|
180
214
|
const balance = yield connectionClient.getBalance(publicKey);
|
|
@@ -182,34 +216,72 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
182
216
|
return solBalance.toString();
|
|
183
217
|
});
|
|
184
218
|
}
|
|
185
|
-
|
|
219
|
+
signUint8ArrayMessage(encodedMessage) {
|
|
186
220
|
return __awaiter(this, void 0, void 0, function* () {
|
|
187
221
|
if (!this.turnkeyAddress) {
|
|
188
222
|
throw new DynamicError('No turnkey account');
|
|
189
223
|
}
|
|
190
224
|
const address = this.turnkeyAddress;
|
|
191
|
-
|
|
225
|
+
let signedMessageRaw;
|
|
226
|
+
yield this.createOrRestoreSession();
|
|
227
|
+
yield this.walletUiUtils.signMessage({
|
|
192
228
|
handler: () => __awaiter(this, void 0, void 0, function* () {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
229
|
+
let account = yield this.getTurnkeyAccount();
|
|
230
|
+
try {
|
|
231
|
+
signedMessageRaw = yield (account === null || account === void 0 ? void 0 : account.signMessage(encodedMessage, address));
|
|
232
|
+
}
|
|
233
|
+
catch (_a) {
|
|
234
|
+
yield this.removeSessionKeys();
|
|
235
|
+
yield this.createOrRestoreSession({
|
|
236
|
+
ignoreRestore: true,
|
|
237
|
+
});
|
|
238
|
+
account = yield this.getTurnkeyAccount();
|
|
239
|
+
signedMessageRaw = yield (account === null || account === void 0 ? void 0 : account.signMessage(encodedMessage, address));
|
|
240
|
+
}
|
|
197
241
|
return bufferToBase64(signedMessageRaw || Buffer.from([]));
|
|
198
242
|
}),
|
|
199
|
-
message:
|
|
243
|
+
message: new TextDecoder().decode(encodedMessage),
|
|
200
244
|
});
|
|
201
|
-
|
|
245
|
+
if (!signedMessageRaw) {
|
|
246
|
+
throw new Error('Failed to sign message');
|
|
247
|
+
}
|
|
248
|
+
return signedMessageRaw;
|
|
202
249
|
});
|
|
203
250
|
}
|
|
204
|
-
|
|
205
|
-
return __awaiter(this,
|
|
206
|
-
const
|
|
251
|
+
signMessage(messageToSign) {
|
|
252
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
253
|
+
const enc = new TextEncoder();
|
|
254
|
+
const encodedMessage = enc.encode(messageToSign);
|
|
255
|
+
const signedRawMessage = yield this.signUint8ArrayMessage(encodedMessage);
|
|
256
|
+
return bufferToBase64(signedRawMessage);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
signTransaction(transaction) {
|
|
260
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
yield this.createOrRestoreSession();
|
|
262
|
+
let account = yield this.getTurnkeyAccount();
|
|
207
263
|
const address = this.turnkeyAddress;
|
|
208
264
|
if (!account || !address) {
|
|
209
265
|
throw new Error('No turnkey account');
|
|
210
266
|
}
|
|
211
|
-
|
|
212
|
-
|
|
267
|
+
try {
|
|
268
|
+
yield account.addSignature(transaction, address);
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
if (TURNKEY_SDK_SESSION_KEY_RETRYABLE_ERRORS.some((errorMsg) => err.message.includes(errorMsg))) {
|
|
272
|
+
yield this.removeSessionKeys();
|
|
273
|
+
yield this.createOrRestoreSession({
|
|
274
|
+
ignoreRestore: true,
|
|
275
|
+
});
|
|
276
|
+
account = (yield this.getTurnkeyAccount());
|
|
277
|
+
yield account.addSignature(transaction, address);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
logger.error('[TK] failed to perform SignTransaction activity', err);
|
|
281
|
+
throw err;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return transaction;
|
|
213
285
|
});
|
|
214
286
|
}
|
|
215
287
|
internalSignAndSendTransaction(transaction, options) {
|
|
@@ -228,8 +300,8 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
228
300
|
transaction.feePayer =
|
|
229
301
|
(_a = transaction.feePayer) !== null && _a !== void 0 ? _a : new PublicKey(this.turnkeyAddress);
|
|
230
302
|
}
|
|
231
|
-
const signedTransaction = yield this.signTransaction(
|
|
232
|
-
const signature = yield currentConnection.sendRawTransaction(signedTransaction, options);
|
|
303
|
+
const signedTransaction = yield this.signTransaction(transaction);
|
|
304
|
+
const signature = yield currentConnection.sendRawTransaction(Buffer.from(signedTransaction.serialize()), options);
|
|
233
305
|
// listen for tx confirmation until 60 seconds, which is ~150 blocks expiration
|
|
234
306
|
return new Promise((resolve, reject) => {
|
|
235
307
|
const timeout = setTimeout(() => {
|
|
@@ -249,21 +321,45 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
249
321
|
}
|
|
250
322
|
signAndSendTransaction(transaction, options) {
|
|
251
323
|
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
var _a;
|
|
252
325
|
if (!this.turnkeyAddress)
|
|
253
326
|
throw new DynamicError('Solana wallet not found');
|
|
254
|
-
|
|
327
|
+
let optimizedTransaction = transaction;
|
|
328
|
+
try {
|
|
329
|
+
if ((yield this.getNetwork()) === 'mainnet') {
|
|
330
|
+
optimizedTransaction = (yield optimizeSolanaTransaction(this.getEnvId(), transaction, (_a = this.turnkeyAddress) !== null && _a !== void 0 ? _a : ''));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
logger.warn('Failed to optimize transaction', e);
|
|
335
|
+
}
|
|
336
|
+
const transactionsData = yield decodeTransaction(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
255
337
|
if (!(transactionsData === null || transactionsData === void 0 ? void 0 : transactionsData.length)) {
|
|
256
338
|
throw new DynamicError('Incorrectly formatted transaction instructions');
|
|
257
339
|
}
|
|
258
|
-
|
|
340
|
+
let spent;
|
|
341
|
+
let insufficientFunds = false;
|
|
342
|
+
try {
|
|
343
|
+
spent = yield getTotalSolanaSpend(optimizedTransaction, this.getConnection(), this.turnkeyAddress);
|
|
344
|
+
}
|
|
345
|
+
catch (e) {
|
|
346
|
+
if (e.message === 'Insufficient funds') {
|
|
347
|
+
insufficientFunds = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const to = summarizeTransactionDecodedData(transactionsData);
|
|
259
351
|
const uiTransaction = new SolanaUiTransaction({
|
|
260
352
|
connection: this.getConnection(),
|
|
261
353
|
from: this.turnkeyAddress,
|
|
262
|
-
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(
|
|
263
|
-
originalTransaction:
|
|
354
|
+
onSubmit: () => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(optimizedTransaction, options); }),
|
|
355
|
+
originalTransaction: optimizedTransaction,
|
|
264
356
|
});
|
|
265
357
|
uiTransaction.to = to;
|
|
266
|
-
uiTransaction.value =
|
|
358
|
+
uiTransaction.value = spent;
|
|
359
|
+
if (insufficientFunds) {
|
|
360
|
+
uiTransaction.notEnoughFundsError = true;
|
|
361
|
+
}
|
|
362
|
+
// TODO: remove this. We should not be passing references to wallet connectors
|
|
267
363
|
return this.walletUiUtils.sendTransaction(this, uiTransaction);
|
|
268
364
|
});
|
|
269
365
|
}
|
|
@@ -307,11 +403,14 @@ class TurnkeySolanaWalletConnector extends TurnkeyWalletConnectorBase {
|
|
|
307
403
|
}
|
|
308
404
|
createUiTransaction(from) {
|
|
309
405
|
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
-
|
|
406
|
+
yield this.validateActiveWallet(from);
|
|
407
|
+
const transaction = new SolanaUiTransaction({
|
|
311
408
|
connection: this.getConnection(),
|
|
312
409
|
from,
|
|
313
410
|
onSubmit: (transaction) => __awaiter(this, void 0, void 0, function* () { return this.internalSignAndSendTransaction(transaction); }),
|
|
314
411
|
});
|
|
412
|
+
transaction.feeDeducted = true;
|
|
413
|
+
return transaction;
|
|
315
414
|
});
|
|
316
415
|
}
|
|
317
416
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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 SdkApi = require('./utils/SdkApi.cjs');
|
|
9
|
+
|
|
10
|
+
const serializeTransaction = (transaction) => {
|
|
11
|
+
if (transaction instanceof web3_js.VersionedTransaction) {
|
|
12
|
+
return Buffer.from(transaction.serialize()).toString('base64');
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return Buffer.from(transaction.serialize({ verifySignatures: false })).toString('base64');
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const deserializeTransaction = (serializedTransaction) => {
|
|
19
|
+
const transactionBuffer = Buffer.from(serializedTransaction, 'base64');
|
|
20
|
+
return web3_js.VersionedTransaction.deserialize(transactionBuffer);
|
|
21
|
+
};
|
|
22
|
+
const optimizeSolanaTransaction = (environmentId, transaction, address) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
const serializedTransaction = serializeTransaction(transaction);
|
|
24
|
+
const request = {
|
|
25
|
+
environmentId,
|
|
26
|
+
solanaTransactionOptimizationRequest: {
|
|
27
|
+
address,
|
|
28
|
+
transaction: serializedTransaction,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const response = yield SdkApi.sdkApi().optimizeTransaction(request);
|
|
32
|
+
const optimizedTransaction = deserializeTransaction(response.transaction);
|
|
33
|
+
return optimizedTransaction;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
exports.deserializeTransaction = deserializeTransaction;
|
|
37
|
+
exports.optimizeSolanaTransaction = optimizeSolanaTransaction;
|
|
38
|
+
exports.serializeTransaction = serializeTransaction;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
2
|
+
export declare const serializeTransaction: (transaction: Transaction | VersionedTransaction) => string;
|
|
3
|
+
export declare const deserializeTransaction: (serializedTransaction: string) => VersionedTransaction;
|
|
4
|
+
export declare const optimizeSolanaTransaction: (environmentId: string, transaction: Transaction | VersionedTransaction, address: string) => Promise<VersionedTransaction>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { __awaiter } from '../../../../_virtual/_tslib.js';
|
|
3
|
+
import { VersionedTransaction } from '@solana/web3.js';
|
|
4
|
+
import { sdkApi } from './utils/SdkApi.js';
|
|
5
|
+
|
|
6
|
+
const serializeTransaction = (transaction) => {
|
|
7
|
+
if (transaction instanceof VersionedTransaction) {
|
|
8
|
+
return Buffer.from(transaction.serialize()).toString('base64');
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
return Buffer.from(transaction.serialize({ verifySignatures: false })).toString('base64');
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const deserializeTransaction = (serializedTransaction) => {
|
|
15
|
+
const transactionBuffer = Buffer.from(serializedTransaction, 'base64');
|
|
16
|
+
return VersionedTransaction.deserialize(transactionBuffer);
|
|
17
|
+
};
|
|
18
|
+
const optimizeSolanaTransaction = (environmentId, transaction, address) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
const serializedTransaction = serializeTransaction(transaction);
|
|
20
|
+
const request = {
|
|
21
|
+
environmentId,
|
|
22
|
+
solanaTransactionOptimizationRequest: {
|
|
23
|
+
address,
|
|
24
|
+
transaction: serializedTransaction,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
const response = yield sdkApi().optimizeTransaction(request);
|
|
28
|
+
const optimizedTransaction = deserializeTransaction(response.transaction);
|
|
29
|
+
return optimizedTransaction;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export { deserializeTransaction, optimizeSolanaTransaction, serializeTransaction };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { AuthEvents } from './auth';
|
|
3
|
+
/** Maps internal event names to their listeners */
|
|
4
|
+
export type DynamicEvents = AuthEvents;
|
|
5
|
+
export declare const dynamicEvents: EventEmitter<AuthEvents, any>;
|
|
6
|
+
export type DynamicEventEmitter = typeof dynamicEvents;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AuthMethod, AuthOptions } from '@dynamic-labs/types';
|
|
2
|
+
/**
|
|
3
|
+
* Maps auth methods to what property will be displayed under the "option" property of the event.
|
|
4
|
+
*
|
|
5
|
+
* Users will be able to access this data through the AuthOptions[K] type injection as well,
|
|
6
|
+
* but with the "option" property they will also have a standard way to access the auth method target.
|
|
7
|
+
*/
|
|
8
|
+
type AuthEventPayloadOptionMap = {
|
|
9
|
+
wallet: AuthOptions['wallet']['connectorName'];
|
|
10
|
+
sms: AuthOptions['sms']['phone'];
|
|
11
|
+
email: AuthOptions['email']['email'];
|
|
12
|
+
social: AuthOptions['social']['provider'];
|
|
13
|
+
externalAuth: AuthOptions['externalAuth']['externalUserId'];
|
|
14
|
+
};
|
|
15
|
+
/** Payload of auth events that provide insight into which auth method was selected */
|
|
16
|
+
export type AuthEventPayload = {
|
|
17
|
+
[K in AuthMethod]: {
|
|
18
|
+
type: K;
|
|
19
|
+
option: AuthEventPayloadOptionMap[K];
|
|
20
|
+
} & AuthOptions[K];
|
|
21
|
+
}[AuthMethod];
|
|
22
|
+
export type AuthEvents = {
|
|
23
|
+
/**
|
|
24
|
+
* Informs an auth attempt failed.
|
|
25
|
+
* In general triggered when an error occurs or when user cancels out.
|
|
26
|
+
* For email/sms, specifically happens when users cancels the OTP verification.
|
|
27
|
+
*/
|
|
28
|
+
authFailure: (method: AuthEventPayload,
|
|
29
|
+
/** Will be 'user-cancelled' when cancelled, or the error when there is an error */
|
|
30
|
+
reason: 'user-cancelled' | {
|
|
31
|
+
error: unknown;
|
|
32
|
+
}) => void;
|
|
33
|
+
/** Informs an auth attempt initialized, and provides insight into which auth option it is */
|
|
34
|
+
authInit: (method: AuthEventPayload) => void;
|
|
35
|
+
logout: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Emitted when the user succesfully completes an MFA challenge
|
|
38
|
+
*/
|
|
39
|
+
mfaCompletionSuccess: (args: {
|
|
40
|
+
mfaToken?: string;
|
|
41
|
+
}) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Emitted when there is an error verifiyng the MFA challenge
|
|
44
|
+
*/
|
|
45
|
+
mfaCompletionFailure: (args: {
|
|
46
|
+
error: unknown;
|
|
47
|
+
}) => void;
|
|
48
|
+
};
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
5
|
+
|
|
6
|
+
/* eslint-disable no-underscore-dangle */
|
|
7
|
+
class ApiEndpoint {
|
|
8
|
+
}
|
|
9
|
+
ApiEndpoint.getBaseUrl = () => {
|
|
10
|
+
if (!ApiEndpoint.__defined__) {
|
|
11
|
+
throw new Error('ApiEndpoint Base URL has not been initialized');
|
|
12
|
+
}
|
|
13
|
+
return ApiEndpoint.__baseUrl__;
|
|
14
|
+
};
|
|
15
|
+
ApiEndpoint.setBaseUrl = (baseUrlInput) => {
|
|
16
|
+
if (!ApiEndpoint.__defined__) {
|
|
17
|
+
if (!baseUrlInput) {
|
|
18
|
+
/**
|
|
19
|
+
* If the baseUrl is not provided, use the default baseUrl from the sdk-api package
|
|
20
|
+
*/
|
|
21
|
+
ApiEndpoint.__baseUrl__ = new sdkApiCore.Configuration().basePath;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
ApiEndpoint.__baseUrl__ = baseUrlInput;
|
|
25
|
+
}
|
|
26
|
+
ApiEndpoint.__defined__ = true;
|
|
27
|
+
}
|
|
28
|
+
else if (!baseUrlInput && ApiEndpoint.__defined__) {
|
|
29
|
+
/**
|
|
30
|
+
* If for some reason (usually in local development), the setBaseUrl is called multiple times with undefined
|
|
31
|
+
* And we already have it defined, let's just assume it's a no-op
|
|
32
|
+
*/
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
else if (ApiEndpoint.__baseUrl__ !== baseUrlInput) {
|
|
36
|
+
throw new Error(`ApiEndpoint baseUrl is already set to ${ApiEndpoint.__baseUrl__}, cannot change it to ${baseUrlInput}`);
|
|
37
|
+
}
|
|
38
|
+
Object.freeze(ApiEndpoint);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = ApiEndpoint;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { Configuration } from '@dynamic-labs/sdk-api-core';
|
|
3
|
+
|
|
4
|
+
/* eslint-disable no-underscore-dangle */
|
|
5
|
+
class ApiEndpoint {
|
|
6
|
+
}
|
|
7
|
+
ApiEndpoint.getBaseUrl = () => {
|
|
8
|
+
if (!ApiEndpoint.__defined__) {
|
|
9
|
+
throw new Error('ApiEndpoint Base URL has not been initialized');
|
|
10
|
+
}
|
|
11
|
+
return ApiEndpoint.__baseUrl__;
|
|
12
|
+
};
|
|
13
|
+
ApiEndpoint.setBaseUrl = (baseUrlInput) => {
|
|
14
|
+
if (!ApiEndpoint.__defined__) {
|
|
15
|
+
if (!baseUrlInput) {
|
|
16
|
+
/**
|
|
17
|
+
* If the baseUrl is not provided, use the default baseUrl from the sdk-api package
|
|
18
|
+
*/
|
|
19
|
+
ApiEndpoint.__baseUrl__ = new Configuration().basePath;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
ApiEndpoint.__baseUrl__ = baseUrlInput;
|
|
23
|
+
}
|
|
24
|
+
ApiEndpoint.__defined__ = true;
|
|
25
|
+
}
|
|
26
|
+
else if (!baseUrlInput && ApiEndpoint.__defined__) {
|
|
27
|
+
/**
|
|
28
|
+
* If for some reason (usually in local development), the setBaseUrl is called multiple times with undefined
|
|
29
|
+
* And we already have it defined, let's just assume it's a no-op
|
|
30
|
+
*/
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
else if (ApiEndpoint.__baseUrl__ !== baseUrlInput) {
|
|
34
|
+
throw new Error(`ApiEndpoint baseUrl is already set to ${ApiEndpoint.__baseUrl__}, cannot change it to ${baseUrlInput}`);
|
|
35
|
+
}
|
|
36
|
+
Object.freeze(ApiEndpoint);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export { ApiEndpoint as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
7
|
+
var utils = require('@dynamic-labs/utils');
|
|
8
|
+
var helpers = require('./helpers.cjs');
|
|
9
|
+
var ApiEndpoint = require('./ApiEndpoint.cjs');
|
|
10
|
+
var version = require('./version.cjs');
|
|
11
|
+
|
|
12
|
+
const sdkApi = () => {
|
|
13
|
+
const baseUrl = process.env.API_BASE_URL ||
|
|
14
|
+
process.env.NX_API_BASE_URL ||
|
|
15
|
+
'https://app.dynamic.xyz/api/v0';
|
|
16
|
+
ApiEndpoint.setBaseUrl(baseUrl);
|
|
17
|
+
const settings = {
|
|
18
|
+
basePath: ApiEndpoint.getBaseUrl(),
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const minJwt = helpers.getMinAuthToken();
|
|
24
|
+
if (minJwt) {
|
|
25
|
+
settings.headers.Authorization = `Bearer ${minJwt}`;
|
|
26
|
+
}
|
|
27
|
+
const credentials = helpers.isCookieEnabled()
|
|
28
|
+
? 'include'
|
|
29
|
+
: undefined;
|
|
30
|
+
settings.headers['x-dyn-version'] = `WalletKit/${version.VERSION}`;
|
|
31
|
+
settings.headers['x-dyn-api-version'] = `API/${version.API_VERSION}`;
|
|
32
|
+
return new sdkApiCore.SDKApi(new sdkApiCore.Configuration(Object.assign(Object.assign({}, settings), { credentials, fetchApi: utils.FetchService.fetch })));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
exports.sdkApi = sdkApi;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { SDKApi, Configuration } from '@dynamic-labs/sdk-api-core';
|
|
3
|
+
import { FetchService } from '@dynamic-labs/utils';
|
|
4
|
+
import { getMinAuthToken, isCookieEnabled } from './helpers.js';
|
|
5
|
+
import ApiEndpoint from './ApiEndpoint.js';
|
|
6
|
+
import { VERSION, API_VERSION } from './version.js';
|
|
7
|
+
|
|
8
|
+
const sdkApi = () => {
|
|
9
|
+
const baseUrl = process.env.API_BASE_URL ||
|
|
10
|
+
process.env.NX_API_BASE_URL ||
|
|
11
|
+
'https://app.dynamic.xyz/api/v0';
|
|
12
|
+
ApiEndpoint.setBaseUrl(baseUrl);
|
|
13
|
+
const settings = {
|
|
14
|
+
basePath: ApiEndpoint.getBaseUrl(),
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const minJwt = getMinAuthToken();
|
|
20
|
+
if (minJwt) {
|
|
21
|
+
settings.headers.Authorization = `Bearer ${minJwt}`;
|
|
22
|
+
}
|
|
23
|
+
const credentials = isCookieEnabled()
|
|
24
|
+
? 'include'
|
|
25
|
+
: undefined;
|
|
26
|
+
settings.headers['x-dyn-version'] = `WalletKit/${VERSION}`;
|
|
27
|
+
settings.headers['x-dyn-api-version'] = `API/${API_VERSION}`;
|
|
28
|
+
return new SDKApi(new Configuration(Object.assign(Object.assign({}, settings), { credentials, fetchApi: FetchService.fetch })));
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { sdkApi };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
7
|
+
var logger$1 = require('@dynamic-labs/logger');
|
|
8
|
+
var utils = require('@dynamic-labs/utils');
|
|
9
|
+
|
|
10
|
+
const logger = new logger$1.Logger('DynamicSDK');
|
|
11
|
+
const AUTH_MIN_TOKEN = 'dynamic_min_authentication_token';
|
|
12
|
+
const AUTH_MIN_TOKEN_DEMO = 'dynamic_min_authentication_token_demo';
|
|
13
|
+
const isCookieEnabled = () => {
|
|
14
|
+
var _a, _b, _c, _d;
|
|
15
|
+
let securitySettings = (_a = utils.StorageService.getItem('dynamic_store')) !== null && _a !== void 0 ? _a : utils.StorageService.getItem('dynamic_store_demo');
|
|
16
|
+
securitySettings = (_b = securitySettings === null || securitySettings === void 0 ? void 0 : securitySettings.settings) === null || _b === void 0 ? void 0 : _b.security;
|
|
17
|
+
if (!securitySettings)
|
|
18
|
+
return false;
|
|
19
|
+
// client uses Dynamic cookies
|
|
20
|
+
const dynamicCookiesEnabled = (((_c = securitySettings.auth) === null || _c === void 0 ? void 0 : _c.storage) || []).includes(sdkApiCore.AuthStorageEnum.Cookie);
|
|
21
|
+
// BYO JWT client puts their non-Dynamic JWT in a cookie
|
|
22
|
+
const byoJwtCookieEnabled = Boolean((_d = securitySettings.externalAuth) === null || _d === void 0 ? void 0 : _d.cookieName);
|
|
23
|
+
// should return true for both of these scenarios
|
|
24
|
+
// because we also need to do `credentials: true` in api.ts when
|
|
25
|
+
// a byo jwt client sets their named cookie for their jwt and
|
|
26
|
+
// needs to send it to our backend
|
|
27
|
+
return dynamicCookiesEnabled || byoJwtCookieEnabled;
|
|
28
|
+
};
|
|
29
|
+
const parseToken = (token) => {
|
|
30
|
+
var _a;
|
|
31
|
+
if (!token)
|
|
32
|
+
return undefined;
|
|
33
|
+
const base64 = (_a = token.split('.')[1]) === null || _a === void 0 ? void 0 : _a.replace(/-/g, '+').replace(/_/g, '/');
|
|
34
|
+
const jsonPayload = base64 &&
|
|
35
|
+
decodeURIComponent(atob(base64)
|
|
36
|
+
.split('')
|
|
37
|
+
.map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)
|
|
38
|
+
.join(''));
|
|
39
|
+
return JSON.parse(jsonPayload);
|
|
40
|
+
};
|
|
41
|
+
const decodeMinJwt = (token) => {
|
|
42
|
+
try {
|
|
43
|
+
const json = parseToken(token);
|
|
44
|
+
if (!json)
|
|
45
|
+
return undefined;
|
|
46
|
+
return sdkApiCore.MinifiedDynamicJwtFromJSON(json);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
logger.error(e);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const getMinAuthToken = () => {
|
|
54
|
+
var _a;
|
|
55
|
+
if (typeof window === 'undefined')
|
|
56
|
+
return undefined;
|
|
57
|
+
const token = (_a = utils.StorageService.getItem(AUTH_MIN_TOKEN, {
|
|
58
|
+
priority: ['secureStorage', 'localStorage'],
|
|
59
|
+
})) !== null && _a !== void 0 ? _a : utils.StorageService.getItem(AUTH_MIN_TOKEN_DEMO, {
|
|
60
|
+
priority: ['secureStorage', 'localStorage'],
|
|
61
|
+
});
|
|
62
|
+
if (!token || isMinAuthTokenExpired(token))
|
|
63
|
+
return undefined;
|
|
64
|
+
return token;
|
|
65
|
+
};
|
|
66
|
+
const isMinAuthTokenExpired = (token) => {
|
|
67
|
+
const decoded = decodeMinJwt(token);
|
|
68
|
+
return isTokenExpired(decoded);
|
|
69
|
+
};
|
|
70
|
+
const isTokenExpired = (decoded) => {
|
|
71
|
+
if (!decoded) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
if (!decoded.exp) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
const expirationTime = new Date(decoded.exp * 1000).getTime();
|
|
78
|
+
const currentTime = new Date().getTime();
|
|
79
|
+
if (currentTime >= expirationTime) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
exports.AUTH_MIN_TOKEN = AUTH_MIN_TOKEN;
|
|
86
|
+
exports.AUTH_MIN_TOKEN_DEMO = AUTH_MIN_TOKEN_DEMO;
|
|
87
|
+
exports.decodeMinJwt = decodeMinJwt;
|
|
88
|
+
exports.getMinAuthToken = getMinAuthToken;
|
|
89
|
+
exports.isCookieEnabled = isCookieEnabled;
|
|
90
|
+
exports.isMinAuthTokenExpired = isMinAuthTokenExpired;
|
|
91
|
+
exports.logger = logger;
|
|
92
|
+
exports.parseToken = parseToken;
|