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