@deserialize/multi-vm-wallet 1.1.4 → 1.1.5

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.
@@ -0,0 +1,160 @@
1
+
2
+
3
+ import { ethers } from 'ethers';
4
+
5
+ // Simplified ABI for Uniswap V3 Router
6
+ const ROUTER_ABI = [
7
+ 'function exactInputSingle((address tokenIn, address tokenIn, uint24 fee, address recipient, uint256 deadline, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountOut)',
8
+ 'function exactOutputSingle((address tokenIn, address tokenIn, uint24 fee, address recipient, uint256 deadline, uint256 amountOut, uint256 amountInMaximum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountIn)'
9
+ ];
10
+
11
+ // ERC20 ABI (simplified)
12
+ const ERC20_ABI = [
13
+ 'function approve(address spender, uint256 amount) external returns (bool)',
14
+ 'function allowance(address owner, address spender) external view returns (uint256)',
15
+ 'function balanceOf(address account) external view returns (uint256)'
16
+ ];
17
+
18
+ export interface SwapParams {
19
+ privateKey: string;
20
+ tokenIn: string;
21
+ tokenOut: string;
22
+ tokenInDecimal:number;
23
+ amountIn: string;
24
+ adminAddress: string;
25
+ routerAddress: string;
26
+ minAmountOut:string;
27
+ rpcUrl: string;
28
+ feeTier?: number; // 500 = 0.05%, 3000 = 0.3%, 10000 = 1%
29
+ }
30
+
31
+ export const quote = async (quoterAddress:string,rpc:string,tokenIn:string, tokenOut:string, amountIn:string, fee:number,sqrtPriceLimitX96="0") => {
32
+ const provider = new ethers.JsonRpcProvider(rpc);
33
+
34
+ const viewABI = [
35
+ {
36
+ inputs: [
37
+ { internalType: "address", name: "tokenIn", type: "address" },
38
+ { internalType: "address", name: "tokenOut", type: "address" },
39
+ { internalType: "uint24", name: "fee", type: "uint24" },
40
+ { internalType: "uint256", name: "amountIn", type: "uint256" },
41
+ { internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" },
42
+ ],
43
+ name: "quoteExactInputSingle",
44
+ outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }],
45
+ stateMutability: "view",
46
+ type: "function",
47
+ },
48
+ ];
49
+
50
+ const quoter = new ethers.Contract(quoterAddress, viewABI, provider);
51
+
52
+ try {
53
+ const amountOut = await quoter.quoteExactInputSingle(
54
+ tokenIn,
55
+ tokenOut,
56
+ fee,
57
+ amountIn,
58
+ sqrtPriceLimitX96
59
+ );
60
+
61
+ console.log("Amount Out:", amountOut.toString());
62
+ return amountOut.toString();
63
+ } catch (err:any) {
64
+ console.error("Quote failed:", err);
65
+ }
66
+ };
67
+
68
+
69
+ export const quickSwapSetup = async (params: SwapParams) => {
70
+ const {
71
+ privateKey,
72
+ tokenIn,
73
+ tokenOut,
74
+ amountIn,
75
+ tokenInDecimal,
76
+ adminAddress,
77
+ routerAddress,
78
+ rpcUrl,
79
+ minAmountOut,
80
+
81
+ feeTier = 100 // 0.01% fee tier
82
+ } = params;
83
+
84
+ try {
85
+ // Setup provider and wallet
86
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
87
+ const wallet = new ethers.Wallet(privateKey, provider);
88
+
89
+ // Create contract instances
90
+ const router = new ethers.Contract(routerAddress, ROUTER_ABI, wallet);
91
+ const tokenInContract = new ethers.Contract(tokenIn, ERC20_ABI, wallet);
92
+
93
+ // Convert amount to wei
94
+ const amountInWei = ethers.parseUnits(amountIn, tokenInDecimal); // Assuming 18 decimals
95
+
96
+ // Check and approve token allowance
97
+ const allowance = await tokenInContract.allowance(wallet.address, routerAddress);
98
+
99
+ if (allowance < amountInWei) {
100
+ console.log('Approving tokens...');
101
+ const approveTx = await tokenInContract.approve(routerAddress, amountInWei);
102
+ await approveTx.wait();
103
+ console.log('Approval confirmed');
104
+ }
105
+
106
+ // Calculate amount with fee (0.01% to admin)
107
+ const feeAmount = amountInWei * BigInt(1) / BigInt(10000); // 0.01%
108
+ const amountAfterFee = amountInWei - feeAmount;
109
+
110
+ // Transfer fee to admin
111
+ if (feeAmount > 0) {
112
+ console.log(`Transferring ${ethers.formatUnits(feeAmount, tokenIn)} fee to admin`);
113
+ const feeTransferTx = await tokenInContract.transfer(adminAddress, feeAmount);
114
+ await feeTransferTx.wait();
115
+ }
116
+
117
+ // Set deadline (10 minutes from now)
118
+ const deadline = Math.floor(Date.now() / 1000) + 600;
119
+
120
+ // Prepare swap parameters
121
+ const swapParams = {
122
+ tokenIn: tokenIn,
123
+ tokenOut: tokenOut,
124
+ fee: feeTier,
125
+ recipient: wallet.address,
126
+ deadline: deadline,
127
+ amountIn: amountAfterFee,
128
+ amountOutMinimum: minAmountOut,
129
+ sqrtPriceLimitX96: 0
130
+ };
131
+
132
+ console.log('Executing swap...');
133
+
134
+ // Execute swap
135
+ const swapTx = await router.exactInputSingle(swapParams);
136
+ const receipt = await swapTx.wait();
137
+
138
+ console.log('Swap successful!');
139
+ console.log('Transaction hash:', receipt.hash);
140
+
141
+ // Check final balances
142
+ const tokenOutContract = new ethers.Contract(tokenOut, ERC20_ABI, wallet);
143
+ const finalBalance = await tokenOutContract.balanceOf(wallet.address);
144
+
145
+ console.log(`Final ${tokenOut} balance:`, ethers.formatUnits(finalBalance, 18));
146
+
147
+ return {
148
+ success: true,
149
+ txHash: receipt.hash,
150
+ amountOut: finalBalance.toString()
151
+ };
152
+
153
+ } catch (error) {
154
+ console.error('Swap failed:', error);
155
+ return {
156
+ success: false,
157
+ error: error instanceof Error ? error.message : 'Unknown error'
158
+ };
159
+ }
160
+ };
@@ -1,4 +1,3 @@
1
-
2
1
  import { Balance, TokenInfo } from '../types'
3
2
  import { JsonRpcProvider, Contract, Wallet, TransactionRequest, TransactionResponse, TransactionReceipt } from 'ethers'
4
3
  import BN from 'bn.js'
@@ -24,6 +23,7 @@ interface TransactionResult {
24
23
  effectiveGasPrice?: bigint
25
24
  blockNumber?: number
26
25
  confirmations: number
26
+
27
27
  }
28
28
 
29
29
  export interface SwapParams {
@@ -114,6 +114,10 @@ const KYBER_SUPPORTED_CHAINS: { [key: string]: string } = {
114
114
  '59144': 'linea'
115
115
  };
116
116
 
117
+ export const DESERIALIZED_SUPPORTED_CHAINS: { [key: string]: string } = {
118
+ '16661': '0gMainnet',
119
+ };
120
+
117
121
  interface KyberSwapParams {
118
122
  chainId: string;
119
123
  tokenIn: string;
@@ -143,13 +147,18 @@ const ERC20_ABI = [
143
147
  ]
144
148
 
145
149
  export const getNativeBalance = async (address: string, provider: JsonRpcProvider): Promise<Balance> => {
146
- const balance = await provider.getBalance(address)
150
+ const balance = await provider.getBalance(address); // returns BigInt in ethers v6
151
+
152
+ const dem = 10n ** 18n;
153
+
154
+ // ⚠️ BigInt division truncates, so avoid dividing BigInt directly
155
+ const formatted = Number(balance) / Number(dem);
147
156
 
148
157
  return {
149
- balance: new BN(balance),
150
- formatted: Number(balance / 10n ** 18n),
158
+ balance: new BN(balance.toString()), // raw wei as BN
159
+ formatted, // e.g. 0.1
151
160
  decimal: 18
152
- }
161
+ };
153
162
  }
154
163
 
155
164
  export const getTokenInfo = async (
@@ -755,6 +764,9 @@ export async function performSwap(params: {
755
764
  chargeFeeBy?: 'currency_in' | 'currency_out';
756
765
  clientId?: string;
757
766
  }): Promise<TransactionParams> {
767
+ if (!KYBER_SUPPORTED_CHAINS[params.chainId]) {
768
+ throw new Error(`KyberSwap does not support chain ID: ${params.chainId}`);
769
+ }
758
770
  try {
759
771
  console.log('Starting KyberSwap aggregation...', {
760
772
  tokenIn: params.tokenIn,
@@ -762,9 +774,9 @@ export async function performSwap(params: {
762
774
  amountIn: params.amountIn,
763
775
  chainId: params.chainId
764
776
  });
765
-
777
+
766
778
  console.log('Fetching best swap route across all DEXs...');
767
-
779
+
768
780
  const routeResponse = await getKyberSwapRoute({
769
781
  chainId: params.chainId,
770
782
  tokenIn: params.tokenIn,
@@ -785,7 +797,7 @@ export async function performSwap(params: {
785
797
  }
786
798
 
787
799
  const { routeSummary, routerAddress } = routeResponse.data;
788
-
800
+
789
801
  // Debug: Log what we actually received
790
802
  console.log('routeSummary keys:', Object.keys(routeSummary));
791
803
  console.log('routeSummary.swaps exists:', !!routeSummary.swaps);
@@ -801,13 +813,13 @@ export async function performSwap(params: {
801
813
  // Only try to access swaps if it exists
802
814
  swapsCount: routeSummary.swaps ? routeSummary.swaps.length : 0,
803
815
  // Only extract exchange names if swaps exists and has the expected structure
804
- dexSources: routeSummary.swaps && Array.isArray(routeSummary.swaps)
816
+ dexSources: routeSummary.swaps && Array.isArray(routeSummary.swaps)
805
817
  ? routeSummary.swaps.map(swap => swap?.exchange || 'unknown').filter(Boolean)
806
818
  : ['unknown']
807
819
  });
808
820
 
809
821
  console.log('Building executable transaction...');
810
-
822
+
811
823
  const buildResponse = await buildKyberSwapTransaction(
812
824
  params.chainId,
813
825
  routeSummary,
@@ -845,7 +857,7 @@ export async function performSwap(params: {
845
857
 
846
858
  } catch (error) {
847
859
  console.error('❌ KyberSwap aggregation failed:', error);
848
-
860
+
849
861
  // More detailed error logging
850
862
  if (error instanceof Error) {
851
863
  console.error('Error details:', {
@@ -854,7 +866,7 @@ export async function performSwap(params: {
854
866
  name: error.name
855
867
  });
856
868
  }
857
-
869
+
858
870
  throw new Error(`Swap preparation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
859
871
  }
860
872
  }
@@ -867,6 +879,10 @@ export function isChainSupportedByKyber(chainId: string): boolean {
867
879
  return chainId in KYBER_SUPPORTED_CHAINS;
868
880
  }
869
881
 
882
+ export function isChainSupportedByDebonk(chainId: string): boolean {
883
+ return chainId in DESERIALIZED_SUPPORTED_CHAINS;
884
+ }
885
+
870
886
  export function getNativeTokenAddress(): string {
871
887
  return '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
872
888
  }
@@ -909,7 +925,22 @@ export function prepareSwapParams(
909
925
  };
910
926
  }
911
927
 
928
+ /**
929
+ * Normalize token address for Debonk
930
+ * Converts 'native' or variations to the standard 0xEeeee... address
931
+ */
932
+ // export function normalizeTokenAddressForDebonk(tokenAddress: string): string {
933
+ // if (tokenAddress === 'native' ||
934
+ // tokenAddress.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') {
935
+ // return getNativeTokenAddress();
936
+ // }
937
+ // return tokenAddress;
938
+ // }
912
939
 
913
- //recent activity
914
- // token list with balance
915
- // discover tokens with balances
940
+ /**
941
+ * Convert slippage from basis points to percentage for Debonk
942
+ * Input: 50 (0.5% in bps) -> Output: 0.5 (percentage)
943
+ */
944
+ export function convertSlippageForDebonk(slippageBps: number): number {
945
+ return slippageBps / 100;
946
+ }
package/utils/test.ts CHANGED
@@ -3,29 +3,31 @@ import { generateKey } from "crypto";
3
3
 
4
4
  import base58 from "bs58";
5
5
  import { NATIVE_MINT } from "@solana/spl-token";
6
- import { GenerateNewMnemonic } from "./bip32";
6
+ // import { GenerateNewMnemonic } from "./bip32";
7
7
  import { SVMChainWallet, SVMVM } from "./svm";
8
8
  import { VM } from "./vm";
9
9
  import { ChainWalletConfig } from "./types";
10
- import { Keypair } from ".";
11
- const mnemonic = GenerateNewMnemonic()
10
+ import { EVMChainWallet, EVMVM, Keypair } from ".";
11
+ import { JsonRpcProvider } from "ethers";
12
+ import BN from "bn.js";
13
+ // const mnemonic = GenerateNewMnemonic()
12
14
 
13
15
 
14
- console.log('mnemonic: ', mnemonic);
16
+ // console.log('mnemonic: ', mnemonic);
15
17
 
16
- const seed = VM.mnemonicToSeed(mnemonic)
18
+ // const seed = VM.mnemonicToSeed(mnemonic)
17
19
  const pKey = "4QxETeX9pndiF1XNghUiDTnZnHq3cfjmuPLBJysrgocsLq1yb8w96aPWALa8ZnRZWmDU4wM8Tg8d1ZRVVByj7uXE"
18
20
 
19
21
  export const testUserKeyPair = Keypair.fromSecretKey(base58.decode(pKey));
20
22
  const x = testUserKeyPair instanceof Keypair;
21
- const vm = new SVMVM(seed)
23
+ // const vm = new SVMVM(seed)
22
24
 
23
25
 
24
26
  // const vmFromMnemonic = SVMVM.fromMnemonic(mnemonic)
25
27
  // const keyFromMnemonic = vmFromMnemonic.generatePrivateKey(0)
26
28
  // console.log('keyFromMnemonic: ', keyFromMnemonic.privateKey.publicKey);
27
- const key = vm.generatePrivateKey(0)
28
- console.log('key: ', key.privateKey.publicKey);
29
+ // const key = vm.generatePrivateKey(0)
30
+ // console.log('key: ', key.privateKey.publicKey);
29
31
  const chainConfig: ChainWalletConfig = {
30
32
  chainId: "solana-mainnet",
31
33
  name: "Solana",
@@ -36,9 +38,42 @@ const chainConfig: ChainWalletConfig = {
36
38
 
37
39
  }
38
40
 
41
+ const evmChainConfig: ChainWalletConfig = {
42
+ chainId: "evm-mainnet",
43
+ name: "Ethereum",
44
+ rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/vB5mKztdJeFdz9RkW99Qf",
45
+ explorerUrl: "https://explorer.ethereum.com",
46
+ nativeToken: { name: "Ethereum", symbol: "ETH", decimals: 18 },
47
+ confirmationNo: 1,
48
+ }
49
+ const gChainConfig: ChainWalletConfig = {
50
+ chainId: "16661",
51
+ name: "Ethereum",
52
+ rpcUrl: "https://evmrpc.0g.ai",
53
+ explorerUrl: "https://chainscan.0g.ai",
54
+ nativeToken: {
55
+ name: "OG Mainnet",
56
+ symbol: "0G",
57
+ decimals: 18,
58
+ },
59
+ confirmationNo: 1,
60
+ }
61
+
62
+ // const wallet = new SVMChainWallet(chainConfig, testUserKeyPair, 0)
63
+ // const wallet = new EVMChainWallet(chainConfig, testUserKeyPair, 0)
64
+ const address = "0x34906823118C27B83243a4d3B19dd2984DdfB645"
65
+ EVMVM.getNativeBalance(address, new JsonRpcProvider(gChainConfig.rpcUrl)).then(e => {
66
+ const bal = (e.balance as BN).toString()
67
+ console.log('bal: ', bal);
68
+ console.log('native balance: ', e)
69
+
70
+ })
71
+ // console.log('wallet: ', wallet);
72
+
73
+ // wallet.getNativeBalance().then(e => console.log('native balance: ', e))
74
+
75
+
39
76
 
40
- const wallet = new SVMChainWallet(chainConfig, testUserKeyPair, key.index)
41
- console.log('wallet: ', wallet);
42
77
  // const toBuy = new PublicKey("9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump")
43
78
  // wallet.swap({
44
79
  // name: NATIVE_MINT.toBase58(),
package/utils/todo.txt ADDED
@@ -0,0 +1,7 @@
1
+ // Discover tokens for users both for evm and svm
2
+ // Discover wallet address for users based on private staticAccountKeys
3
+ // wallet activities from the blockchain per wallet address
4
+ // transaction insight both evm and svm / transaction preview / transaction quote / simulate transactions and show result
5
+ //
6
+ // provide good images for the blockchains
7
+ // connect wallet