@deserialize/multi-vm-wallet 1.0.0 → 1.0.2

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.
@@ -11,9 +11,9 @@ const IChainWallet_1 = require("../IChainWallet");
11
11
  const utils_1 = require("./utils");
12
12
  const bn_js_1 = __importDefault(require("bn.js"));
13
13
  class SVMVM extends vm_1.VM {
14
- constructor(mnemonic) {
15
- super(mnemonic, "SVM");
16
- this.derivationPath = "m/44'/501'/"; // Default EVM derivation path
14
+ constructor(seed) {
15
+ super(seed, "SVM");
16
+ this.derivationPath = "m/44'/501'/"; // Default SVM derivation path
17
17
  }
18
18
  static validateAddress(address) {
19
19
  return web3_js_1.PublicKey.isOnCurve(address.toBuffer());
@@ -28,11 +28,23 @@ class SVMVM extends vm_1.VM {
28
28
  }
29
29
  return { balance: new bn_js_1.default(balance.amount), formatted: balance.uiAmount || parseInt(balance.amount) / 10 ** balance.decimals, decimal: balance.decimals };
30
30
  }
31
- generatePrivateKey(index, seedPhrase = this.mnemonic, derivationPath = this.derivationPath) {
32
- const seed = this.mnemonicToSeed(seedPhrase);
33
- const privateKey = (0, bip32_1.SVMDeriveChildPrivateKey)(seed, index, derivationPath);
31
+ generatePrivateKey(index, seed, mnemonic, derivationPath = this.derivationPath) {
32
+ let _seed;
33
+ if (seed) {
34
+ _seed = seed;
35
+ }
36
+ else if (mnemonic) {
37
+ _seed = vm_1.VM.mnemonicToSeed(mnemonic);
38
+ }
39
+ else {
40
+ _seed = this.seed;
41
+ }
42
+ const privateKey = (0, bip32_1.SVMDeriveChildPrivateKey)(_seed, index, derivationPath);
34
43
  return { privateKey, index };
35
44
  }
45
+ static fromMnemonic(seed) {
46
+ return new SVMVM(seed);
47
+ }
36
48
  }
37
49
  exports.SVMVM = SVMVM;
38
50
  SVMVM.signAndSendTransaction = utils_1.signAndSendTransaction;
@@ -66,6 +78,89 @@ class SVMChainWallet extends IChainWallet_1.ChainWallet {
66
78
  const hash = await SVMVM.signAndSendTransaction(transaction, this.connection, [this.privateKey]);
67
79
  return { success: true, hash }; // Placeholder
68
80
  }
81
+ async swap(fromToken, toToken, amount, slippage = 50) {
82
+ try {
83
+ if (amount <= 0) {
84
+ return {
85
+ success: false,
86
+ hash: "",
87
+ error: "Amount must be greater than 0"
88
+ };
89
+ }
90
+ if (slippage < 0 || slippage > 5000) {
91
+ return {
92
+ success: false,
93
+ hash: "",
94
+ error: "Slippage must be between 0 and 5000 basis points (0-50%)"
95
+ };
96
+ }
97
+ const fromTokenMint = new web3_js_1.PublicKey(fromToken.address);
98
+ const toTokenMint = toToken;
99
+ const validation = await (0, utils_1.validateJupiterTokens)(fromTokenMint.toString(), toTokenMint.toString());
100
+ if (!validation.valid) {
101
+ return {
102
+ success: false,
103
+ hash: "",
104
+ error: validation.message || "Token validation failed"
105
+ };
106
+ }
107
+ const baseAmount = (0, utils_1.uiAmountToBaseUnits)(amount, fromToken.decimals);
108
+ const balance = await this.getTokenBalance(fromTokenMint);
109
+ if (balance.balance.lt(new bn_js_1.default(baseAmount))) {
110
+ return {
111
+ success: false,
112
+ hash: "",
113
+ error: "Insufficient balance for swap"
114
+ };
115
+ }
116
+ const swapResult = await (0, utils_1.executeJupiterSwap)({
117
+ fromToken: fromTokenMint,
118
+ toToken: toTokenMint,
119
+ amount: baseAmount,
120
+ slippageBps: slippage,
121
+ userPublicKey: this.address
122
+ }, this.connection, this.privateKey);
123
+ if (!swapResult.success) {
124
+ return {
125
+ success: false,
126
+ hash: "",
127
+ error: swapResult.error || "Swap failed"
128
+ };
129
+ }
130
+ return {
131
+ success: true,
132
+ hash: swapResult.hash || ""
133
+ };
134
+ }
135
+ catch (error) {
136
+ console.error("Swap error:", error);
137
+ return {
138
+ success: false,
139
+ hash: "",
140
+ error: error instanceof Error ? error.message : "Unknown swap error occurred"
141
+ };
142
+ }
143
+ }
144
+ async getSwapQuote(fromToken, toToken, amount, slippage = 50) {
145
+ try {
146
+ const fromTokenMint = new web3_js_1.PublicKey(fromToken.address);
147
+ const baseAmount = (0, utils_1.uiAmountToBaseUnits)(amount, fromToken.decimals);
148
+ const quote = await (0, utils_1.getJupiterQuote)(fromTokenMint.toString(), toToken.toString(), baseAmount, slippage);
149
+ return {
150
+ success: true,
151
+ inputAmount: quote.inAmount,
152
+ outputAmount: quote.outAmount,
153
+ priceImpact: quote.priceImpactPct,
154
+ routePlan: quote.routePlan,
155
+ slippageBps: quote.slippageBps
156
+ };
157
+ }
158
+ catch (error) {
159
+ return {
160
+ success: false,
161
+ error: error instanceof Error ? error.message : "Failed to get swap quote"
162
+ };
163
+ }
164
+ }
69
165
  }
70
166
  exports.SVMChainWallet = SVMChainWallet;
71
- //swaps jupiter swap here
@@ -1,6 +1,54 @@
1
1
  import { Account } from "@solana/spl-token";
2
2
  import { Connection, Keypair, PublicKey, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
3
3
  import { TokenInfo } from "../types";
4
+ export interface JupiterQuoteResponse {
5
+ inputMint: string;
6
+ inAmount: string;
7
+ outputMint: string;
8
+ outAmount: string;
9
+ otherAmountThreshold: string;
10
+ swapMode: string;
11
+ slippageBps: number;
12
+ platformFee: null | any;
13
+ priceImpactPct: string;
14
+ routePlan: RoutePlan[];
15
+ contextSlot: number;
16
+ timeTaken: number;
17
+ }
18
+ interface RoutePlan {
19
+ swapInfo: SwapInfo;
20
+ percent: number;
21
+ }
22
+ interface SwapInfo {
23
+ ammKey: string;
24
+ label: string;
25
+ inputMint: string;
26
+ outputMint: string;
27
+ inAmount: string;
28
+ outAmount: string;
29
+ feeAmount: string;
30
+ feeMint: string;
31
+ }
32
+ interface JupiterSwapResponse {
33
+ swapTransaction: string;
34
+ lastValidBlockHeight: number;
35
+ prioritizationFeeLamports: number;
36
+ }
37
+ interface SwapParams {
38
+ fromToken: PublicKey;
39
+ toToken: PublicKey;
40
+ amount: number;
41
+ slippageBps?: number;
42
+ userPublicKey: PublicKey;
43
+ }
44
+ interface SwapResult {
45
+ success: boolean;
46
+ hash?: string;
47
+ error?: string;
48
+ inputAmount?: string;
49
+ outputAmount?: string;
50
+ priceImpact?: string;
51
+ }
4
52
  export declare const createV0Transaction: (connection: Connection, inX: TransactionInstruction[], signers: Keypair[], payerPubKey: PublicKey, blockHash?: string) => Promise<VersionedTransaction>;
5
53
  export declare const createAtaAndIx: (token: PublicKey, ownerPublicKey: PublicKey, tokenProgramId: PublicKey, connection: Connection) => Promise<{
6
54
  AtaTokenIx: any;
@@ -24,3 +72,14 @@ export declare const getTransferNativeTransaction: (from: Keypair, to: PublicKey
24
72
  export declare const getTransferTokenInx: (from: PublicKey, to: PublicKey, token: TokenInfo, amount: number, connection: Connection) => Promise<TransactionInstruction[]>;
25
73
  export declare const getTransferTokenTransaction: (from: Keypair, to: PublicKey, token: TokenInfo, amount: number, connection: Connection) => Promise<VersionedTransaction>;
26
74
  export declare const signAndSendTransaction: (transaction: VersionedTransaction, connection: Connection, signers: Keypair[]) => Promise<string>;
75
+ export declare const getJupiterQuote: (inputMint: string, outputMint: string, amount: number, slippageBps?: number) => Promise<JupiterQuoteResponse>;
76
+ export declare const buildJupiterSwapTransaction: (quote: JupiterQuoteResponse, userPublicKey: string, prioritizationFeeLamports?: number) => Promise<JupiterSwapResponse>;
77
+ export declare const executeJupiterSwap: (swapParams: SwapParams, connection: Connection, payer: Keypair) => Promise<SwapResult>;
78
+ export declare const uiAmountToBaseUnits: (uiAmount: number, decimals: number) => number;
79
+ export declare const baseUnitsToUiAmount: (baseAmount: string | number, decimals: number) => number;
80
+ export declare const getJupiterTokenList: () => Promise<any[]>;
81
+ export declare const validateJupiterTokens: (inputMint: string, outputMint: string) => Promise<{
82
+ valid: boolean;
83
+ message?: string;
84
+ }>;
85
+ export {};
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  //we will write all the svm utils function here
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.signAndSendTransaction = exports.getTransferTokenTransaction = exports.getTransferTokenInx = exports.getTransferNativeTransaction = exports.getTransferNativeInx = exports.getTokenAccountAccount = exports.getTokenBalance = exports.getSvmNativeBalance = exports.getProgramIdOfToken = exports.getSureAssociatedTokenAddressAndAccount = exports.createAtaAndIx = exports.createV0Transaction = void 0;
4
+ exports.validateJupiterTokens = exports.getJupiterTokenList = exports.baseUnitsToUiAmount = exports.uiAmountToBaseUnits = exports.executeJupiterSwap = exports.buildJupiterSwapTransaction = exports.getJupiterQuote = exports.signAndSendTransaction = exports.getTransferTokenTransaction = exports.getTransferTokenInx = exports.getTransferNativeTransaction = exports.getTransferNativeInx = exports.getTokenAccountAccount = exports.getTokenBalance = exports.getSvmNativeBalance = exports.getProgramIdOfToken = exports.getSureAssociatedTokenAddressAndAccount = exports.createAtaAndIx = exports.createV0Transaction = void 0;
5
5
  const spl_token_1 = require("@solana/spl-token");
6
6
  const web3_js_1 = require("@solana/web3.js");
7
7
  const transactionSender_1 = require("./transactionSender");
8
8
  const bn_js_1 = require("bn.js");
9
+ const JUPITER_BASE_URL = 'https://lite-api.jup.ag';
9
10
  const createV0Transaction = async (connection, inX, signers, payerPubKey, blockHash) => {
10
11
  const blockhash = blockHash || (await connection.getLatestBlockhash()).blockhash;
11
12
  const message = new web3_js_1.TransactionMessage({
@@ -71,7 +72,7 @@ const getProgramIdOfToken = async (owner, token, connection) => {
71
72
  }
72
73
  };
73
74
  exports.getProgramIdOfToken = getProgramIdOfToken;
74
- //get native balance
75
+ //get native balance
75
76
  const getSvmNativeBalance = async (address, connection) => {
76
77
  const balance = await connection.getBalance(address);
77
78
  return { balance: new bn_js_1.BN(balance), formatted: balance / web3_js_1.LAMPORTS_PER_SOL, decimal: 9 };
@@ -159,3 +160,145 @@ const signAndSendTransaction = async (transaction, connection, signers) => {
159
160
  return res.transaction.signatures[0];
160
161
  };
161
162
  exports.signAndSendTransaction = signAndSendTransaction;
163
+ //swap
164
+ //you will. use jupiter for this
165
+ const getJupiterQuote = async (inputMint, outputMint, amount, slippageBps = 50) => {
166
+ const params = new URLSearchParams({
167
+ inputMint,
168
+ outputMint,
169
+ amount: amount.toString(),
170
+ slippageBps: slippageBps.toString(),
171
+ onlyDirectRoutes: 'false',
172
+ asLegacyTransaction: 'false'
173
+ });
174
+ const response = await fetch(`${JUPITER_BASE_URL}/swap/v1/quote?${params}`);
175
+ if (!response.ok) {
176
+ const error = await response.json();
177
+ throw new Error(`Jupiter quote failed: ${error.message || response.statusText}`);
178
+ }
179
+ return await response.json();
180
+ };
181
+ exports.getJupiterQuote = getJupiterQuote;
182
+ const buildJupiterSwapTransaction = async (quote, userPublicKey, prioritizationFeeLamports) => {
183
+ const body = {
184
+ quoteResponse: quote,
185
+ userPublicKey,
186
+ wrapAndUnwrapSol: true,
187
+ useSharedAccounts: true,
188
+ feeAccount: undefined,
189
+ trackingAccount: undefined,
190
+ computeUnitPriceMicroLamports: undefined,
191
+ prioritizationFeeLamports: prioritizationFeeLamports || 1000,
192
+ asLegacyTransaction: false,
193
+ useTokenLedger: false,
194
+ destinationTokenAccount: undefined,
195
+ dynamicComputeUnitLimit: true,
196
+ skipUserAccountsRpcCalls: false
197
+ };
198
+ const response = await fetch(`${JUPITER_BASE_URL}/swap/v1/swap`, {
199
+ method: 'POST',
200
+ headers: {
201
+ 'Content-Type': 'application/json',
202
+ },
203
+ body: JSON.stringify(body),
204
+ });
205
+ if (!response.ok) {
206
+ const error = await response.json();
207
+ throw new Error(`Jupiter swap transaction build failed: ${error.message || response.statusText}`);
208
+ }
209
+ return await response.json();
210
+ };
211
+ exports.buildJupiterSwapTransaction = buildJupiterSwapTransaction;
212
+ const executeJupiterSwap = async (swapParams, connection, payer) => {
213
+ try {
214
+ console.log('Getting Jupiter quote...');
215
+ const quote = await (0, exports.getJupiterQuote)(swapParams.fromToken.toString(), swapParams.toToken.toString(), swapParams.amount, swapParams.slippageBps);
216
+ console.log('Quote received:', {
217
+ inputAmount: quote.inAmount,
218
+ outputAmount: quote.outAmount,
219
+ priceImpact: quote.priceImpactPct
220
+ });
221
+ console.log('Building swap transaction...');
222
+ const swapResponse = await (0, exports.buildJupiterSwapTransaction)(quote, swapParams.userPublicKey.toString());
223
+ console.log('Deserializing transaction...');
224
+ const swapTransactionBuf = Buffer.from(swapResponse.swapTransaction, 'base64');
225
+ const transaction = web3_js_1.VersionedTransaction.deserialize(swapTransactionBuf);
226
+ console.log('Signing transaction...');
227
+ transaction.sign([payer]);
228
+ console.log('Sending transaction...');
229
+ const blockhash = await connection.getLatestBlockhash();
230
+ const signature = await (0, transactionSender_1.transactionSenderAndConfirmationWaiter)({
231
+ connection,
232
+ serializedTransaction: Buffer.from(transaction.serialize()),
233
+ blockhashWithExpiryBlockHeight: {
234
+ blockhash: blockhash.blockhash,
235
+ lastValidBlockHeight: blockhash.lastValidBlockHeight
236
+ }
237
+ });
238
+ if (!signature) {
239
+ return {
240
+ success: false,
241
+ error: 'Transaction failed to confirm'
242
+ };
243
+ }
244
+ console.log('Swap successful! Signature:', signature.transaction.signatures[0]);
245
+ return {
246
+ success: true,
247
+ hash: signature.transaction.signatures[0],
248
+ inputAmount: quote.inAmount,
249
+ outputAmount: quote.outAmount,
250
+ priceImpact: quote.priceImpactPct
251
+ };
252
+ }
253
+ catch (error) {
254
+ console.error('Jupiter swap failed:', error);
255
+ return {
256
+ success: false,
257
+ error: error instanceof Error ? error.message : 'Unknown error occurred'
258
+ };
259
+ }
260
+ };
261
+ exports.executeJupiterSwap = executeJupiterSwap;
262
+ const uiAmountToBaseUnits = (uiAmount, decimals) => {
263
+ return Math.floor(uiAmount * Math.pow(10, decimals));
264
+ };
265
+ exports.uiAmountToBaseUnits = uiAmountToBaseUnits;
266
+ const baseUnitsToUiAmount = (baseAmount, decimals) => {
267
+ return Number(baseAmount) / Math.pow(10, decimals);
268
+ };
269
+ exports.baseUnitsToUiAmount = baseUnitsToUiAmount;
270
+ const getJupiterTokenList = async () => {
271
+ try {
272
+ const response = await fetch(`${JUPITER_BASE_URL}/tokens/v1/mints/tradable`);
273
+ if (!response.ok) {
274
+ throw new Error(`Failed to fetch token list: ${response.statusText}`);
275
+ }
276
+ return await response.json();
277
+ }
278
+ catch (error) {
279
+ console.error('Failed to fetch Jupiter token list:', error);
280
+ return [];
281
+ }
282
+ };
283
+ exports.getJupiterTokenList = getJupiterTokenList;
284
+ const validateJupiterTokens = async (inputMint, outputMint) => {
285
+ try {
286
+ const tokenList = await (0, exports.getJupiterTokenList)();
287
+ const inputSupported = tokenList.includes(inputMint);
288
+ const outputSupported = tokenList.includes(outputMint);
289
+ if (!inputSupported && !outputSupported) {
290
+ return { valid: false, message: 'Both input and output tokens are not supported' };
291
+ }
292
+ if (!inputSupported) {
293
+ return { valid: false, message: 'Input token is not supported' };
294
+ }
295
+ if (!outputSupported) {
296
+ return { valid: false, message: 'Output token is not supported' };
297
+ }
298
+ return { valid: true };
299
+ }
300
+ catch (error) {
301
+ return { valid: false, message: 'Failed to validate tokens' };
302
+ }
303
+ };
304
+ exports.validateJupiterTokens = validateJupiterTokens;
@@ -1,10 +1,9 @@
1
1
  import { vmTypes } from "./types";
2
2
  export declare abstract class VM<AddressType, PrivateKeyType, ConnectionType> {
3
- protected mnemonic: string;
4
3
  protected seed: string;
5
4
  type: vmTypes;
6
- constructor(mnemonic: string, vm: vmTypes);
7
- mnemonicToSeed: (mnemonic: string) => string;
5
+ constructor(seed: string, vm: vmTypes);
6
+ static mnemonicToSeed: (mnemonic: string) => string;
8
7
  abstract derivationPath: string;
9
8
  abstract generatePrivateKey(index: number, mnemonic?: string, derivationPath?: string): {
10
9
  privateKey: PrivateKeyType;
package/dist/utils/vm.js CHANGED
@@ -37,13 +37,12 @@ exports.VM = void 0;
37
37
  const bip39 = __importStar(require("bip39"));
38
38
  // Abstract Base Classes
39
39
  class VM {
40
- constructor(mnemonic, vm) {
41
- this.mnemonicToSeed = (mnemonic) => {
42
- return bip39.mnemonicToSeedSync(mnemonic).toString("hex");
43
- };
44
- this.mnemonic = mnemonic;
40
+ constructor(seed, vm) {
45
41
  this.type = vm;
46
- this.seed = this.mnemonicToSeed(this.mnemonic);
42
+ this.seed = seed;
47
43
  }
48
44
  }
49
45
  exports.VM = VM;
46
+ VM.mnemonicToSeed = (mnemonic) => {
47
+ return bip39.mnemonicToSeedSync(mnemonic).toString("hex");
48
+ };
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@deserialize/multi-vm-wallet",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "devDependencies": {
5
5
  "@types/bn.js": "^5.2.0",
6
- "@types/node": "^24.1.0",
7
- "@types/promise-retry": "^1.1.6"
6
+ "@types/node": "^24.2.1",
7
+ "@types/promise-retry": "^1.1.6",
8
+ "ts-node-dev": "^2.0.0",
9
+ "typescript": "^5.9.2"
8
10
  },
9
11
  "dependencies": {
10
12
  "@solana/spl-token": "^0.4.13",
@@ -22,7 +24,8 @@
22
24
  "types": "dist/index.d.ts",
23
25
  "scripts": {
24
26
  "test": "echo \"Error: no test specified\" && exit 1",
25
- "build": "sudo rm -r dist ; tsc -p tsconfig.json",
27
+ "build": "tsc -p tsconfig.json",
28
+ "dev": "ts-node-dev --respawn --transpile-only utils/index.ts",
26
29
  "publish:sdk": "npm run build && npm publish --access=public"
27
30
  },
28
31
  "repository": {
@@ -20,6 +20,8 @@ export abstract class ChainWallet<AddressType, PrivateKeyType, ConnectionType> {
20
20
  abstract getTokenBalance(tokenAddress: AddressType): Promise<Balance>;
21
21
  abstract transferNative(to: AddressType, amount: number): Promise<TransactionResult>;
22
22
  abstract transferToken(tokenAddress: TokenInfo, to: AddressType, amount: number): Promise<TransactionResult>;
23
+ abstract swap (tokenAddress: TokenInfo, to: AddressType, amount: number, slippage?: number): Promise<TransactionResult>;
24
+
23
25
  // abstract transferNFT(contractAddress: AddressType, tokenId: string, to: string): Promise<TransactionResult>;
24
26
  // abstract getTokenInfo(tokenAddress: string): Promise<TokenInfo>;
25
27
  // abstract getNFTInfo(contractAddress: string, tokenId: string): Promise<NFTInfo>;