@dynamic-labs-wallet/node-svm 0.0.0-preview.160.0 → 0.0.1-paolo-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.js CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  var node = require('@dynamic-labs-wallet/node');
4
4
  var web3_js = require('@solana/web3.js');
5
+ var logger$1 = require('@dynamic-labs/logger');
6
+ var axios = require('axios');
7
+ var core = require('@dynamic-labs-wallet/core');
5
8
 
6
9
  function _extends() {
7
10
  _extends = Object.assign || function assign(target) {
@@ -16,95 +19,163 @@ function _extends() {
16
19
 
17
20
  const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
18
21
 
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;
22
+ // Base58 encoding/decoding (Bitcoin alphabet) without external dependencies
23
+ // Implementation adapted from the reference algorithm; suitable for keys/signatures
24
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
25
+ const ALPHABET_MAP = {};
26
+ for(let i = 0; i < ALPHABET.length; i++)ALPHABET_MAP[ALPHABET[i]] = i;
27
+ function encodeBase58(source) {
28
+ const bytes = source instanceof Uint8Array ? source : new Uint8Array(source);
29
+ if (bytes.length === 0) return '';
30
+ // Count leading zeros
31
+ let zeros = 0;
32
+ while(zeros < bytes.length && bytes[zeros] === 0)zeros++;
33
+ // Allocate enough space in big-endian base58 representation.
34
+ // log(256) / log(58), rounded up.
35
+ const size = (bytes.length - zeros) * 138 / 100 + 1 >>> 0;
36
+ const b58 = new Uint8Array(size);
37
+ let length = 0;
38
+ for(let i = zeros; i < bytes.length; i++){
39
+ let carry = bytes[i];
40
+ let j = 0;
41
+ for(let k = size - 1; (carry !== 0 || j < length) && k >= 0; k--, j++){
42
+ carry += 256 * b58[k] >>> 0;
43
+ b58[k] = carry % 58 >>> 0;
44
+ carry = carry / 58 >>> 0;
45
+ }
46
+ length = j;
47
+ }
48
+ // Skip leading zeros in base58 result
49
+ let it = size - length;
50
+ while(it < size && b58[it] === 0)it++;
51
+ // Translate the result into a string.
52
+ let str = '';
53
+ for(let i = 0; i < zeros; i++)str += '1';
54
+ for(; it < size; it++)str += ALPHABET[b58[it]];
55
+ return str;
23
56
  }
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');
57
+ function decodeBase58(str) {
58
+ if (str.length === 0) return new Uint8Array();
59
+ // Count leading zeros
60
+ let zeros = 0;
61
+ while(zeros < str.length && str[zeros] === '1')zeros++;
62
+ // Allocate enough space in big-endian base256 representation.
63
+ // log(58) / log(256), rounded up.
64
+ const size = (str.length - zeros) * 733 / 1000 + 1 >>> 0;
65
+ const b256 = new Uint8Array(size);
66
+ let length = 0;
67
+ for(let i = zeros; i < str.length; i++){
68
+ const value = ALPHABET_MAP[str[i]];
69
+ if (value === undefined) throw new Error('Invalid base58 character');
70
+ let carry = value;
71
+ let j = 0;
72
+ for(let k = size - 1; (carry !== 0 || j < length) && k >= 0; k--, j++){
73
+ carry += 58 * b256[k] >>> 0;
74
+ b256[k] = (carry & 0xff) >>> 0;
75
+ carry = carry >> 8 >>> 0;
76
+ }
77
+ length = j;
32
78
  }
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
- };
79
+ // Skip leading zeros in b256
80
+ let it = size - length;
81
+ while(it < size && b256[it] === 0)it++;
82
+ const out = new Uint8Array(zeros + (size - it));
83
+ out.fill(0, 0, zeros);
84
+ let j = zeros;
85
+ while(it < size)out[j++] = b256[it++];
86
+ return out;
47
87
  }
48
- const addSignatureToTransaction = ({ transaction, signature, signerPublicKey })=>{
49
- transaction.addSignature(signerPublicKey, Buffer.from(signature));
50
- return transaction;
88
+
89
+ const logger = new logger$1.Logger('DynamicWaasWalletClient');
90
+ const logError = ({ message, error, context })=>{
91
+ if (error instanceof axios.AxiosError) {
92
+ core.handleAxiosError(error, message, context, logger);
93
+ }
94
+ logger.error('[DynamicWaasWalletClient] Error in node-svm client', {
95
+ error: error instanceof Error ? error.message : String(error),
96
+ context
97
+ });
51
98
  };
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
99
 
100
+ // Helper: normalize bytes to hex without triggering Buffer.from(string, encoding) overload
101
+ const toHex = (bytes)=>(Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes)).toString('hex');
58
102
  class DynamicSvmWalletClient extends node.DynamicWalletClient {
59
103
  /**
60
104
  * Creates a wallet account on the Solana chain
61
105
  *
62
106
  * @param thresholdSignatureScheme The threshold signature scheme to use
63
107
  * @returns The account address, public key hex, raw public key, and client key shares
64
- */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
108
+ */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError, backUpToClientShareService = false }) {
65
109
  try {
110
+ let ceremonyCeremonyCompleteResolver;
111
+ const ceremonyCompletePromise = new Promise((resolve)=>{
112
+ ceremonyCeremonyCompleteResolver = resolve;
113
+ });
66
114
  const { rawPublicKey, externalServerKeyShares } = await this.keyGen({
67
115
  chainName: this.chainName,
68
116
  thresholdSignatureScheme,
69
117
  onError,
70
118
  onCeremonyComplete: (accountAddress, walletId)=>{
71
119
  // update wallet map
120
+ const chainConfig = node.getMPCChainConfig(this.chainName);
72
121
  this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
73
122
  accountAddress,
74
123
  walletId,
75
124
  chainName: this.chainName,
76
125
  thresholdSignatureScheme,
126
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
127
+ index,
128
+ value
129
+ ]))),
77
130
  externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
78
131
  });
132
+ this.logger.debug('walletMap updated for wallet', {
133
+ context: {
134
+ accountAddress,
135
+ walletId,
136
+ walletMap: this.walletMap
137
+ }
138
+ });
139
+ ceremonyCeremonyCompleteResolver(undefined);
79
140
  }
80
141
  });
81
- if (!rawPublicKey || !(rawPublicKey instanceof Uint8Array)) {
82
- throw new Error('Raw public key is not a Uint8Array');
142
+ // Wait for the ceremony to complete before proceeding
143
+ await ceremonyCompletePromise;
144
+ if (!rawPublicKey || !(rawPublicKey instanceof Uint8Array || typeof rawPublicKey === 'string')) {
145
+ throw new Error('Raw public key is not a Uint8Array or string' + typeof rawPublicKey);
83
146
  }
84
147
  if (!externalServerKeyShares) {
85
148
  throw new Error('Error creating wallet account');
86
149
  }
87
150
  const { accountAddress } = await this.deriveAccountAddress(rawPublicKey);
88
- void this.storeEncryptedBackupByWalletWithRetry({
151
+ await this.storeEncryptedBackupByWalletWithRetry({
89
152
  accountAddress,
90
153
  externalServerKeyShares,
91
- password
154
+ password,
155
+ backUpToClientShareService
92
156
  });
93
157
  return {
94
158
  accountAddress,
95
- rawPublicKey: rawPublicKey,
159
+ rawPublicKey,
96
160
  externalServerKeyShares
97
161
  };
98
162
  } catch (error) {
99
- this.logger.error('Error in createWalletAccount:', error);
163
+ logError({
164
+ message: ERROR_CREATE_WALLET_ACCOUNT,
165
+ error: error,
166
+ context: {}
167
+ });
100
168
  throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
101
169
  }
102
170
  }
103
171
  // Function to properly derive account address
104
172
  async deriveAccountAddress(rawPublicKey) {
105
- const pubKey = new web3_js.PublicKey(rawPublicKey);
106
- const fromKey = pubKey.toBase58();
107
- const accountAddress = fromKey;
173
+ function ensure32(u8) {
174
+ if (u8.length !== 32) throw new Error(`Invalid pubkey length: ${u8.length}`);
175
+ return u8;
176
+ }
177
+ const pubKeyBytes = typeof rawPublicKey === 'string' ? new Uint8Array(Buffer.from(rawPublicKey, 'hex')) : rawPublicKey;
178
+ const accountAddress = new web3_js.PublicKey(ensure32(pubKeyBytes)).toBase58();
108
179
  return {
109
180
  accountAddress
110
181
  };
@@ -115,67 +186,90 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
115
186
  * @param message The message to sign (Uint8Array)
116
187
  * @param accountAddress Solana address (base58 encoded)
117
188
  * @param password The password for encrypted backup shares
118
- */ async signMessage({ message, accountAddress, password = undefined }) {
119
- await this.verifyPassword({
120
- accountAddress,
121
- password,
122
- walletOperation: node.WalletOperation.SIGN_MESSAGE
123
- });
189
+ */ async signMessage({ message, accountAddress, password = undefined, externalServerKeyShares }) {
190
+ // Validate inputs early
124
191
  if (!accountAddress) {
125
192
  throw new Error('Account address is required');
126
193
  }
127
194
  try {
195
+ // Attempt to recover key shares from backup if not provided
196
+ await this.ensureKeySharesRecovered({
197
+ accountAddress,
198
+ password,
199
+ walletOperation: node.WalletOperation.SIGN_MESSAGE,
200
+ externalServerKeyShares,
201
+ errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.'
202
+ });
203
+ const messageBytes = typeof message === 'string' ? new TextEncoder().encode(message) : message;
204
+ const messageHex = toHex(messageBytes);
128
205
  const signatureEd25519 = await this.sign({
129
- message,
130
- accountAddress: accountAddress,
206
+ message: messageHex,
207
+ accountAddress,
131
208
  chainName: this.chainName,
132
- password
209
+ password,
210
+ externalServerKeyShares
133
211
  });
134
- const base58Signature = new web3_js.PublicKey(signatureEd25519).toBase58();
135
- return base58Signature;
212
+ return encodeBase58(signatureEd25519);
136
213
  } catch (error) {
137
- this.logger.error('Error signing message:', error);
214
+ logError({
215
+ message: 'Error signing message:',
216
+ error: error,
217
+ context: {
218
+ accountAddress
219
+ }
220
+ });
138
221
  throw error;
139
222
  }
140
223
  }
141
- async signTransaction({ senderAddress, transaction, password = undefined }) {
224
+ //todo:should txn just be a string?
225
+ async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares }) {
226
+ // Validate inputs early
227
+ if (!senderAddress) {
228
+ throw new Error('Sender address is required');
229
+ }
142
230
  await this.verifyPassword({
143
231
  accountAddress: senderAddress,
144
232
  password,
145
233
  walletOperation: node.WalletOperation.SIGN_TRANSACTION
146
234
  });
147
235
  try {
236
+ // Attempt to recover key shares from backup if not provided
237
+ await this.ensureKeySharesRecovered({
238
+ accountAddress: senderAddress,
239
+ password,
240
+ walletOperation: node.WalletOperation.SIGN_TRANSACTION,
241
+ externalServerKeyShares,
242
+ errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.'
243
+ });
148
244
  let messageToSign;
149
- if (transaction instanceof web3_js.VersionedTransaction) {
150
- // For versioned transactions, we need to sign the message directly
245
+ if (typeof transaction === 'string') {
246
+ messageToSign = transaction.startsWith('0x') ? transaction.slice(2) : transaction;
247
+ } else if (transaction instanceof web3_js.VersionedTransaction) {
151
248
  const messageBytes = transaction.message.serialize();
152
- messageToSign = Buffer.from(messageBytes).toString('hex');
249
+ messageToSign = toHex(messageBytes);
153
250
  } else {
154
- // For legacy transactions, serialize the message
155
251
  const messageBytes = transaction.serializeMessage();
156
- messageToSign = Buffer.from(messageBytes).toString('hex');
252
+ messageToSign = toHex(Buffer.isBuffer(messageBytes) ? messageBytes : messageBytes);
157
253
  }
158
254
  const signatureEd25519 = await this.sign({
159
255
  message: messageToSign,
160
256
  accountAddress: senderAddress,
161
257
  chainName: this.chainName,
162
- password
258
+ password,
259
+ externalServerKeyShares
163
260
  });
164
261
  if (!signatureEd25519) {
165
262
  throw new Error('Signature is undefined');
166
263
  }
167
- const senderPublicKey = new web3_js.PublicKey(senderAddress);
168
- const signedTransaction = addSignatureToTransaction({
169
- transaction,
170
- signature: signatureEd25519,
171
- signerPublicKey: senderPublicKey
172
- });
173
- return signedTransaction;
264
+ return encodeBase58(signatureEd25519);
174
265
  } catch (error) {
175
- this.logger.error('Error in signTransaction:', error);
176
- if (error instanceof Error) {
177
- this.logger.error('Error details:', error);
178
- }
266
+ logError({
267
+ message: 'Error in signTransaction:',
268
+ error: error,
269
+ context: {
270
+ senderAddress
271
+ }
272
+ });
179
273
  throw error;
180
274
  }
181
275
  }
@@ -185,19 +279,17 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
185
279
  * @param accountAddress The account address to export the private key for
186
280
  * @param password The password for encrypted backup shares
187
281
  * @returns The private key
188
- */ async exportPrivateKey({ accountAddress, password = undefined }) {
282
+ */ async exportPrivateKey({ accountAddress, password = undefined, externalServerKeyShares }) {
189
283
  const { derivedPrivateKey } = await this.exportKey({
190
284
  accountAddress,
191
285
  chainName: this.chainName,
192
- password
286
+ password,
287
+ externalServerKeyShares
193
288
  });
194
289
  if (!derivedPrivateKey) {
195
290
  throw new Error('Derived private key is undefined');
196
291
  }
197
- const encodedPrivateKey = new web3_js.PublicKey(derivedPrivateKey).toBase58();
198
- return {
199
- derivedPrivateKey: encodedPrivateKey
200
- };
292
+ return derivedPrivateKey;
201
293
  }
202
294
  /**
203
295
  * Exports the private key for a given account address
@@ -220,20 +312,19 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
220
312
  * @param privateKey The private key to convert
221
313
  * @returns The hex string
222
314
  */ decodePrivateKeyForSolana(privateKey) {
223
- const decoded = new web3_js.PublicKey(privateKey).toBase58();
224
- const slicedBytes = decoded.slice(0, 32);
225
- return Buffer.from(slicedBytes).toString('hex');
315
+ const decoded = decodeBase58(privateKey); // 64 bytes
316
+ if (decoded.length !== 64) throw new Error('Invalid Solana secret key length');
317
+ return Buffer.from(decoded.slice(0, 32)).toString('hex');
226
318
  }
227
319
  getPublicKeyFromPrivateKey(privateKey) {
228
- const privateKeyBytes = new web3_js.PublicKey(privateKey).toBase58();
229
- const keypair = web3_js.Keypair.fromSecretKey(Buffer.from(privateKeyBytes));
230
- const publicKeyBase58 = keypair.publicKey.toBase58();
231
- return publicKeyBase58;
320
+ const secret = decodeBase58(privateKey);
321
+ const keypair = web3_js.Keypair.fromSecretKey(secret);
322
+ return keypair.publicKey.toBase58();
232
323
  }
233
324
  encodePublicKey(publicKey) {
234
- const pubKey = new web3_js.PublicKey(publicKey);
235
- const fromKey = pubKey.toBase58();
236
- return fromKey;
325
+ // Ensure a plain Uint8Array is passed to PublicKey
326
+ const bytes = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
327
+ return new web3_js.PublicKey(bytes).toBase58();
237
328
  }
238
329
  /**
239
330
  * Imports the private key for a given account address
@@ -243,7 +334,11 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
243
334
  * @param thresholdSignatureScheme The threshold signature scheme to use
244
335
  * @param password The password for encrypted backup shares
245
336
  * @returns The account address, raw public key, and client key shares
246
- */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError }) {
337
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError, backUpToClientShareService = false }) {
338
+ let ceremonyCeremonyCompleteResolver;
339
+ const ceremonyCompletePromise = new Promise((resolve)=>{
340
+ ceremonyCeremonyCompleteResolver = resolve;
341
+ });
247
342
  //get public key from private key
248
343
  const publicKey = this.getPublicKeyFromPrivateKey(privateKey);
249
344
  const formattedPrivateKey = await this.decodePrivateKeyForSolana(privateKey);
@@ -254,15 +349,23 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
254
349
  onError,
255
350
  onCeremonyComplete: (accountAddress, walletId)=>{
256
351
  // update wallet map
352
+ const chainConfig = node.getMPCChainConfig(this.chainName);
257
353
  this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
258
354
  accountAddress,
259
355
  walletId,
260
356
  chainName: this.chainName,
261
357
  thresholdSignatureScheme,
358
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
359
+ index,
360
+ value
361
+ ]))),
262
362
  externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
263
363
  });
364
+ ceremonyCeremonyCompleteResolver(undefined);
264
365
  }
265
366
  });
367
+ // Wait for the ceremony to complete before proceeding
368
+ await ceremonyCompletePromise;
266
369
  if (!rawPublicKey || !externalServerKeyShares) {
267
370
  throw new Error('Error creating wallet account');
268
371
  }
@@ -270,11 +373,11 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
270
373
  if (accountAddress !== publicKey) {
271
374
  throw new Error(`Public key mismatch: derived address ${accountAddress} !== public key ${publicKey}`);
272
375
  }
273
- // Backup the new wallet without waiting for the promise to resolve
274
- void this.storeEncryptedBackupByWalletWithRetry({
376
+ await this.storeEncryptedBackupByWalletWithRetry({
275
377
  accountAddress,
276
378
  externalServerKeyShares,
277
- password
379
+ password,
380
+ backUpToClientShareService
278
381
  });
279
382
  return {
280
383
  accountAddress,
@@ -287,17 +390,222 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
287
390
  const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
288
391
  return svmWallets;
289
392
  }
290
- constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl }){
393
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, enableMPCAccelerator }){
291
394
  super({
292
395
  environmentId,
293
396
  baseApiUrl,
294
- baseMPCRelayApiUrl
295
- }), this.chainName = 'SOL';
397
+ baseMPCRelayApiUrl,
398
+ enableMPCAccelerator
399
+ }), this.chainName = 'SVM';
400
+ }
401
+ }
402
+
403
+ async function getBalance({ address, rpcUrl = node.SOLANA_RPC_URL }) {
404
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
405
+ const balance = await connection.getBalance(new web3_js.PublicKey(address));
406
+ return balance;
407
+ }
408
+ async function createSolanaTransaction({ senderSolanaAddress, amount, to, rpcUrl = 'https://api.devnet.solana.com' }) {
409
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
410
+ const balance = await getBalance({
411
+ address: senderSolanaAddress,
412
+ rpcUrl
413
+ });
414
+ if (balance < amount * 1e9) {
415
+ throw new Error('Insufficient balance');
296
416
  }
417
+ const fromPubkey = new web3_js.PublicKey(senderSolanaAddress);
418
+ const transaction = new web3_js.Transaction().add(web3_js.SystemProgram.transfer({
419
+ fromPubkey: fromPubkey,
420
+ toPubkey: new web3_js.PublicKey(to),
421
+ lamports: amount * 1e9
422
+ }));
423
+ const { blockhash } = await connection.getLatestBlockhash();
424
+ transaction.recentBlockhash = blockhash;
425
+ transaction.feePayer = fromPubkey;
426
+ const serializedTransaction = transaction.serializeMessage();
427
+ return {
428
+ transaction,
429
+ serializedTransaction
430
+ };
431
+ }
432
+ const addSignatureToTransaction = ({ transaction, signature, signerPublicKey })=>{
433
+ transaction.addSignature(signerPublicKey, Buffer.from(signature));
434
+ return transaction;
435
+ };
436
+ function attachSignature({ transaction, signatureBase58, senderAddress }) {
437
+ const sigBytes = decodeBase58(signatureBase58);
438
+ const signerPubkey = new web3_js.PublicKey(senderAddress);
439
+ return addSignatureToTransaction({
440
+ transaction,
441
+ signature: sigBytes,
442
+ signerPublicKey: signerPubkey
443
+ });
297
444
  }
445
+ async function sendTransaction({ signedTransaction, rpcUrl = 'https://api.devnet.solana.com' }) {
446
+ const connection = new web3_js.Connection(rpcUrl != null ? rpcUrl : 'https://api.devnet.solana.com');
447
+ const txid = await connection.sendRawTransaction(Buffer.from(signedTransaction));
448
+ return txid;
449
+ }
450
+
451
+ /**
452
+ * Creates a delegated SVM wallet client for functional operations
453
+ */ const createDelegatedSvmWalletClient = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, apiKey, debug = false })=>{
454
+ const baseClient = node.createDelegatedWalletClient({
455
+ environmentId,
456
+ baseApiUrl,
457
+ baseMPCRelayApiUrl,
458
+ apiKey,
459
+ debug
460
+ });
461
+ const svmClient = _extends({}, baseClient, {
462
+ chainName: 'SVM'
463
+ });
464
+ return svmClient;
465
+ };
466
+ /**
467
+ * Signs a message using delegated signing for SVM
468
+ */ const delegatedSignMessage = async (client, { walletId, walletApiKey, keyShare, message, isFormatted = false })=>{
469
+ try {
470
+ // Use the delegated sign message function from node package
471
+ const signatureEd25519 = await node.delegatedSignMessage(client, {
472
+ walletId,
473
+ walletApiKey,
474
+ keyShare,
475
+ message,
476
+ chainName: client.chainName,
477
+ isFormatted
478
+ });
479
+ // Use PublicKey to encode signature as base58 (SVM format)
480
+ const base58Signature = encodeBase58(signatureEd25519);
481
+ return base58Signature;
482
+ } catch (error) {
483
+ logError({
484
+ message: 'Error in delegatedSignMessage',
485
+ error: error,
486
+ context: {
487
+ walletId
488
+ }
489
+ });
490
+ throw error;
491
+ }
492
+ };
493
+ /**
494
+ * Signs a transaction using delegated signing for SVM
495
+ *
496
+ * @param client - The delegated SVM wallet client
497
+ * @param options - Signing options
498
+ * @param options.walletId - The wallet ID
499
+ * @param options.walletApiKey - The wallet API key
500
+ * @param options.keyShare - The server key share
501
+ * @param options.transaction - The transaction to sign (VersionedTransaction or Transaction)
502
+ * @param options.signerAddress - Optional. The address that should sign the transaction.
503
+ * If not provided, defaults to the first signer (VersionedTransaction)
504
+ * or fee payer (Transaction). Use this for gasless transactions where
505
+ * a separate fee payer pays the fees.
506
+ *
507
+ * @returns The partially signed transaction with the signature attached for the specified signer
508
+ *
509
+ * @example
510
+ * // Standard transaction where sender is also fee payer
511
+ * const signedTx = await delegatedSignTransaction(client, {
512
+ * walletId,
513
+ * walletApiKey,
514
+ * keyShare,
515
+ * transaction,
516
+ * });
517
+ *
518
+ * @example
519
+ * // Gasless transaction with separate fee payer
520
+ * const transaction = new Transaction();
521
+ * transaction.feePayer = feePayerPublicKey; // Set the actual fee payer
522
+ * transaction.add(instruction); // Instruction that requires sender signature
523
+ *
524
+ * const signedTx = await delegatedSignTransaction(client, {
525
+ * walletId,
526
+ * walletApiKey,
527
+ * keyShare,
528
+ * transaction,
529
+ * signerAddress: senderAddress, // Explicitly specify who signs
530
+ * });
531
+ *
532
+ */ const delegatedSignTransaction = async (client, { walletId, walletApiKey, keyShare, transaction, signerAddress })=>{
533
+ try {
534
+ let messageToSign;
535
+ if (transaction instanceof web3_js.VersionedTransaction) {
536
+ // For versioned transactions, we need to sign the message directly
537
+ const messageBytes = transaction.message.serialize();
538
+ messageToSign = Buffer.from(Array.from(messageBytes)).toString('hex');
539
+ } else {
540
+ // For legacy transactions, serialize the message
541
+ const messageBytes = transaction.serializeMessage();
542
+ messageToSign = messageBytes.toString('hex');
543
+ }
544
+ // Use the delegated sign message function from node package
545
+ const signatureEd25519 = await node.delegatedSignMessage(client, {
546
+ walletId,
547
+ walletApiKey,
548
+ keyShare,
549
+ message: messageToSign,
550
+ chainName: client.chainName,
551
+ isFormatted: false
552
+ });
553
+ if (!signatureEd25519) {
554
+ throw new Error('Signature is undefined');
555
+ }
556
+ const resolvedSignerAddress = signerAddress != null ? signerAddress : (()=>{
557
+ var _transaction_feePayer;
558
+ if (transaction instanceof web3_js.VersionedTransaction) {
559
+ var _signers_;
560
+ const signers = transaction.message.staticAccountKeys;
561
+ var _signers__toBase58;
562
+ return (_signers__toBase58 = (_signers_ = signers[0]) == null ? void 0 : _signers_.toBase58()) != null ? _signers__toBase58 : '';
563
+ }
564
+ var _transaction_feePayer_toBase58;
565
+ return (_transaction_feePayer_toBase58 = (_transaction_feePayer = transaction.feePayer) == null ? void 0 : _transaction_feePayer.toBase58()) != null ? _transaction_feePayer_toBase58 : '';
566
+ })();
567
+ if (!resolvedSignerAddress) {
568
+ throw new Error('Could not determine signer address. Provide signerAddress explicitly or ensure transaction has a fee payer.');
569
+ }
570
+ let signerPublicKey;
571
+ try {
572
+ signerPublicKey = new web3_js.PublicKey(resolvedSignerAddress);
573
+ } catch (error) {
574
+ throw new Error(`Invalid signer address: ${resolvedSignerAddress}. ${error instanceof Error ? error.message : 'Unknown error'}`);
575
+ }
576
+ const signedTransaction = addSignatureToTransaction({
577
+ transaction,
578
+ signature: signatureEd25519,
579
+ signerPublicKey
580
+ });
581
+ return signedTransaction;
582
+ } catch (error) {
583
+ logError({
584
+ message: 'Error in delegatedSignTransaction',
585
+ error: error,
586
+ context: {
587
+ walletId
588
+ }
589
+ });
590
+ throw error;
591
+ }
592
+ };
593
+ /**
594
+ * Revoke delegation - delegates to the node package
595
+ */ const revokeDelegation = async (client, params)=>{
596
+ return node.revokeDelegation(client, params);
597
+ };
298
598
 
299
599
  exports.DynamicSvmWalletClient = DynamicSvmWalletClient;
600
+ exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
300
601
  exports.addSignatureToTransaction = addSignatureToTransaction;
602
+ exports.attachSignature = attachSignature;
603
+ exports.createDelegatedSvmWalletClient = createDelegatedSvmWalletClient;
301
604
  exports.createSolanaTransaction = createSolanaTransaction;
605
+ exports.decodeBase58 = decodeBase58;
606
+ exports.delegatedSignMessage = delegatedSignMessage;
607
+ exports.delegatedSignTransaction = delegatedSignTransaction;
608
+ exports.encodeBase58 = encodeBase58;
302
609
  exports.getBalance = getBalance;
610
+ exports.revokeDelegation = revokeDelegation;
303
611
  exports.sendTransaction = sendTransaction;