@dynamic-labs-wallet/node-svm 0.0.0-beta-191.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/index.cjs.js ADDED
@@ -0,0 +1,323 @@
1
+ 'use strict';
2
+
3
+ var node = require('@dynamic-labs-wallet/node');
4
+ var web3_js = require('@solana/web3.js');
5
+
6
+ function _extends() {
7
+ _extends = Object.assign || function assign(target) {
8
+ for(var i = 1; i < arguments.length; i++){
9
+ var source = arguments[i];
10
+ for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
11
+ }
12
+ return target;
13
+ };
14
+ return _extends.apply(this, arguments);
15
+ }
16
+
17
+ const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
18
+
19
+ async function getBalance({ address, rpcUrl = node.SOLANA_RPC_URL }) {
20
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
21
+ const balance = await connection.getBalance(new web3_js.PublicKey(address));
22
+ return balance;
23
+ }
24
+ async function createSolanaTransaction({ senderSolanaAddress, amount, to, rpcUrl = 'https://api.devnet.solana.com' }) {
25
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
26
+ const balance = await getBalance({
27
+ address: senderSolanaAddress,
28
+ rpcUrl
29
+ });
30
+ if (balance < amount * 1e9) {
31
+ throw new Error('Insufficient balance');
32
+ }
33
+ const fromPubkey = new web3_js.PublicKey(senderSolanaAddress);
34
+ const transaction = new web3_js.Transaction().add(web3_js.SystemProgram.transfer({
35
+ fromPubkey: fromPubkey,
36
+ toPubkey: new web3_js.PublicKey(to),
37
+ lamports: amount * 1e9
38
+ }));
39
+ const { blockhash } = await connection.getLatestBlockhash();
40
+ transaction.recentBlockhash = blockhash;
41
+ transaction.feePayer = fromPubkey;
42
+ const serializedTransaction = transaction.serializeMessage();
43
+ return {
44
+ transaction,
45
+ serializedTransaction
46
+ };
47
+ }
48
+ const addSignatureToTransaction = ({ transaction, signature, signerPublicKey })=>{
49
+ transaction.addSignature(signerPublicKey, Buffer.from(signature));
50
+ return transaction;
51
+ };
52
+ async function sendTransaction({ signedTransaction, rpcUrl = 'https://api.devnet.solana.com' }) {
53
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
54
+ const txid = await connection.sendRawTransaction(Buffer.from(signedTransaction));
55
+ return txid;
56
+ }
57
+
58
+ class DynamicSvmWalletClient extends node.DynamicWalletClient {
59
+ /**
60
+ * Creates a wallet account on the Solana chain
61
+ *
62
+ * @param thresholdSignatureScheme The threshold signature scheme to use
63
+ * @returns The account address, public key hex, raw public key, and client key shares
64
+ */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
65
+ try {
66
+ let ceremonyCeremonyCompleteResolver;
67
+ const ceremonyCompletePromise = new Promise((resolve)=>{
68
+ ceremonyCeremonyCompleteResolver = resolve;
69
+ });
70
+ const { rawPublicKey, externalServerKeyShares } = await this.keyGen({
71
+ chainName: this.chainName,
72
+ thresholdSignatureScheme,
73
+ onError,
74
+ onCeremonyComplete: (accountAddress, walletId)=>{
75
+ // update wallet map
76
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
77
+ accountAddress,
78
+ walletId,
79
+ chainName: this.chainName,
80
+ thresholdSignatureScheme,
81
+ externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
82
+ });
83
+ this.logger.debug('walletMap updated for wallet', {
84
+ context: {
85
+ accountAddress,
86
+ walletId,
87
+ walletMap: this.walletMap
88
+ }
89
+ });
90
+ ceremonyCeremonyCompleteResolver(undefined);
91
+ }
92
+ });
93
+ // Wait for the ceremony to complete before proceeding
94
+ await ceremonyCompletePromise;
95
+ if (!rawPublicKey || !(rawPublicKey instanceof Uint8Array)) {
96
+ throw new Error('Raw public key is not a Uint8Array');
97
+ }
98
+ if (!externalServerKeyShares) {
99
+ throw new Error('Error creating wallet account');
100
+ }
101
+ const { accountAddress } = await this.deriveAccountAddress(rawPublicKey);
102
+ await this.storeEncryptedBackupByWalletWithRetry({
103
+ accountAddress,
104
+ externalServerKeyShares,
105
+ password
106
+ });
107
+ return {
108
+ accountAddress,
109
+ rawPublicKey: rawPublicKey,
110
+ externalServerKeyShares
111
+ };
112
+ } catch (error) {
113
+ this.logger.error('Error in createWalletAccount:', error);
114
+ throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
115
+ }
116
+ }
117
+ // Function to properly derive account address
118
+ async deriveAccountAddress(rawPublicKey) {
119
+ const pubKey = new web3_js.PublicKey(rawPublicKey);
120
+ const fromKey = pubKey.toBase58();
121
+ const accountAddress = fromKey;
122
+ return {
123
+ accountAddress
124
+ };
125
+ }
126
+ /**
127
+ * This function takes a message and returns it after being signed with MPC
128
+ *
129
+ * @param message The message to sign (Uint8Array)
130
+ * @param accountAddress Solana address (base58 encoded)
131
+ * @param password The password for encrypted backup shares
132
+ */ async signMessage({ message, accountAddress, password = undefined }) {
133
+ await this.verifyPassword({
134
+ accountAddress,
135
+ password,
136
+ walletOperation: node.WalletOperation.SIGN_MESSAGE
137
+ });
138
+ if (!accountAddress) {
139
+ throw new Error('Account address is required');
140
+ }
141
+ try {
142
+ const signatureEd25519 = await this.sign({
143
+ message,
144
+ accountAddress: accountAddress,
145
+ chainName: this.chainName,
146
+ password
147
+ });
148
+ const base58Signature = new web3_js.PublicKey(signatureEd25519).toBase58();
149
+ return base58Signature;
150
+ } catch (error) {
151
+ this.logger.error('Error signing message:', error);
152
+ throw error;
153
+ }
154
+ }
155
+ async signTransaction({ senderAddress, transaction, password = undefined }) {
156
+ await this.verifyPassword({
157
+ accountAddress: senderAddress,
158
+ password,
159
+ walletOperation: node.WalletOperation.SIGN_TRANSACTION
160
+ });
161
+ try {
162
+ let messageToSign;
163
+ if (transaction instanceof web3_js.VersionedTransaction) {
164
+ // For versioned transactions, we need to sign the message directly
165
+ const messageBytes = transaction.message.serialize();
166
+ messageToSign = Buffer.from(messageBytes).toString('hex');
167
+ } else {
168
+ // For legacy transactions, serialize the message
169
+ const messageBytes = transaction.serializeMessage();
170
+ messageToSign = Buffer.from(messageBytes).toString('hex');
171
+ }
172
+ const signatureEd25519 = await this.sign({
173
+ message: messageToSign,
174
+ accountAddress: senderAddress,
175
+ chainName: this.chainName,
176
+ password
177
+ });
178
+ if (!signatureEd25519) {
179
+ throw new Error('Signature is undefined');
180
+ }
181
+ const senderPublicKey = new web3_js.PublicKey(senderAddress);
182
+ const signedTransaction = addSignatureToTransaction({
183
+ transaction,
184
+ signature: signatureEd25519,
185
+ signerPublicKey: senderPublicKey
186
+ });
187
+ return signedTransaction;
188
+ } catch (error) {
189
+ this.logger.error('Error in signTransaction:', error);
190
+ if (error instanceof Error) {
191
+ this.logger.error('Error details:', error);
192
+ }
193
+ throw error;
194
+ }
195
+ }
196
+ /**
197
+ * Exports the private key for a given account address
198
+ *
199
+ * @param accountAddress The account address to export the private key for
200
+ * @param password The password for encrypted backup shares
201
+ * @returns The private key
202
+ */ async exportPrivateKey({ accountAddress, password = undefined }) {
203
+ const { derivedPrivateKey } = await this.exportKey({
204
+ accountAddress,
205
+ chainName: this.chainName,
206
+ password
207
+ });
208
+ if (!derivedPrivateKey) {
209
+ throw new Error('Derived private key is undefined');
210
+ }
211
+ const encodedPrivateKey = new web3_js.PublicKey(derivedPrivateKey).toBase58();
212
+ return {
213
+ derivedPrivateKey: encodedPrivateKey
214
+ };
215
+ }
216
+ /**
217
+ * Exports the private key for a given account address
218
+ *
219
+ * @param keyShares The key shares to export the private key for
220
+ * @returns The private key
221
+ */ async offlineExportPrivateKey({ keyShares, derivationPath }) {
222
+ const { derivedPrivateKey } = await this.offlineExportKey({
223
+ chainName: this.chainName,
224
+ keyShares,
225
+ derivationPath
226
+ });
227
+ return {
228
+ derivedPrivateKey
229
+ };
230
+ }
231
+ /**
232
+ * Converts the private key to a hex string
233
+ *
234
+ * @param privateKey The private key to convert
235
+ * @returns The hex string
236
+ */ decodePrivateKeyForSolana(privateKey) {
237
+ const decoded = new web3_js.PublicKey(privateKey).toBase58();
238
+ const slicedBytes = decoded.slice(0, 32);
239
+ return Buffer.from(slicedBytes).toString('hex');
240
+ }
241
+ getPublicKeyFromPrivateKey(privateKey) {
242
+ const privateKeyBytes = new web3_js.PublicKey(privateKey).toBase58();
243
+ const keypair = web3_js.Keypair.fromSecretKey(Buffer.from(privateKeyBytes));
244
+ const publicKeyBase58 = keypair.publicKey.toBase58();
245
+ return publicKeyBase58;
246
+ }
247
+ encodePublicKey(publicKey) {
248
+ const pubKey = new web3_js.PublicKey(publicKey);
249
+ const fromKey = pubKey.toBase58();
250
+ return fromKey;
251
+ }
252
+ /**
253
+ * Imports the private key for a given account address
254
+ *
255
+ * @param privateKey The private key to import
256
+ * @param chainName The chain name to import the private key for
257
+ * @param thresholdSignatureScheme The threshold signature scheme to use
258
+ * @param password The password for encrypted backup shares
259
+ * @returns The account address, raw public key, and client key shares
260
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError }) {
261
+ let ceremonyCeremonyCompleteResolver;
262
+ const ceremonyCompletePromise = new Promise((resolve)=>{
263
+ ceremonyCeremonyCompleteResolver = resolve;
264
+ });
265
+ //get public key from private key
266
+ const publicKey = this.getPublicKeyFromPrivateKey(privateKey);
267
+ const formattedPrivateKey = await this.decodePrivateKeyForSolana(privateKey);
268
+ const { rawPublicKey, externalServerKeyShares } = await this.importRawPrivateKey({
269
+ chainName,
270
+ privateKey: formattedPrivateKey,
271
+ thresholdSignatureScheme,
272
+ onError,
273
+ onCeremonyComplete: (accountAddress, walletId)=>{
274
+ // update wallet map
275
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
276
+ accountAddress,
277
+ walletId,
278
+ chainName: this.chainName,
279
+ thresholdSignatureScheme,
280
+ externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
281
+ });
282
+ ceremonyCeremonyCompleteResolver(undefined);
283
+ }
284
+ });
285
+ // Wait for the ceremony to complete before proceeding
286
+ await ceremonyCompletePromise;
287
+ if (!rawPublicKey || !externalServerKeyShares) {
288
+ throw new Error('Error creating wallet account');
289
+ }
290
+ const { accountAddress } = await this.deriveAccountAddress(rawPublicKey);
291
+ if (accountAddress !== publicKey) {
292
+ throw new Error(`Public key mismatch: derived address ${accountAddress} !== public key ${publicKey}`);
293
+ }
294
+ await this.storeEncryptedBackupByWalletWithRetry({
295
+ accountAddress,
296
+ externalServerKeyShares,
297
+ password
298
+ });
299
+ return {
300
+ accountAddress,
301
+ rawPublicKey: rawPublicKey,
302
+ externalServerKeyShares
303
+ };
304
+ }
305
+ async getSvmWallets() {
306
+ const wallets = await this.getWallets();
307
+ const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
308
+ return svmWallets;
309
+ }
310
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl }){
311
+ super({
312
+ environmentId,
313
+ baseApiUrl,
314
+ baseMPCRelayApiUrl
315
+ }), this.chainName = 'SVM';
316
+ }
317
+ }
318
+
319
+ exports.DynamicSvmWalletClient = DynamicSvmWalletClient;
320
+ exports.addSignatureToTransaction = addSignatureToTransaction;
321
+ exports.createSolanaTransaction = createSolanaTransaction;
322
+ exports.getBalance = getBalance;
323
+ exports.sendTransaction = sendTransaction;
package/index.esm.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/index.esm.js ADDED
@@ -0,0 +1,317 @@
1
+ import { SOLANA_RPC_URL, DynamicWalletClient, getExternalServerKeyShareBackupInfo, WalletOperation } from '@dynamic-labs-wallet/node';
2
+ import { Connection, PublicKey, Transaction, SystemProgram, VersionedTransaction, Keypair } from '@solana/web3.js';
3
+
4
+ function _extends() {
5
+ _extends = Object.assign || function assign(target) {
6
+ for(var i = 1; i < arguments.length; i++){
7
+ var source = arguments[i];
8
+ for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
9
+ }
10
+ return target;
11
+ };
12
+ return _extends.apply(this, arguments);
13
+ }
14
+
15
+ const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
16
+
17
+ async function getBalance({ address, rpcUrl = SOLANA_RPC_URL }) {
18
+ const connection = new Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
19
+ const balance = await connection.getBalance(new PublicKey(address));
20
+ return balance;
21
+ }
22
+ async function createSolanaTransaction({ senderSolanaAddress, amount, to, rpcUrl = 'https://api.devnet.solana.com' }) {
23
+ const connection = new Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
24
+ const balance = await getBalance({
25
+ address: senderSolanaAddress,
26
+ rpcUrl
27
+ });
28
+ if (balance < amount * 1e9) {
29
+ throw new Error('Insufficient balance');
30
+ }
31
+ const fromPubkey = new PublicKey(senderSolanaAddress);
32
+ const transaction = new Transaction().add(SystemProgram.transfer({
33
+ fromPubkey: fromPubkey,
34
+ toPubkey: new PublicKey(to),
35
+ lamports: amount * 1e9
36
+ }));
37
+ const { blockhash } = await connection.getLatestBlockhash();
38
+ transaction.recentBlockhash = blockhash;
39
+ transaction.feePayer = fromPubkey;
40
+ const serializedTransaction = transaction.serializeMessage();
41
+ return {
42
+ transaction,
43
+ serializedTransaction
44
+ };
45
+ }
46
+ const addSignatureToTransaction = ({ transaction, signature, signerPublicKey })=>{
47
+ transaction.addSignature(signerPublicKey, Buffer.from(signature));
48
+ return transaction;
49
+ };
50
+ async function sendTransaction({ signedTransaction, rpcUrl = 'https://api.devnet.solana.com' }) {
51
+ const connection = new Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
52
+ const txid = await connection.sendRawTransaction(Buffer.from(signedTransaction));
53
+ return txid;
54
+ }
55
+
56
+ class DynamicSvmWalletClient extends DynamicWalletClient {
57
+ /**
58
+ * Creates a wallet account on the Solana chain
59
+ *
60
+ * @param thresholdSignatureScheme The threshold signature scheme to use
61
+ * @returns The account address, public key hex, raw public key, and client key shares
62
+ */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
63
+ try {
64
+ let ceremonyCeremonyCompleteResolver;
65
+ const ceremonyCompletePromise = new Promise((resolve)=>{
66
+ ceremonyCeremonyCompleteResolver = resolve;
67
+ });
68
+ const { rawPublicKey, externalServerKeyShares } = await this.keyGen({
69
+ chainName: this.chainName,
70
+ thresholdSignatureScheme,
71
+ onError,
72
+ onCeremonyComplete: (accountAddress, walletId)=>{
73
+ // update wallet map
74
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
75
+ accountAddress,
76
+ walletId,
77
+ chainName: this.chainName,
78
+ thresholdSignatureScheme,
79
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
80
+ });
81
+ this.logger.debug('walletMap updated for wallet', {
82
+ context: {
83
+ accountAddress,
84
+ walletId,
85
+ walletMap: this.walletMap
86
+ }
87
+ });
88
+ ceremonyCeremonyCompleteResolver(undefined);
89
+ }
90
+ });
91
+ // Wait for the ceremony to complete before proceeding
92
+ await ceremonyCompletePromise;
93
+ if (!rawPublicKey || !(rawPublicKey instanceof Uint8Array)) {
94
+ throw new Error('Raw public key is not a Uint8Array');
95
+ }
96
+ if (!externalServerKeyShares) {
97
+ throw new Error('Error creating wallet account');
98
+ }
99
+ const { accountAddress } = await this.deriveAccountAddress(rawPublicKey);
100
+ await this.storeEncryptedBackupByWalletWithRetry({
101
+ accountAddress,
102
+ externalServerKeyShares,
103
+ password
104
+ });
105
+ return {
106
+ accountAddress,
107
+ rawPublicKey: rawPublicKey,
108
+ externalServerKeyShares
109
+ };
110
+ } catch (error) {
111
+ this.logger.error('Error in createWalletAccount:', error);
112
+ throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
113
+ }
114
+ }
115
+ // Function to properly derive account address
116
+ async deriveAccountAddress(rawPublicKey) {
117
+ const pubKey = new PublicKey(rawPublicKey);
118
+ const fromKey = pubKey.toBase58();
119
+ const accountAddress = fromKey;
120
+ return {
121
+ accountAddress
122
+ };
123
+ }
124
+ /**
125
+ * This function takes a message and returns it after being signed with MPC
126
+ *
127
+ * @param message The message to sign (Uint8Array)
128
+ * @param accountAddress Solana address (base58 encoded)
129
+ * @param password The password for encrypted backup shares
130
+ */ async signMessage({ message, accountAddress, password = undefined }) {
131
+ await this.verifyPassword({
132
+ accountAddress,
133
+ password,
134
+ walletOperation: WalletOperation.SIGN_MESSAGE
135
+ });
136
+ if (!accountAddress) {
137
+ throw new Error('Account address is required');
138
+ }
139
+ try {
140
+ const signatureEd25519 = await this.sign({
141
+ message,
142
+ accountAddress: accountAddress,
143
+ chainName: this.chainName,
144
+ password
145
+ });
146
+ const base58Signature = new PublicKey(signatureEd25519).toBase58();
147
+ return base58Signature;
148
+ } catch (error) {
149
+ this.logger.error('Error signing message:', error);
150
+ throw error;
151
+ }
152
+ }
153
+ async signTransaction({ senderAddress, transaction, password = undefined }) {
154
+ await this.verifyPassword({
155
+ accountAddress: senderAddress,
156
+ password,
157
+ walletOperation: WalletOperation.SIGN_TRANSACTION
158
+ });
159
+ try {
160
+ let messageToSign;
161
+ if (transaction instanceof VersionedTransaction) {
162
+ // For versioned transactions, we need to sign the message directly
163
+ const messageBytes = transaction.message.serialize();
164
+ messageToSign = Buffer.from(messageBytes).toString('hex');
165
+ } else {
166
+ // For legacy transactions, serialize the message
167
+ const messageBytes = transaction.serializeMessage();
168
+ messageToSign = Buffer.from(messageBytes).toString('hex');
169
+ }
170
+ const signatureEd25519 = await this.sign({
171
+ message: messageToSign,
172
+ accountAddress: senderAddress,
173
+ chainName: this.chainName,
174
+ password
175
+ });
176
+ if (!signatureEd25519) {
177
+ throw new Error('Signature is undefined');
178
+ }
179
+ const senderPublicKey = new PublicKey(senderAddress);
180
+ const signedTransaction = addSignatureToTransaction({
181
+ transaction,
182
+ signature: signatureEd25519,
183
+ signerPublicKey: senderPublicKey
184
+ });
185
+ return signedTransaction;
186
+ } catch (error) {
187
+ this.logger.error('Error in signTransaction:', error);
188
+ if (error instanceof Error) {
189
+ this.logger.error('Error details:', error);
190
+ }
191
+ throw error;
192
+ }
193
+ }
194
+ /**
195
+ * Exports the private key for a given account address
196
+ *
197
+ * @param accountAddress The account address to export the private key for
198
+ * @param password The password for encrypted backup shares
199
+ * @returns The private key
200
+ */ async exportPrivateKey({ accountAddress, password = undefined }) {
201
+ const { derivedPrivateKey } = await this.exportKey({
202
+ accountAddress,
203
+ chainName: this.chainName,
204
+ password
205
+ });
206
+ if (!derivedPrivateKey) {
207
+ throw new Error('Derived private key is undefined');
208
+ }
209
+ const encodedPrivateKey = new PublicKey(derivedPrivateKey).toBase58();
210
+ return {
211
+ derivedPrivateKey: encodedPrivateKey
212
+ };
213
+ }
214
+ /**
215
+ * Exports the private key for a given account address
216
+ *
217
+ * @param keyShares The key shares to export the private key for
218
+ * @returns The private key
219
+ */ async offlineExportPrivateKey({ keyShares, derivationPath }) {
220
+ const { derivedPrivateKey } = await this.offlineExportKey({
221
+ chainName: this.chainName,
222
+ keyShares,
223
+ derivationPath
224
+ });
225
+ return {
226
+ derivedPrivateKey
227
+ };
228
+ }
229
+ /**
230
+ * Converts the private key to a hex string
231
+ *
232
+ * @param privateKey The private key to convert
233
+ * @returns The hex string
234
+ */ decodePrivateKeyForSolana(privateKey) {
235
+ const decoded = new PublicKey(privateKey).toBase58();
236
+ const slicedBytes = decoded.slice(0, 32);
237
+ return Buffer.from(slicedBytes).toString('hex');
238
+ }
239
+ getPublicKeyFromPrivateKey(privateKey) {
240
+ const privateKeyBytes = new PublicKey(privateKey).toBase58();
241
+ const keypair = Keypair.fromSecretKey(Buffer.from(privateKeyBytes));
242
+ const publicKeyBase58 = keypair.publicKey.toBase58();
243
+ return publicKeyBase58;
244
+ }
245
+ encodePublicKey(publicKey) {
246
+ const pubKey = new PublicKey(publicKey);
247
+ const fromKey = pubKey.toBase58();
248
+ return fromKey;
249
+ }
250
+ /**
251
+ * Imports the private key for a given account address
252
+ *
253
+ * @param privateKey The private key to import
254
+ * @param chainName The chain name to import the private key for
255
+ * @param thresholdSignatureScheme The threshold signature scheme to use
256
+ * @param password The password for encrypted backup shares
257
+ * @returns The account address, raw public key, and client key shares
258
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError }) {
259
+ let ceremonyCeremonyCompleteResolver;
260
+ const ceremonyCompletePromise = new Promise((resolve)=>{
261
+ ceremonyCeremonyCompleteResolver = resolve;
262
+ });
263
+ //get public key from private key
264
+ const publicKey = this.getPublicKeyFromPrivateKey(privateKey);
265
+ const formattedPrivateKey = await this.decodePrivateKeyForSolana(privateKey);
266
+ const { rawPublicKey, externalServerKeyShares } = await this.importRawPrivateKey({
267
+ chainName,
268
+ privateKey: formattedPrivateKey,
269
+ thresholdSignatureScheme,
270
+ onError,
271
+ onCeremonyComplete: (accountAddress, walletId)=>{
272
+ // update wallet map
273
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
274
+ accountAddress,
275
+ walletId,
276
+ chainName: this.chainName,
277
+ thresholdSignatureScheme,
278
+ externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
279
+ });
280
+ ceremonyCeremonyCompleteResolver(undefined);
281
+ }
282
+ });
283
+ // Wait for the ceremony to complete before proceeding
284
+ await ceremonyCompletePromise;
285
+ if (!rawPublicKey || !externalServerKeyShares) {
286
+ throw new Error('Error creating wallet account');
287
+ }
288
+ const { accountAddress } = await this.deriveAccountAddress(rawPublicKey);
289
+ if (accountAddress !== publicKey) {
290
+ throw new Error(`Public key mismatch: derived address ${accountAddress} !== public key ${publicKey}`);
291
+ }
292
+ await this.storeEncryptedBackupByWalletWithRetry({
293
+ accountAddress,
294
+ externalServerKeyShares,
295
+ password
296
+ });
297
+ return {
298
+ accountAddress,
299
+ rawPublicKey: rawPublicKey,
300
+ externalServerKeyShares
301
+ };
302
+ }
303
+ async getSvmWallets() {
304
+ const wallets = await this.getWallets();
305
+ const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
306
+ return svmWallets;
307
+ }
308
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl }){
309
+ super({
310
+ environmentId,
311
+ baseApiUrl,
312
+ baseMPCRelayApiUrl
313
+ }), this.chainName = 'SVM';
314
+ }
315
+ }
316
+
317
+ export { DynamicSvmWalletClient, addSignatureToTransaction, createSolanaTransaction, getBalance, sendTransaction };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@dynamic-labs-wallet/node-svm",
3
+ "version": "0.0.0-beta-191.1",
4
+ "license": "MIT",
5
+ "dependencies": {
6
+ "@dynamic-labs-wallet/node": "0.0.0-beta-191.1",
7
+ "@solana/web3.js": "^1.98.2"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "nx": {
13
+ "sourceRoot": "packages/node-svm/src",
14
+ "projectType": "library",
15
+ "name": "node-svm",
16
+ "targets": {
17
+ "build": {}
18
+ }
19
+ },
20
+ "main": "./index.cjs.js",
21
+ "module": "./index.esm.js",
22
+ "types": "./index.esm.d.ts",
23
+ "exports": {
24
+ "./package.json": "./package.json",
25
+ ".": {
26
+ "types": "./index.esm.d.ts",
27
+ "import": "./index.esm.js",
28
+ "require": "./index.cjs.js",
29
+ "default": "./index.cjs.js"
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,103 @@
1
+ import { ServerKeyShare, DynamicWalletClient, Ed25519KeygenResult, ThresholdSignatureScheme } from '@dynamic-labs-wallet/node';
2
+ import { Transaction, VersionedTransaction } from '@solana/web3.js';
3
+ export declare class DynamicSvmWalletClient extends DynamicWalletClient {
4
+ readonly chainName = "SVM";
5
+ accountAddress?: string;
6
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, }: {
7
+ environmentId: string;
8
+ authToken: string;
9
+ baseApiUrl?: string;
10
+ baseMPCRelayApiUrl?: string;
11
+ });
12
+ /**
13
+ * Creates a wallet account on the Solana chain
14
+ *
15
+ * @param thresholdSignatureScheme The threshold signature scheme to use
16
+ * @returns The account address, public key hex, raw public key, and client key shares
17
+ */
18
+ createWalletAccount({ thresholdSignatureScheme, password, onError, }: {
19
+ thresholdSignatureScheme: ThresholdSignatureScheme;
20
+ password?: string;
21
+ onError?: (error: Error) => void;
22
+ }): Promise<{
23
+ accountAddress: string;
24
+ rawPublicKey: Uint8Array;
25
+ externalServerKeyShares: ServerKeyShare[];
26
+ }>;
27
+ deriveAccountAddress(rawPublicKey: Uint8Array): Promise<{
28
+ accountAddress: string;
29
+ }>;
30
+ /**
31
+ * This function takes a message and returns it after being signed with MPC
32
+ *
33
+ * @param message The message to sign (Uint8Array)
34
+ * @param accountAddress Solana address (base58 encoded)
35
+ * @param password The password for encrypted backup shares
36
+ */
37
+ signMessage({ message, accountAddress, password, }: {
38
+ message: string;
39
+ accountAddress: string;
40
+ password?: string;
41
+ }): Promise<string>;
42
+ signTransaction({ senderAddress, transaction, password, }: {
43
+ senderAddress: string;
44
+ transaction: VersionedTransaction | Transaction;
45
+ password?: string;
46
+ }): Promise<VersionedTransaction | Transaction>;
47
+ /**
48
+ * Exports the private key for a given account address
49
+ *
50
+ * @param accountAddress The account address to export the private key for
51
+ * @param password The password for encrypted backup shares
52
+ * @returns The private key
53
+ */
54
+ exportPrivateKey({ accountAddress, password, }: {
55
+ accountAddress: string;
56
+ password?: string;
57
+ }): Promise<{
58
+ derivedPrivateKey: string;
59
+ }>;
60
+ /**
61
+ * Exports the private key for a given account address
62
+ *
63
+ * @param keyShares The key shares to export the private key for
64
+ * @returns The private key
65
+ */
66
+ offlineExportPrivateKey({ keyShares, derivationPath, }: {
67
+ keyShares: Ed25519KeygenResult[];
68
+ derivationPath?: string;
69
+ }): Promise<{
70
+ derivedPrivateKey: string | undefined;
71
+ }>;
72
+ /**
73
+ * Converts the private key to a hex string
74
+ *
75
+ * @param privateKey The private key to convert
76
+ * @returns The hex string
77
+ */
78
+ decodePrivateKeyForSolana(privateKey: string): string;
79
+ getPublicKeyFromPrivateKey(privateKey: string): string;
80
+ encodePublicKey(publicKey: Uint8Array): string;
81
+ /**
82
+ * Imports the private key for a given account address
83
+ *
84
+ * @param privateKey The private key to import
85
+ * @param chainName The chain name to import the private key for
86
+ * @param thresholdSignatureScheme The threshold signature scheme to use
87
+ * @param password The password for encrypted backup shares
88
+ * @returns The account address, raw public key, and client key shares
89
+ */
90
+ importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, onError, }: {
91
+ privateKey: string;
92
+ chainName: string;
93
+ thresholdSignatureScheme: ThresholdSignatureScheme;
94
+ password?: string;
95
+ onError?: (error: Error) => void;
96
+ }): Promise<{
97
+ accountAddress: string;
98
+ rawPublicKey: Uint8Array | undefined;
99
+ externalServerKeyShares: ServerKeyShare[];
100
+ }>;
101
+ getSvmWallets(): Promise<any>;
102
+ }
103
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EAGzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,WAAW,EACX,oBAAoB,EAErB,MAAM,iBAAiB,CAAC;AAIzB,qBAAa,sBAAuB,SAAQ,mBAAmB;IAC7D,QAAQ,CAAC,SAAS,SAAS;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;gBAEZ,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,GACnB,EAAE;QACD,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B;IAQD;;;;;OAKG;IACG,mBAAmB,CAAC,EACxB,wBAAwB,EACxB,QAAoB,EACpB,OAAO,GACR,EAAE;QACD,wBAAwB,EAAE,wBAAwB,CAAC;QACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;KAClC,GAAG,OAAO,CAAC;QACV,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,UAAU,CAAC;QACzB,uBAAuB,EAAE,cAAc,EAAE,CAAC;KAC3C,CAAC;IAkEI,oBAAoB,CAAC,YAAY,EAAE,UAAU;;;IASnD;;;;;;OAMG;IACG,WAAW,CAAC,EAChB,OAAO,EACP,cAAc,EACd,QAAoB,GACrB,EAAE;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IA4BK,eAAe,CAAC,EACpB,aAAa,EACb,WAAW,EACX,QAAoB,GACrB,EAAE;QACD,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,oBAAoB,GAAG,WAAW,CAAC;QAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,oBAAoB,GAAG,WAAW,CAAC;IAgD/C;;;;;;OAMG;IACG,gBAAgB,CAAC,EACrB,cAAc,EACd,QAAoB,GACrB,EAAE;QACD,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;;;IAaD;;;;;OAKG;IACG,uBAAuB,CAAC,EAC5B,SAAS,EACT,cAAc,GACf,EAAE;QACD,SAAS,EAAE,mBAAmB,EAAE,CAAC;QACjC,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB;;;IASD;;;;;OAKG;IACH,yBAAyB,CAAC,UAAU,EAAE,MAAM;IAM5C,0BAA0B,CAAC,UAAU,EAAE,MAAM;IAQ7C,eAAe,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM;IAM9C;;;;;;;;OAQG;IACG,gBAAgB,CAAC,EACrB,UAAU,EACV,SAAS,EACT,wBAAwB,EACxB,QAAoB,EACpB,OAAO,GACR,EAAE;QACD,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,wBAAwB,EAAE,wBAAwB,CAAC;QACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;KAClC,GAAG,OAAO,CAAC;QACV,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,UAAU,GAAG,SAAS,CAAC;QACrC,uBAAuB,EAAE,cAAc,EAAE,CAAC;KAC3C,CAAC;IA8DI,aAAa;CAOpB"}
@@ -0,0 +1,2 @@
1
+ export declare const ERROR_CREATE_WALLET_ACCOUNT = "Error creating svm wallet account";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/client/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,sCAAsC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './client';
2
+ export * from './utils';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ export declare function getBalance({ address, rpcUrl, }: {
3
+ address: string;
4
+ rpcUrl?: string;
5
+ }): Promise<number>;
6
+ export declare function createSolanaTransaction({ senderSolanaAddress, amount, to, rpcUrl, }: {
7
+ senderSolanaAddress: string;
8
+ amount: number;
9
+ to: string;
10
+ rpcUrl?: string;
11
+ }): Promise<{
12
+ transaction: Transaction;
13
+ serializedTransaction: Buffer;
14
+ }>;
15
+ export declare const addSignatureToTransaction: ({ transaction, signature, signerPublicKey, }: {
16
+ transaction: Transaction | VersionedTransaction;
17
+ signature: Uint8Array;
18
+ signerPublicKey: PublicKey;
19
+ }) => VersionedTransaction | Transaction;
20
+ export declare function sendTransaction({ signedTransaction, rpcUrl, }: {
21
+ signedTransaction: Uint8Array;
22
+ rpcUrl?: string;
23
+ }): Promise<string>;
24
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/client/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,SAAS,EAET,WAAW,EACX,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AAEzB,wBAAsB,UAAU,CAAC,EAC/B,OAAO,EACP,MAAuB,GACxB,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,mBAIA;AAED,wBAAsB,uBAAuB,CAAC,EAC5C,mBAAmB,EACnB,MAAM,EACN,EAAE,EACF,MAAwC,GACzC,EAAE;IACD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;;;GAwBA;AAED,eAAO,MAAM,yBAAyB,iDAInC;IACD,WAAW,EAAE,WAAW,GAAG,oBAAoB,CAAC;IAChD,SAAS,EAAE,UAAU,CAAC;IACtB,eAAe,EAAE,SAAS,CAAC;CAC5B,KAAG,oBAAoB,GAAG,WAG1B,CAAC;AAEF,wBAAsB,eAAe,CAAC,EACpC,iBAAiB,EACjB,MAAwC,GACzC,EAAE;IACD,iBAAiB,EAAE,UAAU,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,mBAMA"}
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './client/index';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}