@deserialize/multi-vm-wallet 1.2.2 → 1.2.4
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/dist/IChainWallet.d.ts +6 -1
- package/dist/IChainWallet.js.map +1 -1
- package/dist/constant.js +32 -18
- package/dist/constant.js.map +1 -1
- package/dist/evm/evm.d.ts +5 -1
- package/dist/evm/evm.js +11 -2
- package/dist/evm/evm.js.map +1 -1
- package/dist/evm/transaction.utils.d.ts +362 -0
- package/dist/evm/transaction.utils.js +669 -0
- package/dist/evm/transaction.utils.js.map +1 -0
- package/dist/evm/transactionParsing.d.ts +1 -3633
- package/dist/evm/transactionParsing.js +0 -27
- package/dist/evm/transactionParsing.js.map +1 -1
- package/dist/evm/utils.d.ts +13 -1
- package/dist/evm/utils.js +101 -2
- package/dist/evm/utils.js.map +1 -1
- package/dist/helpers/index.d.ts +2 -1
- package/dist/helpers/index.js +5 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/svm/svm.d.ts +14 -4
- package/dist/svm/svm.js +25 -7
- package/dist/svm/svm.js.map +1 -1
- package/dist/svm/utils.d.ts +9 -3
- package/dist/svm/utils.js +94 -12
- package/dist/svm/utils.js.map +1 -1
- package/dist/test.d.ts +4 -0
- package/dist/test.js +38 -18
- package/dist/test.js.map +1 -1
- package/dist/types.d.ts +110 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -2
- package/utils/IChainWallet.ts +6 -3
- package/utils/constant.ts +34 -18
- package/utils/evm/evm.ts +17 -4
- package/utils/evm/transaction.utils.ts +824 -0
- package/utils/evm/transactionParsing.ts +0 -26
- package/utils/evm/utils.ts +110 -3
- package/utils/helpers/index.ts +7 -1
- package/utils/svm/svm.ts +40 -9
- package/utils/svm/utils.ts +131 -16
- package/utils/test.ts +48 -18
- package/utils/types.ts +140 -0
|
@@ -610,30 +610,4 @@ async function parseTransferLogs(
|
|
|
610
610
|
return { tokens, nfts };
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
-
/**
|
|
614
|
-
* Helper function to create a client
|
|
615
|
-
*/
|
|
616
|
-
export function createEVMClient(rpcUrl: string) {
|
|
617
|
-
return createPublicClient({
|
|
618
|
-
transport: http(rpcUrl),
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Example usage:
|
|
623
|
-
/*
|
|
624
|
-
import { mainnet } from 'viem/chains';
|
|
625
|
-
|
|
626
|
-
const client = createPublicClient({
|
|
627
|
-
chain: mainnet,
|
|
628
|
-
transport: http('https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY'),
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
const history = await getEVMTransactionHistoryWithAPI(
|
|
632
|
-
client,
|
|
633
|
-
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' as Address,
|
|
634
|
-
'https://api.etherscan.io/api',
|
|
635
|
-
'YOUR_ETHERSCAN_API_KEY'
|
|
636
|
-
);
|
|
637
613
|
|
|
638
|
-
console.log(history);
|
|
639
|
-
*/
|
package/utils/evm/utils.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Balance, ChainWalletConfig, SUPPORTED_VM, UserTokenBalance, TokenInfo } from '../types'
|
|
2
|
-
import { JsonRpcProvider, Contract, Wallet, TransactionRequest, TransactionResponse, TransactionReceipt, parseUnits, formatUnits } from 'ethers'
|
|
1
|
+
import { Balance, ChainWalletConfig, SUPPORTED_VM, UserTokenBalance, TokenInfo, EVMNFT, NFT } from '../types'
|
|
2
|
+
import { JsonRpcProvider, Contract, Wallet, TransactionRequest, TransactionResponse, TransactionReceipt, parseUnits, formatUnits, ethers } from 'ethers'
|
|
3
3
|
import BN from 'bn.js'
|
|
4
4
|
import { HelperAPI } from '../helpers';
|
|
5
|
+
import BigNumber from 'bignumber.js';
|
|
5
6
|
|
|
6
7
|
const KYBER_BASE_URL = 'https://aggregator-api.kyberswap.com';
|
|
7
8
|
|
|
@@ -149,10 +150,11 @@ const ERC20_ABI = [
|
|
|
149
150
|
|
|
150
151
|
export const getNativeBalance = async (address: string, provider: JsonRpcProvider): Promise<Balance> => {
|
|
151
152
|
const balance = await provider.getBalance(address)
|
|
153
|
+
const final = ethers.formatEther(balance)
|
|
152
154
|
|
|
153
155
|
return {
|
|
154
156
|
balance: new BN(balance),
|
|
155
|
-
formatted: Number(
|
|
157
|
+
formatted: Number(final),
|
|
156
158
|
decimal: 18
|
|
157
159
|
}
|
|
158
160
|
}
|
|
@@ -654,6 +656,24 @@ export const discoverTokens = async (wallet: string, chain: ChainWalletConfig):
|
|
|
654
656
|
return formatBalances
|
|
655
657
|
}
|
|
656
658
|
|
|
659
|
+
export function calcGasTotal(gasLimit = '0', gasPrice = '0') {
|
|
660
|
+
return new BN(gasLimit, 16).mul(new BN(gasPrice, 16)).toString();
|
|
661
|
+
}
|
|
662
|
+
export function toPrecisionWithoutTrailingZeros(n: number, precision: number) {
|
|
663
|
+
return new BigNumber(n)
|
|
664
|
+
.toPrecision(precision)
|
|
665
|
+
.replace(/(\.[0-9]*[1-9])0*|(\.0*)/u, '$1');
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* @param {number|string|BigNumber} value
|
|
670
|
+
* @param {number=} decimals
|
|
671
|
+
* @returns {BigNumber}
|
|
672
|
+
*/
|
|
673
|
+
export function calcTokenAmount(value: number | string | BigNumber, decimals?: number): BigNumber {
|
|
674
|
+
const divisor = new BigNumber(10).pow(decimals ?? 0);
|
|
675
|
+
return new BigNumber(String(value)).div(divisor);
|
|
676
|
+
}
|
|
657
677
|
//swaps
|
|
658
678
|
|
|
659
679
|
|
|
@@ -934,4 +954,91 @@ export function prepareSwapParams(
|
|
|
934
954
|
|
|
935
955
|
export function convertSlippageForDebonk(slippageBps: number): number {
|
|
936
956
|
return slippageBps / 100;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
export const transformEVMNFTToUnified = (nft: EVMNFT): NFT => {
|
|
960
|
+
// Extract image URL from various sources
|
|
961
|
+
const imageUrl = nft.image?.cachedUrl ||
|
|
962
|
+
nft.image?.thumbnailUrl ||
|
|
963
|
+
nft.image?.pngUrl ||
|
|
964
|
+
nft.image?.originalUrl ||
|
|
965
|
+
nft.openSeaMetadata?.imageUrl ||
|
|
966
|
+
nft.raw?.metadata?.image ||
|
|
967
|
+
undefined;
|
|
968
|
+
|
|
969
|
+
// Extract attributes
|
|
970
|
+
const attributes = nft.raw?.metadata?.attributes?.map(attr => ({
|
|
971
|
+
trait_type: attr.trait_type,
|
|
972
|
+
value: attr.value,
|
|
973
|
+
display_type: attr.display_type
|
|
974
|
+
}));
|
|
975
|
+
|
|
976
|
+
return {
|
|
977
|
+
id: `${nft.contract.address}:${nft.tokenId}`,
|
|
978
|
+
name: nft.name || nft.raw?.metadata?.name || 'Unknown',
|
|
979
|
+
symbol: nft.contract.symbol,
|
|
980
|
+
description: nft.description || nft.raw?.metadata?.description || '',
|
|
981
|
+
image: imageUrl,
|
|
982
|
+
uri: nft.raw?.tokenUri || '',
|
|
983
|
+
collection: {
|
|
984
|
+
address: nft.contract.address,
|
|
985
|
+
name: nft.openSeaMetadata?.collectionName || nft.contract.name,
|
|
986
|
+
verified: nft.openSeaMetadata?.safelistRequestStatus === 'verified'
|
|
987
|
+
},
|
|
988
|
+
chainType: 'EVM',
|
|
989
|
+
balance: nft.balance,
|
|
990
|
+
attributes,
|
|
991
|
+
tokenStandard: nft.tokenType,
|
|
992
|
+
isSpam: nft.contract.isSpam,
|
|
993
|
+
raw: {
|
|
994
|
+
evm: nft
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
export const discoverNFTs = async (wallet: string, chain: ChainWalletConfig): Promise<NFT[]> => {
|
|
1000
|
+
console.log('discoverNFTs: Starting NFT discovery');
|
|
1001
|
+
console.log('Wallet:', wallet);
|
|
1002
|
+
console.log('Chain:', chain.name, 'ChainId:', chain.chainId);
|
|
1003
|
+
|
|
1004
|
+
try {
|
|
1005
|
+
const response = await HelperAPI.getUserNFTs(wallet, chain.vmType ?? "EVM", chain.chainId);
|
|
1006
|
+
|
|
1007
|
+
console.log('discoverNFTs: Successfully fetched', response.data.length, 'NFTs');
|
|
1008
|
+
|
|
1009
|
+
// Filter out spam NFTs if desired (optional)
|
|
1010
|
+
const evmNfts = response.data.filter(nft => !nft.contract.isSpam);
|
|
1011
|
+
|
|
1012
|
+
console.log('discoverNFTs: After spam filtering:', evmNfts.length, 'NFTs');
|
|
1013
|
+
|
|
1014
|
+
// Transform to unified NFT format
|
|
1015
|
+
const nfts = evmNfts.map(transformEVMNFTToUnified);
|
|
1016
|
+
|
|
1017
|
+
return nfts;
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
console.error('discoverNFTs: Error fetching NFTs:', error);
|
|
1020
|
+
console.error('Error details:', error instanceof Error ? error.message : 'Unknown error');
|
|
1021
|
+
throw error;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
export const discoverAllNFTs = async (wallet: string, chain: ChainWalletConfig): Promise<NFT[]> => {
|
|
1026
|
+
console.log('discoverAllNFTs: Starting NFT discovery (including spam)');
|
|
1027
|
+
console.log('Wallet:', wallet);
|
|
1028
|
+
console.log('Chain:', chain.name, 'ChainId:', chain.chainId);
|
|
1029
|
+
|
|
1030
|
+
try {
|
|
1031
|
+
const response = await HelperAPI.getUserNFTs(wallet, chain.vmType ?? "EVM", chain.chainId);
|
|
1032
|
+
|
|
1033
|
+
console.log('discoverAllNFTs: Successfully fetched', response.data.length, 'NFTs (including spam)');
|
|
1034
|
+
|
|
1035
|
+
// Transform to unified NFT format
|
|
1036
|
+
const nfts = response.data.map(transformEVMNFTToUnified);
|
|
1037
|
+
|
|
1038
|
+
return nfts;
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
console.error('discoverAllNFTs: Error fetching NFTs:', error);
|
|
1041
|
+
console.error('Error details:', error instanceof Error ? error.message : 'Unknown error');
|
|
1042
|
+
throw error;
|
|
1043
|
+
}
|
|
937
1044
|
}
|
package/utils/helpers/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vmTypes } from "../types";
|
|
1
|
+
import { vmTypes, EVMNFTResponse } from "../types";
|
|
2
2
|
|
|
3
3
|
const BASE_URL = "https://helper.decane.app"
|
|
4
4
|
|
|
@@ -8,4 +8,10 @@ export class HelperAPI {
|
|
|
8
8
|
const data = await res.json();
|
|
9
9
|
return data;
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
static async getUserNFTs(wallet: string, vm: vmTypes, chainId: number): Promise<EVMNFTResponse> {
|
|
13
|
+
const res = await fetch("" + BASE_URL + `/${vm}/nfts/discover?wallet=${wallet}&chainId=${chainId}`);
|
|
14
|
+
const data = await res.json();
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
11
17
|
}
|
package/utils/svm/svm.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
|
1
|
+
import { Connection, Keypair, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
|
|
2
2
|
import { SVMDeriveChildPrivateKey } from "../walletBip32";
|
|
3
3
|
import { VM } from "../vm";
|
|
4
4
|
import { ChainWallet } from "../IChainWallet";
|
|
5
|
-
import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult } from "../types";
|
|
5
|
+
import { Balance, ChainWalletConfig, UserTokenBalance, TokenInfo, TransactionResult, NFT } from "../types";
|
|
6
6
|
import {
|
|
7
7
|
getSvmNativeBalance,
|
|
8
8
|
getTokenBalance,
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
validateJupiterTokens,
|
|
17
17
|
JupiterQuoteResponse,
|
|
18
18
|
getTokenInfo,
|
|
19
|
-
discoverTokens
|
|
19
|
+
discoverTokens,
|
|
20
|
+
signTransaction,
|
|
21
|
+
sendTransaction,
|
|
22
|
+
fetchWalletNfts
|
|
20
23
|
} from "./utils";
|
|
21
24
|
import BN from "bn.js";
|
|
22
25
|
import nacl from "tweetnacl";
|
|
@@ -26,6 +29,7 @@ import { getSVMTransactionHistory, SVMTransactionHistoryItem } from "./transacti
|
|
|
26
29
|
|
|
27
30
|
export class SVMVM extends VM<PublicKey, Keypair, Connection> {
|
|
28
31
|
getTokenInfo = getTokenInfo
|
|
32
|
+
static getTokenInfo = getTokenInfo
|
|
29
33
|
static validateAddress(address: PublicKey): boolean {
|
|
30
34
|
try {
|
|
31
35
|
new PublicKey(address)
|
|
@@ -54,6 +58,10 @@ export class SVMVM extends VM<PublicKey, Keypair, Connection> {
|
|
|
54
58
|
|
|
55
59
|
static signAndSendTransaction = signAndSendTransaction
|
|
56
60
|
|
|
61
|
+
static signTransaction = signTransaction
|
|
62
|
+
|
|
63
|
+
static sendTransaction = sendTransaction
|
|
64
|
+
|
|
57
65
|
|
|
58
66
|
generatePrivateKey(index: number, seed?: string, mnemonic?: string, derivationPath = this.derivationPath) {
|
|
59
67
|
let _seed: string
|
|
@@ -91,6 +99,8 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
|
|
|
91
99
|
return await SVMVM.getNativeBalance(this.address, this.connection!)
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
|
|
103
|
+
|
|
94
104
|
async getTokenBalance(tokenAddress: PublicKey): Promise<Balance> {
|
|
95
105
|
// Implement token balance retrieval logic here
|
|
96
106
|
return await SVMVM.getTokenBalance(this.address, (tokenAddress), this.connection!);
|
|
@@ -101,25 +111,47 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
|
|
|
101
111
|
return tokens
|
|
102
112
|
}
|
|
103
113
|
|
|
114
|
+
async discoverNFT(): Promise<NFT[]> {
|
|
115
|
+
// Implement NFT discovery logic here
|
|
116
|
+
const nfts = await fetchWalletNfts(this.address, this.connection!)
|
|
117
|
+
return nfts
|
|
118
|
+
}
|
|
119
|
+
|
|
104
120
|
async transferNative(to: PublicKey, amount: number): Promise<TransactionResult> {
|
|
105
121
|
// Implement native transfer logic here
|
|
106
122
|
const transaction = await getTransferNativeTransaction(this.privateKey, to, amount, this.connection!)
|
|
107
|
-
const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!,
|
|
123
|
+
const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!, this.privateKey);
|
|
108
124
|
return { success: true, hash } // Placeholder
|
|
109
125
|
}
|
|
110
126
|
|
|
111
127
|
async transferToken(token: TokenInfo, to: PublicKey, amount: number): Promise<TransactionResult> {
|
|
112
128
|
// Implement token transfer logic here
|
|
113
129
|
const transaction = await getTransferTokenTransaction(this.privateKey, new PublicKey(to), token, (amount), this.connection!);
|
|
114
|
-
const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!,
|
|
130
|
+
const hash = await SVMVM.signAndSendTransaction(transaction, this.connection!, this.privateKey);
|
|
115
131
|
return { success: true, hash }; // Placeholder
|
|
116
132
|
}
|
|
117
133
|
|
|
134
|
+
async signTransaction(transaction: VersionedTransaction | Transaction) {
|
|
135
|
+
return await SVMVM.signTransaction(transaction, this.privateKey)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async sendTransaction(transaction: VersionedTransaction | Transaction) {
|
|
139
|
+
return await SVMVM.sendTransaction(transaction, this.connection!)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async signAndSendTransaction(transaction: VersionedTransaction | Transaction) {
|
|
143
|
+
return await SVMVM.signAndSendTransaction(transaction, this.connection!, this.privateKey);
|
|
144
|
+
}
|
|
145
|
+
|
|
118
146
|
async getTransactionHistory(): Promise<SVMTransactionHistoryItem[]> {
|
|
119
147
|
const history = await getSVMTransactionHistory(this.connection!, this.address);
|
|
120
148
|
return history;
|
|
121
149
|
}
|
|
122
150
|
|
|
151
|
+
async getTokenInfo(tokenAddress: PublicKey) {
|
|
152
|
+
return await SVMVM.getTokenInfo(tokenAddress, this.connection!)
|
|
153
|
+
}
|
|
154
|
+
|
|
123
155
|
async swap(fromToken: TokenInfo, toToken: PublicKey, amount: number, slippage: number = 50): Promise<TransactionResult> {
|
|
124
156
|
try {
|
|
125
157
|
if (amount <= 0) {
|
|
@@ -235,9 +267,8 @@ export class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection>
|
|
|
235
267
|
};
|
|
236
268
|
}
|
|
237
269
|
}
|
|
238
|
-
signMessage = (message:
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
return base58.encode(signature);
|
|
270
|
+
signMessage = (message: Uint8Array<ArrayBuffer>,) => {
|
|
271
|
+
const signature = nacl.sign.detached(message, this.privateKey.secretKey);
|
|
272
|
+
return signature
|
|
242
273
|
};
|
|
243
274
|
}
|
package/utils/svm/utils.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
//we will write all the svm utils function here
|
|
2
2
|
|
|
3
3
|
import { Account, createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, getAccount, getAssociatedTokenAddress, getAssociatedTokenAddressSync, getMint, Mint, 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 { ChainWalletConfig, UserTokenBalance, TokenInfo } from "../types";
|
|
4
|
+
import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
|
|
5
|
+
import { ChainWalletConfig, UserTokenBalance, TokenInfo, SolanaNFT, NFT } from "../types";
|
|
6
6
|
import { transactionSenderAndConfirmationWaiter } from "./transactionSender";
|
|
7
7
|
import { BN } from "bn.js";
|
|
8
|
-
import {
|
|
8
|
+
import { generateSigner, percentAmount, publicKey } from '@metaplex-foundation/umi'
|
|
9
|
+
import {
|
|
10
|
+
createNft,
|
|
11
|
+
fetchDigitalAsset,
|
|
12
|
+
fetchAllDigitalAssetByOwner,
|
|
13
|
+
mplTokenMetadata,
|
|
14
|
+
} from '@metaplex-foundation/mpl-token-metadata'
|
|
15
|
+
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
|
|
16
|
+
|
|
17
|
+
import { PublicKey as UmiPublicKey } from "@metaplex-foundation/umi-public-keys"
|
|
9
18
|
|
|
10
19
|
const JUPITER_BASE_URL = 'https://lite-api.jup.ag';
|
|
11
20
|
|
|
@@ -271,15 +280,16 @@ export const getTransferNativeTransaction = async (from: Keypair, to: PublicKey,
|
|
|
271
280
|
console.log('getTransferNativeTransaction: Completed');
|
|
272
281
|
return transaction;
|
|
273
282
|
}
|
|
274
|
-
const getMetaTokenMetaplexData = (mintAddress: PublicKey, connection: Connection) => {
|
|
275
|
-
const
|
|
276
|
-
|
|
283
|
+
const getMetaTokenMetaplexData = async (mintAddress: PublicKey, connection: Connection) => {
|
|
284
|
+
const umi = createUmi(connection.rpcEndpoint).use(mplTokenMetadata())
|
|
285
|
+
const ass = await fetchDigitalAsset(umi, mintAddress.toBase58() as unknown as UmiPublicKey)
|
|
286
|
+
return ass.metadata
|
|
287
|
+
|
|
277
288
|
}
|
|
278
289
|
|
|
279
290
|
export const getTokenInfo = async (tokenAddress: PublicKey, connection: Connection, programId?: PublicKey): Promise<TokenInfo> => {
|
|
280
291
|
let mint: Mint
|
|
281
292
|
|
|
282
|
-
|
|
283
293
|
const metaplexData = await getMetaTokenMetaplexData(tokenAddress, connection).catch(() => null);
|
|
284
294
|
if (programId) {
|
|
285
295
|
const mint = await getMint(connection, tokenAddress, "confirmed", programId)
|
|
@@ -347,17 +357,31 @@ export const getTransferTokenTransaction = async (from: Keypair, to: PublicKey,
|
|
|
347
357
|
return transaction;
|
|
348
358
|
}
|
|
349
359
|
|
|
350
|
-
export const
|
|
351
|
-
|
|
352
|
-
|
|
360
|
+
export const signTransaction = async (
|
|
361
|
+
transaction: VersionedTransaction | Transaction,
|
|
362
|
+
signers: Keypair,
|
|
363
|
+
): Promise<VersionedTransaction | Transaction> => {
|
|
364
|
+
|
|
353
365
|
|
|
354
|
-
transaction
|
|
355
|
-
|
|
366
|
+
if (transaction instanceof Transaction) {
|
|
367
|
+
transaction.partialSign(signers);
|
|
356
368
|
|
|
357
|
-
|
|
358
|
-
|
|
369
|
+
} else {
|
|
370
|
+
transaction.sign([signers]);
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return transaction;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
export const sendTransaction = async (
|
|
378
|
+
transaction: VersionedTransaction | Transaction,
|
|
379
|
+
connection: Connection
|
|
380
|
+
): Promise<string> => {
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
const blockhash = await connection.getLatestBlockhash();
|
|
359
384
|
|
|
360
|
-
console.log('Sending transaction...');
|
|
361
385
|
const res = await transactionSenderAndConfirmationWaiter({
|
|
362
386
|
connection,
|
|
363
387
|
serializedTransaction: Buffer.from(transaction.serialize()),
|
|
@@ -375,7 +399,21 @@ export const signAndSendTransaction = async (transaction: VersionedTransaction,
|
|
|
375
399
|
const signature = res.transaction.signatures[0];
|
|
376
400
|
console.log('Transaction successful, signature:', signature);
|
|
377
401
|
return signature;
|
|
378
|
-
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export const signAndSendTransaction = async (
|
|
405
|
+
transaction: VersionedTransaction | Transaction,
|
|
406
|
+
connection: Connection,
|
|
407
|
+
signers: Keypair,
|
|
408
|
+
options?: { partialSign?: boolean }
|
|
409
|
+
): Promise<string> => {
|
|
410
|
+
console.log('signAndSendTransaction: Starting');
|
|
411
|
+
|
|
412
|
+
const signedTx = await signTransaction(transaction, signers);
|
|
413
|
+
const signature = await sendTransaction(signedTx, connection);
|
|
414
|
+
|
|
415
|
+
return signature;
|
|
416
|
+
};
|
|
379
417
|
export const discoverTokens = async (ownerAddress: PublicKey, connection: Connection): Promise<UserTokenBalance<PublicKey>[]> => {
|
|
380
418
|
|
|
381
419
|
const owner = new PublicKey(ownerAddress);
|
|
@@ -723,3 +761,80 @@ export const validateJupiterTokens = async (
|
|
|
723
761
|
}
|
|
724
762
|
};
|
|
725
763
|
|
|
764
|
+
export const transformSolanaNFTToUnified = (nft: SolanaNFT): NFT => {
|
|
765
|
+
return {
|
|
766
|
+
id: nft.mint,
|
|
767
|
+
name: nft.name,
|
|
768
|
+
symbol: nft.symbol,
|
|
769
|
+
description: '', // Will be populated from metadata URI if needed
|
|
770
|
+
image: undefined, // Will be populated from metadata URI if needed
|
|
771
|
+
uri: nft.uri,
|
|
772
|
+
collection: {
|
|
773
|
+
address: nft.mint,
|
|
774
|
+
name: nft.name,
|
|
775
|
+
verified: nft.creators?.some(c => c.verified) ?? false,
|
|
776
|
+
},
|
|
777
|
+
chainType: 'SVM',
|
|
778
|
+
balance: '1', // NFTs on Solana are typically quantity 1
|
|
779
|
+
creators: nft.creators,
|
|
780
|
+
sellerFeeBasisPoints: nft.sellerFeeBasisPoints,
|
|
781
|
+
tokenStandard: 'NonFungible',
|
|
782
|
+
raw: {
|
|
783
|
+
svm: nft
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
export const fetchWalletNfts = async (
|
|
789
|
+
walletAddress: PublicKey,
|
|
790
|
+
connection: Connection
|
|
791
|
+
): Promise<NFT[]> => {
|
|
792
|
+
console.log('fetchWalletNfts: Starting');
|
|
793
|
+
console.log('Wallet address:', walletAddress.toString());
|
|
794
|
+
|
|
795
|
+
try {
|
|
796
|
+
// Create UMI instance with the connection's RPC endpoint
|
|
797
|
+
const umi = createUmi(connection.rpcEndpoint).use(mplTokenMetadata());
|
|
798
|
+
console.log('UMI instance created with RPC endpoint:', connection.rpcEndpoint);
|
|
799
|
+
|
|
800
|
+
// Convert Solana PublicKey to UMI PublicKey
|
|
801
|
+
const owner = publicKey(walletAddress.toString());
|
|
802
|
+
console.log('Fetching NFTs for owner:', owner);
|
|
803
|
+
|
|
804
|
+
// Fetch all digital assets owned by the wallet
|
|
805
|
+
const assets = await fetchAllDigitalAssetByOwner(umi, owner);
|
|
806
|
+
console.log('Fetched assets count:', assets.length);
|
|
807
|
+
|
|
808
|
+
// Transform the assets into our SolanaNFT format
|
|
809
|
+
const solanaNfts: SolanaNFT[] = assets.map((asset) => {
|
|
810
|
+
const metadata = asset.metadata;
|
|
811
|
+
|
|
812
|
+
return {
|
|
813
|
+
mint: asset.publicKey.toString(),
|
|
814
|
+
name: metadata.name,
|
|
815
|
+
symbol: metadata.symbol,
|
|
816
|
+
uri: metadata.uri,
|
|
817
|
+
updateAuthority: metadata.updateAuthority.toString(),
|
|
818
|
+
sellerFeeBasisPoints: metadata.sellerFeeBasisPoints,
|
|
819
|
+
creators: metadata.creators && 'value' in metadata.creators && metadata.creators.value
|
|
820
|
+
? metadata.creators.value.map((creator) => ({
|
|
821
|
+
address: creator.address.toString(),
|
|
822
|
+
verified: creator.verified,
|
|
823
|
+
share: creator.share,
|
|
824
|
+
}))
|
|
825
|
+
: undefined,
|
|
826
|
+
};
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
// Transform to unified NFT format
|
|
830
|
+
const nfts = solanaNfts.map(transformSolanaNFTToUnified);
|
|
831
|
+
|
|
832
|
+
console.log('fetchWalletNfts: Successfully fetched', nfts.length, 'NFTs');
|
|
833
|
+
return nfts;
|
|
834
|
+
} catch (error) {
|
|
835
|
+
console.log('fetchWalletNfts: Error fetching NFTs:', error);
|
|
836
|
+
console.log('Error details:', error instanceof Error ? error.message : 'Unknown error');
|
|
837
|
+
throw error;
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
|
package/utils/test.ts
CHANGED
|
@@ -8,11 +8,13 @@ import { Connection, PublicKey, Keypair } from "@solana/web3.js";
|
|
|
8
8
|
import { SVMChainWallet, SVMVM, } from "./svm";
|
|
9
9
|
import { VM } from "./vm";
|
|
10
10
|
import { ChainWalletConfig } from "./types";
|
|
11
|
-
import { EVMChainWallet } from "./evm";
|
|
11
|
+
import { discoverNFTs, EVMChainWallet } from "./evm";
|
|
12
12
|
import { } from "./svm/transactionParsing";
|
|
13
13
|
import { getEVMTransactionHistory } from "./evm/transactionParsing";
|
|
14
14
|
import { createPublicClient, http, PublicClient } from "viem";
|
|
15
15
|
import { base, baseGoerli } from "viem/chains";
|
|
16
|
+
import { fetchWalletNfts, getTokenInfo } from "./svm/utils";
|
|
17
|
+
import { JsonRpcProvider } from "ethers";
|
|
16
18
|
// const mnemonic = GenerateNewMnemonic()
|
|
17
19
|
|
|
18
20
|
|
|
@@ -25,6 +27,7 @@ export const testUserKeyPair = Keypair.fromSecretKey(base58.decode(pKey));
|
|
|
25
27
|
const x = testUserKeyPair instanceof Keypair;
|
|
26
28
|
const evePrivateKey = "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
|
|
27
29
|
const evmPrivateKey2 = "0x0123456789012345678901234567890123456789012345678901234567890123"
|
|
30
|
+
const ogPrivKey = "d2d3f7117aa9a4c6e5d4affedd8a5ea624ffd82b2a1de81509e5913709b1ea72"
|
|
28
31
|
|
|
29
32
|
// const vm = new SVMVM(seed)
|
|
30
33
|
|
|
@@ -37,7 +40,7 @@ const evmPrivateKey2 = "0x012345678901234567890123456789012345678901234567890123
|
|
|
37
40
|
const chainConfig: ChainWalletConfig = {
|
|
38
41
|
chainId: 123456789,
|
|
39
42
|
name: "Solana",
|
|
40
|
-
rpcUrl: "https://solana-mainnet.g.alchemy.com/v2/
|
|
43
|
+
rpcUrl: "https://solana-mainnet.g.alchemy.com/v2/lhoyb3hc9ccT9NA_y2cfA",
|
|
41
44
|
explorerUrl: "https://explorer.solana.com",
|
|
42
45
|
nativeToken: { name: "Solana", symbol: "SOL", decimals: 9 },
|
|
43
46
|
confirmationNo: 1,
|
|
@@ -47,17 +50,27 @@ const chainConfig: ChainWalletConfig = {
|
|
|
47
50
|
const evmChainConfig: ChainWalletConfig = {
|
|
48
51
|
chainId: 8453,
|
|
49
52
|
name: "Ethereum",
|
|
50
|
-
rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/
|
|
53
|
+
rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/lhoyb3hc9ccT9NA_y2cfA",
|
|
51
54
|
explorerUrl: "https://explorer.ethereum.com",
|
|
52
55
|
nativeToken: { name: "Ethereum", symbol: "ETH", decimals: 18 },
|
|
53
56
|
confirmationNo: 1,
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
const OgChainConfig: ChainWalletConfig = {
|
|
60
|
+
chainId: 16661,
|
|
61
|
+
name: "",
|
|
62
|
+
rpcUrl: "https://evmrpc.0g.ai",
|
|
63
|
+
explorerUrl: "",
|
|
64
|
+
nativeToken: { name: "Ethereum", symbol: "ETH", decimals: 18 },
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
|
|
57
69
|
// const wallet = new SVMChainWallet(chainConfig, testUserKeyPair, 0)
|
|
58
|
-
const wallet = new EVMChainWallet(
|
|
70
|
+
const wallet = new EVMChainWallet(OgChainConfig, ogPrivKey, 0)
|
|
71
|
+
wallet.getNativeBalance().then(console.log)
|
|
59
72
|
// console.log('wallet: ', wallet);
|
|
60
|
-
|
|
73
|
+
// getTokenInfo(new PublicKey("9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump"), wallet.connection!).then(e => console.log('token info: ', e))
|
|
61
74
|
// wallet.discoverToken().then(e => console.log('discovered tokens: ', e))
|
|
62
75
|
// wallet.getNativeBalance().then(e => console.log('native balance: ', e))
|
|
63
76
|
console.log('address: ', wallet.address);
|
|
@@ -81,6 +94,10 @@ console.log('address: ', wallet.address);
|
|
|
81
94
|
const RPC_URL = chainConfig.rpcUrl;
|
|
82
95
|
const connection = new Connection(RPC_URL);
|
|
83
96
|
|
|
97
|
+
// const evmConnection = new JsonRpcProvider(evmChainConfig.rpcUrl, {
|
|
98
|
+
// chainId: evmChainConfig.chainId
|
|
99
|
+
// });
|
|
100
|
+
|
|
84
101
|
/**
|
|
85
102
|
* Fetches and logs the token metadata for a given mint address.
|
|
86
103
|
* @param mintAddress - The mint address of the token.
|
|
@@ -99,17 +116,30 @@ const connection = new Connection(RPC_URL);
|
|
|
99
116
|
// }).catch((error: any) => {
|
|
100
117
|
// console.error("Error fetching transaction history:", error);
|
|
101
118
|
// });
|
|
102
|
-
const client = createPublicClient({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
getEVMTransactionHistory(client as PublicClient, "0x9C82CE0e125F61AdE50BC0c19638F6Ba93d71D5e", {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}).then((history: any) => {
|
|
111
|
-
|
|
112
|
-
}).catch((error: any) => {
|
|
113
|
-
|
|
114
|
-
});
|
|
119
|
+
// const client = createPublicClient({
|
|
120
|
+
// chain: base,
|
|
121
|
+
// transport: http(base.rpcUrls.default.http[0]),
|
|
122
|
+
// })
|
|
123
|
+
|
|
124
|
+
// getEVMTransactionHistory(client as PublicClient, "0x9C82CE0e125F61AdE50BC0c19638F6Ba93d71D5e", {
|
|
125
|
+
// startBlock: BigInt(37427020)
|
|
126
|
+
// // before: "0xabc..."
|
|
127
|
+
// }).then((history: any) => {
|
|
128
|
+
// console.log("EVM Transaction History:", history);
|
|
129
|
+
// }).catch((error: any) => {
|
|
130
|
+
// console.error("Error fetching EVM transaction history:", error);
|
|
131
|
+
// });
|
|
132
|
+
|
|
133
|
+
// discoverNFTs("0x498581ff718922c3f8e6a244956af099b2652b2b", evmChainConfig).then(nfts => {
|
|
134
|
+
// console.log("Discovered NFTs:", nfts);
|
|
135
|
+
// }).catch(error => {
|
|
136
|
+
// console.error("Error discovering NFTs:", error);
|
|
137
|
+
// });
|
|
138
|
+
|
|
139
|
+
// fetchWalletNfts(new PublicKey("LebronkTYWjc5J1gtqntdMcbhBXgwRgYcCxMA8JMA17"), connection).then(nfts => {
|
|
140
|
+
// console.log("Discovered NFTs:", nfts);
|
|
141
|
+
// }).catch(error => {
|
|
142
|
+
// console.error("Error discovering NFTs:", error);
|
|
143
|
+
// });
|
|
144
|
+
|
|
115
145
|
|