@deserialize/multi-vm-wallet 1.0.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.
Files changed (43) hide show
  1. package/dist/tsconfig.tsbuildinfo +1 -0
  2. package/dist/utils/IChainWallet.d.ts +16 -0
  3. package/dist/utils/IChainWallet.js +22 -0
  4. package/dist/utils/bip32.d.ts +11 -0
  5. package/dist/utils/bip32.js +99 -0
  6. package/dist/utils/evm/evm.d.ts +30 -0
  7. package/dist/utils/evm/evm.js +72 -0
  8. package/dist/utils/evm/index.d.ts +2 -0
  9. package/dist/utils/evm/index.js +18 -0
  10. package/dist/utils/evm/utils.d.ts +92 -0
  11. package/dist/utils/evm/utils.js +346 -0
  12. package/dist/utils/index.d.ts +6 -0
  13. package/dist/utils/index.js +22 -0
  14. package/dist/utils/svm/index.d.ts +1 -0
  15. package/dist/utils/svm/index.js +17 -0
  16. package/dist/utils/svm/svm.d.ts +24 -0
  17. package/dist/utils/svm/svm.js +71 -0
  18. package/dist/utils/svm/transactionSender.d.ts +8 -0
  19. package/dist/utils/svm/transactionSender.js +83 -0
  20. package/dist/utils/svm/utils.d.ts +26 -0
  21. package/dist/utils/svm/utils.js +161 -0
  22. package/dist/utils/types.d.ts +44 -0
  23. package/dist/utils/types.js +9 -0
  24. package/dist/utils/vm.d.ts +13 -0
  25. package/dist/utils/vm.js +49 -0
  26. package/package.json +42 -0
  27. package/tsconfig.json +115 -0
  28. package/utils/IChainWallet.ts +36 -0
  29. package/utils/bip32.ts +66 -0
  30. package/utils/evm/evm.ts +84 -0
  31. package/utils/evm/index.ts +2 -0
  32. package/utils/evm/utils.ts +504 -0
  33. package/utils/index.ts +6 -0
  34. package/utils/svm/index.js +17 -0
  35. package/utils/svm/index.ts +1 -0
  36. package/utils/svm/svm.js +71 -0
  37. package/utils/svm/svm.ts +75 -0
  38. package/utils/svm/transactionSender.js +83 -0
  39. package/utils/svm/transactionSender.ts +108 -0
  40. package/utils/svm/utils.js +161 -0
  41. package/utils/svm/utils.ts +203 -0
  42. package/utils/types.ts +53 -0
  43. package/utils/vm.ts +26 -0
@@ -0,0 +1,75 @@
1
+ import { Connection, Keypair, PublicKey } from "@solana/web3.js";
2
+ import { SVMDeriveChildPrivateKey } from "../bip32";
3
+ import { VM } from "../vm";
4
+ import { ChainWallet } from "../IChainWallet";
5
+ import { Balance, ChainWalletConfig, TokenInfo, TransactionResult } from "../types";
6
+ import { getSvmNativeBalance, getTokenBalance, getTransferNativeTransaction, getTransferTokenTransaction, signAndSendTransaction } from "./utils";
7
+ import BN from "bn.js";
8
+
9
+ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
10
+ derivationPath = "m/44'/501'/"; // Default EVM derivation path
11
+
12
+ constructor(mnemonic: string) {
13
+ super(mnemonic, "SVM");
14
+ }
15
+ static validateAddress(address: PublicKey): boolean {
16
+ return PublicKey.isOnCurve(address.toBuffer());
17
+ }
18
+ static getNativeBalance(address: PublicKey, connection: Connection): Promise<Balance> {
19
+ return getSvmNativeBalance(address, connection);
20
+ }
21
+ static async getTokenBalance(address: PublicKey, tokenAddress: PublicKey, connection: Connection): Promise<Balance> {
22
+ const balance = await getTokenBalance(address, tokenAddress, connection);
23
+ if (balance === 0) {
24
+ return { balance: new BN(0), formatted: 0, decimal: 0 };
25
+ }
26
+ return { balance: new BN(balance.amount), formatted: balance.uiAmount || parseInt(balance.amount) / 10 ** balance.decimals, decimal: balance.decimals };
27
+ }
28
+
29
+ static signAndSendTransaction = signAndSendTransaction
30
+ generatePrivateKey(index: number, seedPhrase = this.mnemonic, derivationPath = this.derivationPath) {
31
+ const seed = this.mnemonicToSeed(seedPhrase);
32
+ const privateKey = SVMDeriveChildPrivateKey(seed, index, derivationPath);
33
+ return { privateKey, index };
34
+ }
35
+
36
+ }
37
+
38
+ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection> {
39
+ constructor(config: ChainWalletConfig, privateKey: Keypair, index: number) {
40
+ super(config, privateKey, index);
41
+ this.address = privateKey.publicKey;
42
+ this.privateKey = privateKey;
43
+ this.connection = new Connection(config.rpcUrl)
44
+ }
45
+ generateAddress() {
46
+ return this.address;
47
+ }
48
+ async getNativeBalance(): Promise<Balance> {
49
+ // Implement native balance retrieval logic here
50
+ return await SVMVM.getNativeBalance(this.address, this.connection!)
51
+ }
52
+
53
+ async getTokenBalance(tokenAddress: PublicKey): Promise<Balance> {
54
+ // Implement token balance retrieval logic here
55
+ return await SVMVM.getTokenBalance(this.address, (tokenAddress), this.connection!);
56
+ }
57
+
58
+ async transferNative(to: PublicKey, amount: number): Promise<TransactionResult> {
59
+ // Implement native transfer logic here
60
+ const transaction = await getTransferNativeTransaction(this.privateKey, to, amount, this.connection!)
61
+ const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!, [this.privateKey]);
62
+ return { success: true, hash } // Placeholder
63
+ }
64
+
65
+ async transferToken(token: TokenInfo, to: PublicKey, amount: number): Promise<TransactionResult> {
66
+ // Implement token transfer logic here
67
+ const transaction = await getTransferTokenTransaction(this.privateKey, new PublicKey(to), token, (amount), this.connection!);
68
+ const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!, [this.privateKey]);
69
+ return { success: true, hash }; // Placeholder
70
+ }
71
+ }
72
+
73
+
74
+ //swaps jupiter swap here
75
+
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.transactionSenderAndConfirmationWaiter = transactionSenderAndConfirmationWaiter;
7
+ const web3_js_1 = require("@solana/web3.js");
8
+ const promise_retry_1 = __importDefault(require("promise-retry"));
9
+ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10
+ const SEND_OPTIONS = {
11
+ skipPreflight: false,
12
+ };
13
+ async function transactionSenderAndConfirmationWaiter({ connection, serializedTransaction, blockhashWithExpiryBlockHeight, }) {
14
+ const txid = await connection.sendRawTransaction(serializedTransaction, SEND_OPTIONS);
15
+ const controller = new AbortController();
16
+ const abortSignal = controller.signal;
17
+ const abortableResender = async () => {
18
+ while (true) {
19
+ await wait(2000);
20
+ if (abortSignal.aborted)
21
+ return;
22
+ try {
23
+ await connection.sendRawTransaction(serializedTransaction, SEND_OPTIONS);
24
+ }
25
+ catch (e) {
26
+ console.warn(`Failed to resend transaction: ${e}`);
27
+ }
28
+ }
29
+ };
30
+ try {
31
+ abortableResender();
32
+ const lastValidBlockHeight = blockhashWithExpiryBlockHeight.lastValidBlockHeight - 150;
33
+ // this would throw TransactionExpiredBlockheightExceededError
34
+ await Promise.race([
35
+ connection.confirmTransaction({
36
+ ...blockhashWithExpiryBlockHeight,
37
+ lastValidBlockHeight,
38
+ signature: txid,
39
+ abortSignal,
40
+ }, "confirmed"),
41
+ new Promise(async (resolve) => {
42
+ // in case ws socket died
43
+ while (!abortSignal.aborted) {
44
+ await wait(2000);
45
+ const tx = await connection.getSignatureStatus(txid, {
46
+ searchTransactionHistory: false,
47
+ });
48
+ if (tx?.value?.confirmationStatus === "confirmed") {
49
+ resolve(tx);
50
+ }
51
+ }
52
+ }),
53
+ ]);
54
+ }
55
+ catch (e) {
56
+ if (e instanceof web3_js_1.TransactionExpiredBlockheightExceededError) {
57
+ // we consume this error and getTransaction would return null
58
+ return null;
59
+ }
60
+ else {
61
+ // invalid state from web3.js
62
+ throw e;
63
+ }
64
+ }
65
+ finally {
66
+ controller.abort();
67
+ }
68
+ // in case rpc is not synced yet, we add some retries
69
+ const response = (0, promise_retry_1.default)(async (retry) => {
70
+ const response = await connection.getTransaction(txid, {
71
+ commitment: "confirmed",
72
+ maxSupportedTransactionVersion: 0,
73
+ });
74
+ if (!response) {
75
+ retry(response);
76
+ }
77
+ return response;
78
+ }, {
79
+ retries: 5,
80
+ minTimeout: 1e3,
81
+ });
82
+ return response;
83
+ }
@@ -0,0 +1,108 @@
1
+ import {
2
+ BlockhashWithExpiryBlockHeight,
3
+ Connection,
4
+ TransactionExpiredBlockheightExceededError,
5
+ VersionedTransactionResponse,
6
+ } from "@solana/web3.js";
7
+ import promiseRetry from "promise-retry";
8
+ const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
9
+
10
+ type TransactionSenderAndConfirmationWaiterArgs = {
11
+ connection: Connection;
12
+ serializedTransaction: Buffer;
13
+ blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight;
14
+ };
15
+
16
+ const SEND_OPTIONS = {
17
+ skipPreflight: false,
18
+ };
19
+
20
+ export async function transactionSenderAndConfirmationWaiter({
21
+ connection,
22
+ serializedTransaction,
23
+ blockhashWithExpiryBlockHeight,
24
+ }: TransactionSenderAndConfirmationWaiterArgs): Promise<VersionedTransactionResponse | null> {
25
+ const txid = await connection.sendRawTransaction(
26
+ serializedTransaction,
27
+ SEND_OPTIONS
28
+ );
29
+
30
+ const controller = new AbortController();
31
+ const abortSignal = controller.signal;
32
+
33
+ const abortableResender = async () => {
34
+ while (true) {
35
+ await wait(2_000);
36
+ if (abortSignal.aborted) return;
37
+ try {
38
+ await connection.sendRawTransaction(
39
+ serializedTransaction,
40
+ SEND_OPTIONS
41
+ );
42
+ } catch (e) {
43
+ console.warn(`Failed to resend transaction: ${e}`);
44
+ }
45
+ }
46
+ };
47
+
48
+ try {
49
+ abortableResender();
50
+ const lastValidBlockHeight =
51
+ blockhashWithExpiryBlockHeight.lastValidBlockHeight - 150;
52
+
53
+ // this would throw TransactionExpiredBlockheightExceededError
54
+ await Promise.race([
55
+ connection.confirmTransaction(
56
+ {
57
+ ...blockhashWithExpiryBlockHeight,
58
+ lastValidBlockHeight,
59
+ signature: txid,
60
+ abortSignal,
61
+ },
62
+ "confirmed"
63
+ ),
64
+ new Promise(async (resolve) => {
65
+ // in case ws socket died
66
+ while (!abortSignal.aborted) {
67
+ await wait(2_000);
68
+ const tx = await connection.getSignatureStatus(txid, {
69
+ searchTransactionHistory: false,
70
+ });
71
+ if (tx?.value?.confirmationStatus === "confirmed") {
72
+ resolve(tx);
73
+ }
74
+ }
75
+ }),
76
+ ]);
77
+ } catch (e) {
78
+ if (e instanceof TransactionExpiredBlockheightExceededError) {
79
+ // we consume this error and getTransaction would return null
80
+ return null;
81
+ } else {
82
+ // invalid state from web3.js
83
+ throw e;
84
+ }
85
+ } finally {
86
+ controller.abort();
87
+ }
88
+
89
+ // in case rpc is not synced yet, we add some retries
90
+ const response = promiseRetry(
91
+ async (retry) => {
92
+ const response = await connection.getTransaction(txid, {
93
+ commitment: "confirmed",
94
+ maxSupportedTransactionVersion: 0,
95
+ });
96
+ if (!response) {
97
+ retry(response);
98
+ }
99
+ return response;
100
+ },
101
+ {
102
+ retries: 5,
103
+ minTimeout: 1e3,
104
+ }
105
+ );
106
+
107
+ return response;
108
+ }
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ //we will write all the svm utils function here
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;
5
+ const spl_token_1 = require("@solana/spl-token");
6
+ const web3_js_1 = require("@solana/web3.js");
7
+ const transactionSender_1 = require("./transactionSender");
8
+ const bn_js_1 = require("bn.js");
9
+ const createV0Transaction = async (connection, inX, signers, payerPubKey, blockHash) => {
10
+ const blockhash = blockHash || (await connection.getLatestBlockhash()).blockhash;
11
+ const message = new web3_js_1.TransactionMessage({
12
+ payerKey: payerPubKey,
13
+ instructions: inX,
14
+ recentBlockhash: blockhash,
15
+ }).compileToV0Message();
16
+ const transaction = new web3_js_1.VersionedTransaction(message);
17
+ transaction.message.staticAccountKeys;
18
+ if (signers.length < 1) {
19
+ transaction.sign(signers);
20
+ }
21
+ return transaction;
22
+ };
23
+ exports.createV0Transaction = createV0Transaction;
24
+ const createAtaAndIx = async (token, ownerPublicKey, tokenProgramId, connection) => {
25
+ let AtaTokenIx;
26
+ const associatedToken = (0, spl_token_1.getAssociatedTokenAddressSync)(token, ownerPublicKey, false, tokenProgramId);
27
+ const accountExist = await connection.getAccountInfo(associatedToken);
28
+ if (!accountExist) {
29
+ AtaTokenIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(ownerPublicKey, associatedToken, ownerPublicKey, token, tokenProgramId);
30
+ }
31
+ return {
32
+ AtaTokenIx,
33
+ associatedToken,
34
+ };
35
+ };
36
+ exports.createAtaAndIx = createAtaAndIx;
37
+ const getSureAssociatedTokenAddressAndAccount = async (connection, token, owner) => {
38
+ let ATA;
39
+ let programId;
40
+ let tokenAccount;
41
+ try {
42
+ programId = token.equals(spl_token_1.NATIVE_MINT)
43
+ ? spl_token_1.TOKEN_PROGRAM_ID
44
+ : spl_token_1.TOKEN_2022_PROGRAM_ID;
45
+ ATA = (0, spl_token_1.getAssociatedTokenAddressSync)(token, owner, true, programId);
46
+ tokenAccount = await (0, spl_token_1.getAccount)(connection, ATA, "confirmed", programId);
47
+ return { ATA, programId, tokenAccount };
48
+ }
49
+ catch (error) {
50
+ programId = spl_token_1.TOKEN_PROGRAM_ID;
51
+ ATA = (0, spl_token_1.getAssociatedTokenAddressSync)(token, owner, true, programId);
52
+ tokenAccount = await (0, spl_token_1.getAccount)(connection, ATA, "confirmed", programId);
53
+ return { ATA, programId, tokenAccount };
54
+ }
55
+ };
56
+ exports.getSureAssociatedTokenAddressAndAccount = getSureAssociatedTokenAddressAndAccount;
57
+ const getProgramIdOfToken = async (owner, token, connection) => {
58
+ if (token.equals(spl_token_1.NATIVE_MINT)) {
59
+ return spl_token_1.TOKEN_PROGRAM_ID;
60
+ }
61
+ let ATA;
62
+ let programId = spl_token_1.TOKEN_PROGRAM_ID;
63
+ let tokenAccount;
64
+ try {
65
+ ATA = (0, spl_token_1.getAssociatedTokenAddressSync)(token, owner, true, programId);
66
+ tokenAccount = await (0, spl_token_1.getAccount)(connection, ATA, "confirmed", programId);
67
+ return spl_token_1.TOKEN_PROGRAM_ID;
68
+ }
69
+ catch (error) {
70
+ return spl_token_1.TOKEN_2022_PROGRAM_ID;
71
+ }
72
+ };
73
+ exports.getProgramIdOfToken = getProgramIdOfToken;
74
+ //get native balance
75
+ const getSvmNativeBalance = async (address, connection) => {
76
+ const balance = await connection.getBalance(address);
77
+ return { balance: new bn_js_1.BN(balance), formatted: balance / web3_js_1.LAMPORTS_PER_SOL, decimal: 9 };
78
+ };
79
+ exports.getSvmNativeBalance = getSvmNativeBalance;
80
+ const getTokenBalance = async (address, token, connection) => {
81
+ try {
82
+ // Get the balance from the token account
83
+ const tokenAccount = await (0, exports.getTokenAccountAccount)(token, address, connection);
84
+ if (!tokenAccount) {
85
+ console.error("Token account not found");
86
+ return 0;
87
+ }
88
+ const tokenBalance = await connection.getTokenAccountBalance(tokenAccount.address);
89
+ if (!tokenBalance) {
90
+ console.error("Token balance not found");
91
+ return 0;
92
+ }
93
+ return tokenBalance.value;
94
+ }
95
+ catch (error) {
96
+ return 0;
97
+ }
98
+ };
99
+ exports.getTokenBalance = getTokenBalance;
100
+ const getTokenAccountAccount = async (token, address, connection) => {
101
+ try {
102
+ // Get the associated token account address for the user and the token mint
103
+ const associatedTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(token, // The token mint address
104
+ address // The user's public key
105
+ );
106
+ // Fetch the token account information
107
+ const tokenAccount = await (0, spl_token_1.getAccount)(connection, associatedTokenAccount);
108
+ return tokenAccount;
109
+ }
110
+ catch (error) {
111
+ console.error("Error getting token balance:");
112
+ return null;
113
+ }
114
+ };
115
+ exports.getTokenAccountAccount = getTokenAccountAccount;
116
+ const getTransferNativeInx = async (from, to, amount) => {
117
+ return web3_js_1.SystemProgram.transfer({
118
+ fromPubkey: from,
119
+ toPubkey: to,
120
+ lamports: amount * web3_js_1.LAMPORTS_PER_SOL, // Convert SOL to lamports
121
+ });
122
+ };
123
+ exports.getTransferNativeInx = getTransferNativeInx;
124
+ const getTransferNativeTransaction = async (from, to, amount, connection) => {
125
+ const instruction = await (0, exports.getTransferNativeInx)(from.publicKey, to, amount);
126
+ const transaction = await (0, exports.createV0Transaction)(connection, [instruction], [from], from.publicKey);
127
+ return transaction;
128
+ };
129
+ exports.getTransferNativeTransaction = getTransferNativeTransaction;
130
+ const getTransferTokenInx = async (from, to, token, amount, connection) => {
131
+ const inx = [];
132
+ const tokenToSend = new web3_js_1.PublicKey(token.address);
133
+ const { ATA: source, programId, tokenAccount } = await (0, exports.getSureAssociatedTokenAddressAndAccount)(connection, from, tokenToSend);
134
+ const { associatedToken: destination, AtaTokenIx } = await (0, exports.createAtaAndIx)(tokenToSend, to, programId, connection);
135
+ if (!tokenAccount) {
136
+ throw new Error("Token account not found");
137
+ }
138
+ if (AtaTokenIx) {
139
+ inx.push(AtaTokenIx);
140
+ }
141
+ const tInx = (0, spl_token_1.createTransferCheckedInstruction)(source, tokenToSend, destination, from, amount, token.decimals, undefined, programId);
142
+ inx.push(tInx);
143
+ return inx;
144
+ };
145
+ exports.getTransferTokenInx = getTransferTokenInx;
146
+ const getTransferTokenTransaction = async (from, to, token, amount, connection) => {
147
+ const instruction = await (0, exports.getTransferTokenInx)(from.publicKey, to, token, amount, connection);
148
+ const transaction = await (0, exports.createV0Transaction)(connection, instruction, [from], from.publicKey);
149
+ return transaction;
150
+ };
151
+ exports.getTransferTokenTransaction = getTransferTokenTransaction;
152
+ const signAndSendTransaction = async (transaction, connection, signers) => {
153
+ transaction.sign(signers);
154
+ const blockhash = await connection.getLatestBlockhash();
155
+ const res = await (0, transactionSender_1.transactionSenderAndConfirmationWaiter)({ connection, serializedTransaction: Buffer.from(transaction.serialize()), blockhashWithExpiryBlockHeight: { blockhash: blockhash.blockhash, lastValidBlockHeight: blockhash.lastValidBlockHeight } });
156
+ if (!res) {
157
+ throw new Error("Transaction failed to send or confirm");
158
+ }
159
+ return res.transaction.signatures[0];
160
+ };
161
+ exports.signAndSendTransaction = signAndSendTransaction;
@@ -0,0 +1,203 @@
1
+ //we will write all the svm utils function here
2
+
3
+ import { Account, createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, getAccount, getAssociatedTokenAddress, getAssociatedTokenAddressSync, NATIVE_MINT, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token";
4
+ import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
5
+ import { TokenInfo } from "../types";
6
+ import { transactionSenderAndConfirmationWaiter } from "./transactionSender";
7
+ import { BN } from "bn.js";
8
+ export const createV0Transaction = async (
9
+ connection: Connection,
10
+ inX: TransactionInstruction[],
11
+ signers: Keypair[],
12
+ payerPubKey: PublicKey,
13
+ blockHash?: string
14
+ ) => {
15
+ const blockhash =
16
+ blockHash || (await connection.getLatestBlockhash()).blockhash;
17
+ const message = new TransactionMessage({
18
+ payerKey: payerPubKey,
19
+ instructions: inX,
20
+ recentBlockhash: blockhash,
21
+ }).compileToV0Message();
22
+
23
+ const transaction = new VersionedTransaction(message);
24
+ transaction.message.staticAccountKeys;
25
+ if (signers.length < 1) {
26
+ transaction.sign(signers);
27
+ }
28
+
29
+ return transaction;
30
+ };
31
+
32
+ export const createAtaAndIx = async (
33
+ token: PublicKey,
34
+ ownerPublicKey: PublicKey,
35
+ tokenProgramId: PublicKey,
36
+ connection: Connection,
37
+ ) => {
38
+ let AtaTokenIx;
39
+ const associatedToken = getAssociatedTokenAddressSync(
40
+ token,
41
+ ownerPublicKey,
42
+ false,
43
+ tokenProgramId
44
+ );
45
+
46
+ const accountExist = await connection.getAccountInfo(associatedToken);
47
+ if (!accountExist) {
48
+ AtaTokenIx = createAssociatedTokenAccountIdempotentInstruction(
49
+ ownerPublicKey,
50
+ associatedToken,
51
+ ownerPublicKey,
52
+ token,
53
+ tokenProgramId
54
+ );
55
+ }
56
+ return {
57
+ AtaTokenIx,
58
+ associatedToken,
59
+ };
60
+ };
61
+ export const getSureAssociatedTokenAddressAndAccount = async (
62
+ connection: Connection,
63
+ token: PublicKey,
64
+ owner: PublicKey,
65
+ ) => {
66
+ let ATA: PublicKey;
67
+ let programId: PublicKey;
68
+ let tokenAccount: Account;
69
+ try {
70
+ programId = token.equals(NATIVE_MINT)
71
+ ? TOKEN_PROGRAM_ID
72
+ : TOKEN_2022_PROGRAM_ID;
73
+ ATA = getAssociatedTokenAddressSync(token, owner, true, programId);
74
+ tokenAccount = await getAccount(connection, ATA, "confirmed", programId);
75
+ return { ATA, programId, tokenAccount };
76
+ } catch (error) {
77
+ programId = TOKEN_PROGRAM_ID;
78
+ ATA = getAssociatedTokenAddressSync(token, owner, true, programId);
79
+ tokenAccount = await getAccount(connection, ATA, "confirmed", programId);
80
+ return { ATA, programId, tokenAccount };
81
+ }
82
+ };
83
+
84
+ export const getProgramIdOfToken = async (owner: PublicKey, token: PublicKey, connection: Connection) => {
85
+ if (token.equals(NATIVE_MINT)) {
86
+ return TOKEN_PROGRAM_ID;
87
+ }
88
+ let ATA: PublicKey;
89
+ let programId: PublicKey = TOKEN_PROGRAM_ID
90
+ let tokenAccount: Account;
91
+ try {
92
+ ATA = getAssociatedTokenAddressSync(token, owner, true, programId);
93
+ tokenAccount = await getAccount(connection, ATA, "confirmed", programId);
94
+ return TOKEN_PROGRAM_ID
95
+ } catch (error) {
96
+ return TOKEN_2022_PROGRAM_ID;
97
+
98
+ }
99
+
100
+
101
+
102
+ }
103
+ //get native balance
104
+
105
+ export const getSvmNativeBalance = async (address: PublicKey, connection: Connection,) => {
106
+ const balance = await connection.getBalance(address);
107
+ return { balance: new BN(balance), formatted: balance / LAMPORTS_PER_SOL, decimal: 9 };
108
+ };
109
+
110
+ export const getTokenBalance = async (address: PublicKey, token: PublicKey, connection: Connection) => {
111
+
112
+ try {
113
+ // Get the balance from the token account
114
+ const tokenAccount = await getTokenAccountAccount(token, address, connection);
115
+ if (!tokenAccount) {
116
+ console.error("Token account not found");
117
+ return 0;
118
+ }
119
+ const tokenBalance = await connection.getTokenAccountBalance(
120
+ tokenAccount.address
121
+ );
122
+
123
+ if (!tokenBalance) {
124
+ console.error("Token balance not found");
125
+ return 0;
126
+ }
127
+
128
+ return tokenBalance.value;
129
+
130
+ } catch (error) {
131
+ return 0;
132
+ }
133
+ }
134
+
135
+ export const getTokenAccountAccount = async (token: PublicKey, address: PublicKey, connection: Connection): Promise<Account | null> => {
136
+ try {
137
+
138
+ // Get the associated token account address for the user and the token mint
139
+ const associatedTokenAccount = await getAssociatedTokenAddress(
140
+ token, // The token mint address
141
+ address // The user's public key
142
+ );
143
+ // Fetch the token account information
144
+ const tokenAccount = await getAccount(
145
+ connection,
146
+ associatedTokenAccount
147
+ );
148
+
149
+ return tokenAccount;
150
+ } catch (error) {
151
+ console.error("Error getting token balance:");
152
+ return null;
153
+ }
154
+ };
155
+
156
+ export const getTransferNativeInx = async (from: PublicKey, to: PublicKey, amount: number): Promise<TransactionInstruction> => {
157
+ return SystemProgram.transfer({
158
+ fromPubkey: from,
159
+ toPubkey: to,
160
+ lamports: amount * LAMPORTS_PER_SOL, // Convert SOL to lamports
161
+ })
162
+ }
163
+
164
+ export const getTransferNativeTransaction = async (from: Keypair, to: PublicKey, amount: number, connection: Connection) => {
165
+ const instruction = await getTransferNativeInx(from.publicKey, to, amount);
166
+ const transaction = await createV0Transaction(connection, [instruction], [from], from.publicKey);
167
+ return transaction;
168
+ }
169
+
170
+ export const getTransferTokenInx = async (from: PublicKey, to: PublicKey, token: TokenInfo, amount: number, connection: Connection): Promise<TransactionInstruction[]> => {
171
+ const inx: TransactionInstruction[] = []
172
+
173
+ const tokenToSend = new PublicKey(token.address);
174
+ const { ATA: source, programId, tokenAccount } = await getSureAssociatedTokenAddressAndAccount(connection, from, tokenToSend);
175
+ const { associatedToken: destination, AtaTokenIx } = await createAtaAndIx(tokenToSend, to, programId, connection);
176
+
177
+ if (!tokenAccount) {
178
+ throw new Error("Token account not found");
179
+ }
180
+ if (AtaTokenIx) {
181
+ inx.push(AtaTokenIx);
182
+ }
183
+ const tInx = createTransferCheckedInstruction(source, tokenToSend, destination, from, amount, token.decimals, undefined, programId)
184
+ inx.push(tInx);
185
+
186
+ return inx;
187
+
188
+ }
189
+ export const getTransferTokenTransaction = async (from: Keypair, to: PublicKey, token: TokenInfo, amount: number, connection: Connection): Promise<VersionedTransaction> => {
190
+ const instruction = await getTransferTokenInx(from.publicKey, to, token, amount, connection);
191
+ const transaction = await createV0Transaction(connection, instruction, [from], from.publicKey);
192
+ return transaction;
193
+ }
194
+ export const signAndSendTransaction = async (transaction: VersionedTransaction, connection: Connection, signers: Keypair[]) => {
195
+ transaction.sign(signers)
196
+ const blockhash = await connection.getLatestBlockhash()
197
+ const res = await transactionSenderAndConfirmationWaiter({ connection, serializedTransaction: Buffer.from(transaction.serialize()), blockhashWithExpiryBlockHeight: { blockhash: blockhash.blockhash, lastValidBlockHeight: blockhash.lastValidBlockHeight } })
198
+ if (!res) {
199
+ throw new Error("Transaction failed to send or confirm");
200
+ }
201
+ return res.transaction.signatures[0];
202
+
203
+ }
package/utils/types.ts ADDED
@@ -0,0 +1,53 @@
1
+ import BN from "bn.js"
2
+ import { EVMVM } from "./evm";
3
+ import { SVMVM } from "./svm";
4
+
5
+ export interface ChainWalletConfig {
6
+ chainId: string | number;
7
+ name: string;
8
+ rpcUrl: string;
9
+ explorerUrl: string;
10
+
11
+ nativeToken: {
12
+ name: string;
13
+ symbol: string;
14
+ decimals: number;
15
+ };
16
+ confirmationNo?: number
17
+ testnet?: boolean;
18
+ }
19
+
20
+ export interface TokenInfo {
21
+ address: string;
22
+ name: string;
23
+ symbol: string;
24
+ decimals: number;
25
+ }
26
+
27
+ export interface NFTInfo {
28
+ tokenId: string;
29
+ contractAddress: string;
30
+ name?: string;
31
+ description?: string;
32
+ image?: string;
33
+ }
34
+
35
+ export interface TransactionResult {
36
+ hash: string;
37
+ success: boolean;
38
+ error?: string;
39
+ }
40
+
41
+ export interface Balance {
42
+ balance: BN;
43
+ formatted: number;
44
+ decimal: number
45
+ }
46
+
47
+
48
+ export const SUPPORTED_VM = {
49
+ 'EVM': EVMVM,
50
+ 'SVM': SVMVM
51
+ } as const;
52
+
53
+ export type vmTypes = keyof typeof SUPPORTED_VM;