@dynamic-labs-wallet/node-svm 0.0.0-pr384.2 → 0.0.0-pr526.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.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,45 +19,86 @@ function _extends() {
|
|
|
16
19
|
|
|
17
20
|
const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
@@ -73,11 +117,16 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
73
117
|
onError,
|
|
74
118
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
75
119
|
// update wallet map
|
|
120
|
+
const chainConfig = node.getMPCChainConfig(this.chainName);
|
|
76
121
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
|
|
77
122
|
accountAddress,
|
|
78
123
|
walletId,
|
|
79
124
|
chainName: this.chainName,
|
|
80
125
|
thresholdSignatureScheme,
|
|
126
|
+
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
127
|
+
index,
|
|
128
|
+
value
|
|
129
|
+
]))),
|
|
81
130
|
externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
|
|
82
131
|
});
|
|
83
132
|
this.logger.debug('walletMap updated for wallet', {
|
|
@@ -111,16 +160,22 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
111
160
|
externalServerKeyShares
|
|
112
161
|
};
|
|
113
162
|
} catch (error) {
|
|
114
|
-
|
|
163
|
+
logError({
|
|
164
|
+
message: ERROR_CREATE_WALLET_ACCOUNT,
|
|
165
|
+
error: error,
|
|
166
|
+
context: {}
|
|
167
|
+
});
|
|
115
168
|
throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
|
|
116
169
|
}
|
|
117
170
|
}
|
|
118
171
|
// Function to properly derive account address
|
|
119
172
|
async deriveAccountAddress(rawPublicKey) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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();
|
|
124
179
|
return {
|
|
125
180
|
accountAddress
|
|
126
181
|
};
|
|
@@ -132,47 +187,69 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
132
187
|
* @param accountAddress Solana address (base58 encoded)
|
|
133
188
|
* @param password The password for encrypted backup shares
|
|
134
189
|
*/ async signMessage({ message, accountAddress, password = undefined, externalServerKeyShares }) {
|
|
135
|
-
|
|
136
|
-
accountAddress,
|
|
137
|
-
password,
|
|
138
|
-
walletOperation: node.WalletOperation.SIGN_MESSAGE
|
|
139
|
-
});
|
|
190
|
+
// Validate inputs early
|
|
140
191
|
if (!accountAddress) {
|
|
141
192
|
throw new Error('Account address is required');
|
|
142
193
|
}
|
|
143
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);
|
|
144
205
|
const signatureEd25519 = await this.sign({
|
|
145
|
-
message,
|
|
146
|
-
accountAddress
|
|
206
|
+
message: messageHex,
|
|
207
|
+
accountAddress,
|
|
147
208
|
chainName: this.chainName,
|
|
148
209
|
password,
|
|
149
210
|
externalServerKeyShares
|
|
150
211
|
});
|
|
151
|
-
|
|
152
|
-
const base58Signature = new web3_js.PublicKey(signatureEd25519).toBase58();
|
|
153
|
-
return base58Signature;
|
|
212
|
+
return encodeBase58(signatureEd25519);
|
|
154
213
|
} catch (error) {
|
|
155
|
-
|
|
214
|
+
logError({
|
|
215
|
+
message: 'Error signing message:',
|
|
216
|
+
error: error,
|
|
217
|
+
context: {
|
|
218
|
+
accountAddress
|
|
219
|
+
}
|
|
220
|
+
});
|
|
156
221
|
throw error;
|
|
157
222
|
}
|
|
158
223
|
}
|
|
159
224
|
//todo:should txn just be a string?
|
|
160
225
|
async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares }) {
|
|
226
|
+
// Validate inputs early
|
|
227
|
+
if (!senderAddress) {
|
|
228
|
+
throw new Error('Sender address is required');
|
|
229
|
+
}
|
|
161
230
|
await this.verifyPassword({
|
|
162
231
|
accountAddress: senderAddress,
|
|
163
232
|
password,
|
|
164
233
|
walletOperation: node.WalletOperation.SIGN_TRANSACTION
|
|
165
234
|
});
|
|
166
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
|
+
});
|
|
167
244
|
let messageToSign;
|
|
168
|
-
if (transaction
|
|
169
|
-
|
|
245
|
+
if (typeof transaction === 'string') {
|
|
246
|
+
messageToSign = transaction.startsWith('0x') ? transaction.slice(2) : transaction;
|
|
247
|
+
} else if (transaction instanceof web3_js.VersionedTransaction) {
|
|
170
248
|
const messageBytes = transaction.message.serialize();
|
|
171
|
-
messageToSign =
|
|
249
|
+
messageToSign = toHex(messageBytes);
|
|
172
250
|
} else {
|
|
173
|
-
// For legacy transactions, serialize the message
|
|
174
251
|
const messageBytes = transaction.serializeMessage();
|
|
175
|
-
messageToSign = Buffer.
|
|
252
|
+
messageToSign = toHex(Buffer.isBuffer(messageBytes) ? messageBytes : messageBytes);
|
|
176
253
|
}
|
|
177
254
|
const signatureEd25519 = await this.sign({
|
|
178
255
|
message: messageToSign,
|
|
@@ -184,18 +261,15 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
184
261
|
if (!signatureEd25519) {
|
|
185
262
|
throw new Error('Signature is undefined');
|
|
186
263
|
}
|
|
187
|
-
|
|
188
|
-
const signedTransaction = addSignatureToTransaction({
|
|
189
|
-
transaction,
|
|
190
|
-
signature: signatureEd25519,
|
|
191
|
-
signerPublicKey: senderPublicKey
|
|
192
|
-
});
|
|
193
|
-
return signedTransaction;
|
|
264
|
+
return encodeBase58(signatureEd25519);
|
|
194
265
|
} catch (error) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
266
|
+
logError({
|
|
267
|
+
message: 'Error in signTransaction:',
|
|
268
|
+
error: error,
|
|
269
|
+
context: {
|
|
270
|
+
senderAddress
|
|
271
|
+
}
|
|
272
|
+
});
|
|
199
273
|
throw error;
|
|
200
274
|
}
|
|
201
275
|
}
|
|
@@ -238,18 +312,19 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
238
312
|
* @param privateKey The private key to convert
|
|
239
313
|
* @returns The hex string
|
|
240
314
|
*/ decodePrivateKeyForSolana(privateKey) {
|
|
241
|
-
const decoded =
|
|
242
|
-
|
|
243
|
-
return Buffer.from(
|
|
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');
|
|
244
318
|
}
|
|
245
319
|
getPublicKeyFromPrivateKey(privateKey) {
|
|
246
|
-
const
|
|
247
|
-
const keypair = web3_js.Keypair.fromSecretKey(
|
|
248
|
-
|
|
249
|
-
return publicKeyBase58;
|
|
320
|
+
const secret = decodeBase58(privateKey);
|
|
321
|
+
const keypair = web3_js.Keypair.fromSecretKey(secret);
|
|
322
|
+
return keypair.publicKey.toBase58();
|
|
250
323
|
}
|
|
251
324
|
encodePublicKey(publicKey) {
|
|
252
|
-
|
|
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();
|
|
253
328
|
}
|
|
254
329
|
/**
|
|
255
330
|
* Imports the private key for a given account address
|
|
@@ -274,11 +349,16 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
274
349
|
onError,
|
|
275
350
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
276
351
|
// update wallet map
|
|
352
|
+
const chainConfig = node.getMPCChainConfig(this.chainName);
|
|
277
353
|
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
|
|
278
354
|
accountAddress,
|
|
279
355
|
walletId,
|
|
280
356
|
chainName: this.chainName,
|
|
281
357
|
thresholdSignatureScheme,
|
|
358
|
+
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
359
|
+
index,
|
|
360
|
+
value
|
|
361
|
+
]))),
|
|
282
362
|
externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
|
|
283
363
|
});
|
|
284
364
|
ceremonyCeremonyCompleteResolver(undefined);
|
|
@@ -310,17 +390,222 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
310
390
|
const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
|
|
311
391
|
return svmWallets;
|
|
312
392
|
}
|
|
313
|
-
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl }){
|
|
393
|
+
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, enableMPCAccelerator }){
|
|
314
394
|
super({
|
|
315
395
|
environmentId,
|
|
316
396
|
baseApiUrl,
|
|
317
|
-
baseMPCRelayApiUrl
|
|
397
|
+
baseMPCRelayApiUrl,
|
|
398
|
+
enableMPCAccelerator
|
|
318
399
|
}), this.chainName = 'SVM';
|
|
319
400
|
}
|
|
320
401
|
}
|
|
321
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');
|
|
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
|
+
});
|
|
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
|
+
};
|
|
598
|
+
|
|
322
599
|
exports.DynamicSvmWalletClient = DynamicSvmWalletClient;
|
|
600
|
+
exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
|
|
323
601
|
exports.addSignatureToTransaction = addSignatureToTransaction;
|
|
602
|
+
exports.attachSignature = attachSignature;
|
|
603
|
+
exports.createDelegatedSvmWalletClient = createDelegatedSvmWalletClient;
|
|
324
604
|
exports.createSolanaTransaction = createSolanaTransaction;
|
|
605
|
+
exports.decodeBase58 = decodeBase58;
|
|
606
|
+
exports.delegatedSignMessage = delegatedSignMessage;
|
|
607
|
+
exports.delegatedSignTransaction = delegatedSignTransaction;
|
|
608
|
+
exports.encodeBase58 = encodeBase58;
|
|
325
609
|
exports.getBalance = getBalance;
|
|
610
|
+
exports.revokeDelegation = revokeDelegation;
|
|
326
611
|
exports.sendTransaction = sendTransaction;
|