@dynamic-labs-wallet/node-svm 0.0.322 → 0.0.323
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 +140 -1
- package/index.esm.js +141 -4
- package/package.json +2 -2
package/index.cjs.js
CHANGED
|
@@ -15,6 +15,7 @@ function _extends() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
|
|
18
|
+
const ERROR_SIGN_RAW_MESSAGE = 'Error signing raw message';
|
|
18
19
|
|
|
19
20
|
// Base58 encoding/decoding (Bitcoin alphabet) without external dependencies
|
|
20
21
|
// Implementation adapted from the reference algorithm; suitable for keys/signatures
|
|
@@ -209,12 +210,61 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
209
210
|
throw error;
|
|
210
211
|
}
|
|
211
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Signs a pre-formatted (raw) message without additional encoding.
|
|
215
|
+
* The message must be a hex string representing already-hashed data.
|
|
216
|
+
*
|
|
217
|
+
* @param message The pre-formatted hex message to sign
|
|
218
|
+
* @param accountAddress Solana address (base58 encoded)
|
|
219
|
+
* @param password The password for encrypted backup shares
|
|
220
|
+
*/ async signRawMessage({ message, accountAddress, password = undefined, externalServerKeyShares }) {
|
|
221
|
+
if (!accountAddress) {
|
|
222
|
+
throw new Error('Account address is required');
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
// Attempt to recover key shares from backup if not provided
|
|
226
|
+
await this.ensureKeySharesRecovered({
|
|
227
|
+
accountAddress,
|
|
228
|
+
password,
|
|
229
|
+
walletOperation: node.WalletOperation.SIGN_MESSAGE,
|
|
230
|
+
externalServerKeyShares,
|
|
231
|
+
errorMessage: 'External server key shares are required to sign a raw message. No backup shares available for recovery.'
|
|
232
|
+
});
|
|
233
|
+
const messageHex = node.stripHexPrefix(message);
|
|
234
|
+
const signatureEd25519 = await this.sign({
|
|
235
|
+
message: messageHex,
|
|
236
|
+
accountAddress,
|
|
237
|
+
chainName: this.chainName,
|
|
238
|
+
password,
|
|
239
|
+
externalServerKeyShares,
|
|
240
|
+
isFormatted: true
|
|
241
|
+
});
|
|
242
|
+
return encodeBase58(signatureEd25519);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
logError$1({
|
|
245
|
+
message: ERROR_SIGN_RAW_MESSAGE,
|
|
246
|
+
error: error,
|
|
247
|
+
context: {
|
|
248
|
+
accountAddress
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
throw new Error(ERROR_SIGN_RAW_MESSAGE);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
212
254
|
//todo:should txn just be a string?
|
|
213
|
-
async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares }) {
|
|
255
|
+
async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares, sponsor = false }) {
|
|
214
256
|
// Validate inputs early
|
|
215
257
|
if (!senderAddress) {
|
|
216
258
|
throw new Error('Sender address is required');
|
|
217
259
|
}
|
|
260
|
+
if (sponsor) {
|
|
261
|
+
if (typeof transaction === 'string') {
|
|
262
|
+
throw new TypeError('sponsor=true requires a Transaction or VersionedTransaction object, not a hex string');
|
|
263
|
+
}
|
|
264
|
+
transaction = await this.sponsorTransaction({
|
|
265
|
+
transaction
|
|
266
|
+
});
|
|
267
|
+
}
|
|
218
268
|
await this.verifyPassword({
|
|
219
269
|
accountAddress: senderAddress,
|
|
220
270
|
password
|
|
@@ -381,6 +431,37 @@ class DynamicSvmWalletClient extends node.DynamicWalletClient {
|
|
|
381
431
|
externalKeySharesWithBackupStatus
|
|
382
432
|
};
|
|
383
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* Sponsors a Solana transaction via the Dynamic gas sponsorship API.
|
|
436
|
+
*
|
|
437
|
+
* Sends the unsigned transaction to Dynamic's sponsorTransaction endpoint,
|
|
438
|
+
* which replaces the fee payer with the sponsor's address. The returned
|
|
439
|
+
* transaction object has the sponsor as fee payer and should be passed to
|
|
440
|
+
* {@link signTransaction} instead of the original transaction.
|
|
441
|
+
*
|
|
442
|
+
* Gas sponsorship must be enabled for your environment in the Dynamic
|
|
443
|
+
* dashboard before calling this method.
|
|
444
|
+
*
|
|
445
|
+
* @param transaction - Unsigned Solana transaction (legacy or versioned).
|
|
446
|
+
* @returns The sponsored transaction with the gas sponsor as fee payer.
|
|
447
|
+
*/ async sponsorTransaction({ transaction, traceContext }) {
|
|
448
|
+
// Serialize the unsigned transaction to base64 wire format
|
|
449
|
+
const serialized = transaction instanceof web3_js.VersionedTransaction ? transaction.serialize() : transaction.serialize({
|
|
450
|
+
requireAllSignatures: false,
|
|
451
|
+
verifySignatures: false
|
|
452
|
+
});
|
|
453
|
+
const txBase64 = Buffer.from(serialized).toString('base64');
|
|
454
|
+
const { transaction: sponsoredBase64 } = await this.apiClient.requestSvmSponsoredTransaction({
|
|
455
|
+
transaction: txBase64,
|
|
456
|
+
traceContext
|
|
457
|
+
});
|
|
458
|
+
const sponsoredBytes = Buffer.from(sponsoredBase64, 'base64');
|
|
459
|
+
// Deserialize back to the same transaction type
|
|
460
|
+
if (transaction instanceof web3_js.VersionedTransaction) {
|
|
461
|
+
return web3_js.VersionedTransaction.deserialize(sponsoredBytes);
|
|
462
|
+
}
|
|
463
|
+
return web3_js.Transaction.from(sponsoredBytes);
|
|
464
|
+
}
|
|
384
465
|
async getSvmWallets() {
|
|
385
466
|
const wallets = await this.getWallets();
|
|
386
467
|
const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
|
|
@@ -589,6 +670,62 @@ const logError = node.createLogError('node-svm');
|
|
|
589
670
|
throw error;
|
|
590
671
|
}
|
|
591
672
|
};
|
|
673
|
+
/**
|
|
674
|
+
* Signs a pre-formatted (raw) message using delegated signing for SVM.
|
|
675
|
+
* The message must be a hex string representing already-hashed data.
|
|
676
|
+
*
|
|
677
|
+
* @param client - The delegated SVM wallet client
|
|
678
|
+
* @param options - Signing options
|
|
679
|
+
* @param options.walletId - The wallet ID
|
|
680
|
+
* @param options.walletApiKey - The wallet API key
|
|
681
|
+
* @param options.keyShare - The server key share
|
|
682
|
+
* @param options.message - Hex string of the already-hashed data to sign
|
|
683
|
+
*
|
|
684
|
+
* @returns The base58-encoded signature
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* // Sign a pre-hashed message
|
|
688
|
+
* const signature = await delegatedSignRawMessage(client, {
|
|
689
|
+
* walletId,
|
|
690
|
+
* walletApiKey,
|
|
691
|
+
* keyShare,
|
|
692
|
+
* message: preHashedHex, // hex string of already-hashed data
|
|
693
|
+
* });
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* // Sign a SHA-256 hash derived from arbitrary application data
|
|
697
|
+
* import { createHash } from 'crypto';
|
|
698
|
+
* const hash = createHash('sha256').update('my application data').digest('hex');
|
|
699
|
+
* const signature = await delegatedSignRawMessage(client, {
|
|
700
|
+
* walletId,
|
|
701
|
+
* walletApiKey,
|
|
702
|
+
* keyShare,
|
|
703
|
+
* message: hash,
|
|
704
|
+
* });
|
|
705
|
+
*
|
|
706
|
+
*/ const delegatedSignRawMessage = async (client, { walletId, walletApiKey, keyShare, message })=>{
|
|
707
|
+
if (!keyShare || !walletId || !walletApiKey) {
|
|
708
|
+
throw new Error('Delegated key share, wallet ID, and wallet API key are required to sign a raw message');
|
|
709
|
+
}
|
|
710
|
+
try {
|
|
711
|
+
return await delegatedSignMessage(client, {
|
|
712
|
+
walletId,
|
|
713
|
+
walletApiKey,
|
|
714
|
+
keyShare,
|
|
715
|
+
message: node.stripHexPrefix(message),
|
|
716
|
+
isFormatted: true
|
|
717
|
+
});
|
|
718
|
+
} catch (error) {
|
|
719
|
+
logError({
|
|
720
|
+
message: 'Error in delegatedSignRawMessage',
|
|
721
|
+
error: error,
|
|
722
|
+
context: {
|
|
723
|
+
walletId
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
throw error;
|
|
727
|
+
}
|
|
728
|
+
};
|
|
592
729
|
/**
|
|
593
730
|
* Revoke delegation - delegates to the node package
|
|
594
731
|
*/ const revokeDelegation = async (client, params)=>{
|
|
@@ -597,12 +734,14 @@ const logError = node.createLogError('node-svm');
|
|
|
597
734
|
|
|
598
735
|
exports.DynamicSvmWalletClient = DynamicSvmWalletClient;
|
|
599
736
|
exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
|
|
737
|
+
exports.ERROR_SIGN_RAW_MESSAGE = ERROR_SIGN_RAW_MESSAGE;
|
|
600
738
|
exports.addSignatureToTransaction = addSignatureToTransaction;
|
|
601
739
|
exports.attachSignature = attachSignature;
|
|
602
740
|
exports.createDelegatedSvmWalletClient = createDelegatedSvmWalletClient;
|
|
603
741
|
exports.createSolanaTransaction = createSolanaTransaction;
|
|
604
742
|
exports.decodeBase58 = decodeBase58;
|
|
605
743
|
exports.delegatedSignMessage = delegatedSignMessage;
|
|
744
|
+
exports.delegatedSignRawMessage = delegatedSignRawMessage;
|
|
606
745
|
exports.delegatedSignTransaction = delegatedSignTransaction;
|
|
607
746
|
exports.encodeBase58 = encodeBase58;
|
|
608
747
|
exports.getBalance = getBalance;
|
package/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createLogError, 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,
|
|
1
|
+
import { createLogError, DynamicWalletClient, getMPCChainConfig, getExternalServerKeyShareBackupInfo, WalletOperation, stripHexPrefix, SOLANA_RPC_URL, createDelegatedWalletClient, delegatedSignMessage as delegatedSignMessage$1, revokeDelegation as revokeDelegation$1 } from '@dynamic-labs-wallet/node';
|
|
2
|
+
import { PublicKey, VersionedTransaction, Keypair, Transaction, Connection, SystemProgram } from '@solana/web3.js';
|
|
3
3
|
|
|
4
4
|
function _extends() {
|
|
5
5
|
_extends = Object.assign || function assign(target) {
|
|
@@ -13,6 +13,7 @@ function _extends() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating svm wallet account';
|
|
16
|
+
const ERROR_SIGN_RAW_MESSAGE = 'Error signing raw message';
|
|
16
17
|
|
|
17
18
|
// Base58 encoding/decoding (Bitcoin alphabet) without external dependencies
|
|
18
19
|
// Implementation adapted from the reference algorithm; suitable for keys/signatures
|
|
@@ -207,12 +208,61 @@ class DynamicSvmWalletClient extends DynamicWalletClient {
|
|
|
207
208
|
throw error;
|
|
208
209
|
}
|
|
209
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Signs a pre-formatted (raw) message without additional encoding.
|
|
213
|
+
* The message must be a hex string representing already-hashed data.
|
|
214
|
+
*
|
|
215
|
+
* @param message The pre-formatted hex message to sign
|
|
216
|
+
* @param accountAddress Solana address (base58 encoded)
|
|
217
|
+
* @param password The password for encrypted backup shares
|
|
218
|
+
*/ async signRawMessage({ message, accountAddress, password = undefined, externalServerKeyShares }) {
|
|
219
|
+
if (!accountAddress) {
|
|
220
|
+
throw new Error('Account address is required');
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
// Attempt to recover key shares from backup if not provided
|
|
224
|
+
await this.ensureKeySharesRecovered({
|
|
225
|
+
accountAddress,
|
|
226
|
+
password,
|
|
227
|
+
walletOperation: WalletOperation.SIGN_MESSAGE,
|
|
228
|
+
externalServerKeyShares,
|
|
229
|
+
errorMessage: 'External server key shares are required to sign a raw message. No backup shares available for recovery.'
|
|
230
|
+
});
|
|
231
|
+
const messageHex = stripHexPrefix(message);
|
|
232
|
+
const signatureEd25519 = await this.sign({
|
|
233
|
+
message: messageHex,
|
|
234
|
+
accountAddress,
|
|
235
|
+
chainName: this.chainName,
|
|
236
|
+
password,
|
|
237
|
+
externalServerKeyShares,
|
|
238
|
+
isFormatted: true
|
|
239
|
+
});
|
|
240
|
+
return encodeBase58(signatureEd25519);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
logError$1({
|
|
243
|
+
message: ERROR_SIGN_RAW_MESSAGE,
|
|
244
|
+
error: error,
|
|
245
|
+
context: {
|
|
246
|
+
accountAddress
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
throw new Error(ERROR_SIGN_RAW_MESSAGE);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
210
252
|
//todo:should txn just be a string?
|
|
211
|
-
async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares }) {
|
|
253
|
+
async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares, sponsor = false }) {
|
|
212
254
|
// Validate inputs early
|
|
213
255
|
if (!senderAddress) {
|
|
214
256
|
throw new Error('Sender address is required');
|
|
215
257
|
}
|
|
258
|
+
if (sponsor) {
|
|
259
|
+
if (typeof transaction === 'string') {
|
|
260
|
+
throw new TypeError('sponsor=true requires a Transaction or VersionedTransaction object, not a hex string');
|
|
261
|
+
}
|
|
262
|
+
transaction = await this.sponsorTransaction({
|
|
263
|
+
transaction
|
|
264
|
+
});
|
|
265
|
+
}
|
|
216
266
|
await this.verifyPassword({
|
|
217
267
|
accountAddress: senderAddress,
|
|
218
268
|
password
|
|
@@ -379,6 +429,37 @@ class DynamicSvmWalletClient extends DynamicWalletClient {
|
|
|
379
429
|
externalKeySharesWithBackupStatus
|
|
380
430
|
};
|
|
381
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Sponsors a Solana transaction via the Dynamic gas sponsorship API.
|
|
434
|
+
*
|
|
435
|
+
* Sends the unsigned transaction to Dynamic's sponsorTransaction endpoint,
|
|
436
|
+
* which replaces the fee payer with the sponsor's address. The returned
|
|
437
|
+
* transaction object has the sponsor as fee payer and should be passed to
|
|
438
|
+
* {@link signTransaction} instead of the original transaction.
|
|
439
|
+
*
|
|
440
|
+
* Gas sponsorship must be enabled for your environment in the Dynamic
|
|
441
|
+
* dashboard before calling this method.
|
|
442
|
+
*
|
|
443
|
+
* @param transaction - Unsigned Solana transaction (legacy or versioned).
|
|
444
|
+
* @returns The sponsored transaction with the gas sponsor as fee payer.
|
|
445
|
+
*/ async sponsorTransaction({ transaction, traceContext }) {
|
|
446
|
+
// Serialize the unsigned transaction to base64 wire format
|
|
447
|
+
const serialized = transaction instanceof VersionedTransaction ? transaction.serialize() : transaction.serialize({
|
|
448
|
+
requireAllSignatures: false,
|
|
449
|
+
verifySignatures: false
|
|
450
|
+
});
|
|
451
|
+
const txBase64 = Buffer.from(serialized).toString('base64');
|
|
452
|
+
const { transaction: sponsoredBase64 } = await this.apiClient.requestSvmSponsoredTransaction({
|
|
453
|
+
transaction: txBase64,
|
|
454
|
+
traceContext
|
|
455
|
+
});
|
|
456
|
+
const sponsoredBytes = Buffer.from(sponsoredBase64, 'base64');
|
|
457
|
+
// Deserialize back to the same transaction type
|
|
458
|
+
if (transaction instanceof VersionedTransaction) {
|
|
459
|
+
return VersionedTransaction.deserialize(sponsoredBytes);
|
|
460
|
+
}
|
|
461
|
+
return Transaction.from(sponsoredBytes);
|
|
462
|
+
}
|
|
382
463
|
async getSvmWallets() {
|
|
383
464
|
const wallets = await this.getWallets();
|
|
384
465
|
const svmWallets = wallets.filter((wallet)=>wallet.chainName === 'solana');
|
|
@@ -587,10 +668,66 @@ const logError = createLogError('node-svm');
|
|
|
587
668
|
throw error;
|
|
588
669
|
}
|
|
589
670
|
};
|
|
671
|
+
/**
|
|
672
|
+
* Signs a pre-formatted (raw) message using delegated signing for SVM.
|
|
673
|
+
* The message must be a hex string representing already-hashed data.
|
|
674
|
+
*
|
|
675
|
+
* @param client - The delegated SVM wallet client
|
|
676
|
+
* @param options - Signing options
|
|
677
|
+
* @param options.walletId - The wallet ID
|
|
678
|
+
* @param options.walletApiKey - The wallet API key
|
|
679
|
+
* @param options.keyShare - The server key share
|
|
680
|
+
* @param options.message - Hex string of the already-hashed data to sign
|
|
681
|
+
*
|
|
682
|
+
* @returns The base58-encoded signature
|
|
683
|
+
*
|
|
684
|
+
* @example
|
|
685
|
+
* // Sign a pre-hashed message
|
|
686
|
+
* const signature = await delegatedSignRawMessage(client, {
|
|
687
|
+
* walletId,
|
|
688
|
+
* walletApiKey,
|
|
689
|
+
* keyShare,
|
|
690
|
+
* message: preHashedHex, // hex string of already-hashed data
|
|
691
|
+
* });
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* // Sign a SHA-256 hash derived from arbitrary application data
|
|
695
|
+
* import { createHash } from 'crypto';
|
|
696
|
+
* const hash = createHash('sha256').update('my application data').digest('hex');
|
|
697
|
+
* const signature = await delegatedSignRawMessage(client, {
|
|
698
|
+
* walletId,
|
|
699
|
+
* walletApiKey,
|
|
700
|
+
* keyShare,
|
|
701
|
+
* message: hash,
|
|
702
|
+
* });
|
|
703
|
+
*
|
|
704
|
+
*/ const delegatedSignRawMessage = async (client, { walletId, walletApiKey, keyShare, message })=>{
|
|
705
|
+
if (!keyShare || !walletId || !walletApiKey) {
|
|
706
|
+
throw new Error('Delegated key share, wallet ID, and wallet API key are required to sign a raw message');
|
|
707
|
+
}
|
|
708
|
+
try {
|
|
709
|
+
return await delegatedSignMessage(client, {
|
|
710
|
+
walletId,
|
|
711
|
+
walletApiKey,
|
|
712
|
+
keyShare,
|
|
713
|
+
message: stripHexPrefix(message),
|
|
714
|
+
isFormatted: true
|
|
715
|
+
});
|
|
716
|
+
} catch (error) {
|
|
717
|
+
logError({
|
|
718
|
+
message: 'Error in delegatedSignRawMessage',
|
|
719
|
+
error: error,
|
|
720
|
+
context: {
|
|
721
|
+
walletId
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
throw error;
|
|
725
|
+
}
|
|
726
|
+
};
|
|
590
727
|
/**
|
|
591
728
|
* Revoke delegation - delegates to the node package
|
|
592
729
|
*/ const revokeDelegation = async (client, params)=>{
|
|
593
730
|
return revokeDelegation$1(client, params);
|
|
594
731
|
};
|
|
595
732
|
|
|
596
|
-
export { DynamicSvmWalletClient, ERROR_CREATE_WALLET_ACCOUNT, addSignatureToTransaction, attachSignature, createDelegatedSvmWalletClient, createSolanaTransaction, decodeBase58, delegatedSignMessage, delegatedSignTransaction, encodeBase58, getBalance, revokeDelegation, sendTransaction };
|
|
733
|
+
export { DynamicSvmWalletClient, ERROR_CREATE_WALLET_ACCOUNT, ERROR_SIGN_RAW_MESSAGE, addSignatureToTransaction, attachSignature, createDelegatedSvmWalletClient, createSolanaTransaction, decodeBase58, delegatedSignMessage, delegatedSignRawMessage, delegatedSignTransaction, encodeBase58, getBalance, revokeDelegation, sendTransaction };
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs-wallet/node-svm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.323",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@dynamic-labs-wallet/node": "0.0.
|
|
7
|
+
"@dynamic-labs-wallet/node": "0.0.323",
|
|
8
8
|
"@solana/web3.js": "^1.98.2"
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|