@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.
- package/README.md +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/IChainWallet.d.ts +1 -0
- package/dist/utils/evm/evm.d.ts +12 -3
- package/dist/utils/evm/evm.js +168 -7
- package/dist/utils/evm/utils.d.ts +116 -1
- package/dist/utils/evm/utils.js +191 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/svm/svm.d.ts +14 -2
- package/dist/utils/svm/svm.js +102 -7
- package/dist/utils/svm/utils.d.ts +59 -0
- package/dist/utils/svm/utils.js +145 -2
- package/dist/utils/vm.d.ts +2 -3
- package/dist/utils/vm.js +5 -6
- package/package.json +7 -4
- package/utils/IChainWallet.ts +2 -0
- package/utils/evm/evm.ts +245 -13
- package/utils/evm/utils.ts +350 -1
- package/utils/index.ts +3 -1
- package/utils/svm/svm.ts +146 -9
- package/utils/svm/utils.ts +241 -2
- package/utils/vm.ts +5 -5
- package/utils/svm/index.js +0 -17
- package/utils/svm/svm.js +0 -71
- package/utils/svm/transactionSender.js +0 -83
- package/utils/svm/utils.js +0 -161
package/dist/utils/evm/evm.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
*
|
|
3
3
|
* @param phrase this is the pass phrase for this vm
|
|
4
|
-
* this is a class that will be responsible for creating several evm wallets
|
|
4
|
+
* this is a class that will be responsible for creating several evm wallets code
|
|
5
5
|
*/
|
|
6
6
|
import { ChainWallet } from "../IChainWallet";
|
|
7
7
|
import { Balance, ChainWalletConfig, TokenInfo, TransactionResult } from "../types";
|
|
@@ -10,11 +10,12 @@ import { JsonRpcProvider, Wallet } from "ethers";
|
|
|
10
10
|
export declare const createEvmVmPrivateKey: (phrase: string) => void;
|
|
11
11
|
export declare class EVMVM extends VM<string, string, JsonRpcProvider> {
|
|
12
12
|
derivationPath: string;
|
|
13
|
-
constructor(
|
|
14
|
-
generatePrivateKey(index: number,
|
|
13
|
+
constructor(seed: string);
|
|
14
|
+
generatePrivateKey(index: number, seed?: string, mnemonic?: string, derivationPath?: string): {
|
|
15
15
|
privateKey: string;
|
|
16
16
|
index: number;
|
|
17
17
|
};
|
|
18
|
+
static fromMnemonic(seed: string): VM<string, string, JsonRpcProvider>;
|
|
18
19
|
validateAddress(address: string): boolean;
|
|
19
20
|
static getNativeBalance(address: string, connection: JsonRpcProvider): Promise<Balance>;
|
|
20
21
|
static getTokenBalance(address: string, tokenAddress: string, connection: JsonRpcProvider): Promise<Balance>;
|
|
@@ -27,4 +28,12 @@ export declare class EVMChainWallet extends ChainWallet<string, string, JsonRpcP
|
|
|
27
28
|
getTokenBalance(tokenAddress: string): Promise<Balance>;
|
|
28
29
|
transferNative(to: string, amount: number): Promise<TransactionResult>;
|
|
29
30
|
transferToken(tokenAddress: TokenInfo, to: string, amount: number): Promise<TransactionResult>;
|
|
31
|
+
swap(tokenAddress: TokenInfo, to: string, amount: number, slippage?: number): Promise<TransactionResult>;
|
|
32
|
+
performCompleteSwap(tokenIn: TokenInfo, tokenOut: TokenInfo, amount: number, slippage?: number, recipient?: string, deadline?: number): Promise<TransactionResult>;
|
|
33
|
+
getSwapQuote(tokenIn: TokenInfo, tokenOut: TokenInfo, amount: number): Promise<{
|
|
34
|
+
amountOut: string;
|
|
35
|
+
priceImpact: string;
|
|
36
|
+
gasEstimate: string;
|
|
37
|
+
route: string[];
|
|
38
|
+
}>;
|
|
30
39
|
}
|
package/dist/utils/evm/evm.js
CHANGED
|
@@ -2,27 +2,43 @@
|
|
|
2
2
|
/**
|
|
3
3
|
*
|
|
4
4
|
* @param phrase this is the pass phrase for this vm
|
|
5
|
-
* this is a class that will be responsible for creating several evm wallets
|
|
5
|
+
* this is a class that will be responsible for creating several evm wallets code
|
|
6
6
|
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
7
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
11
|
exports.EVMChainWallet = exports.EVMVM = exports.createEvmVmPrivateKey = void 0;
|
|
9
12
|
const bip32_1 = require("../bip32");
|
|
10
13
|
const IChainWallet_1 = require("../IChainWallet");
|
|
11
14
|
const vm_1 = require("../vm");
|
|
12
15
|
const ethers_1 = require("ethers");
|
|
16
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
13
17
|
const utils_1 = require("./utils");
|
|
14
18
|
const createEvmVmPrivateKey = (phrase) => { };
|
|
15
19
|
exports.createEvmVmPrivateKey = createEvmVmPrivateKey;
|
|
16
20
|
class EVMVM extends vm_1.VM {
|
|
17
|
-
constructor(
|
|
18
|
-
super(
|
|
21
|
+
constructor(seed) {
|
|
22
|
+
super(seed, "EVM");
|
|
19
23
|
this.derivationPath = "m/44'/60'/0'/0/"; // Default EVM derivation path
|
|
20
24
|
}
|
|
21
|
-
generatePrivateKey(index,
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
generatePrivateKey(index, seed, mnemonic, derivationPath = this.derivationPath) {
|
|
26
|
+
let _seed;
|
|
27
|
+
if (seed) {
|
|
28
|
+
_seed = seed;
|
|
29
|
+
}
|
|
30
|
+
else if (mnemonic) {
|
|
31
|
+
_seed = vm_1.VM.mnemonicToSeed(mnemonic);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
_seed = this.seed;
|
|
35
|
+
}
|
|
36
|
+
const privateKey = (0, bip32_1.EVMDeriveChildPrivateKey)(_seed, index, derivationPath).privateKey;
|
|
24
37
|
return { privateKey, index };
|
|
25
38
|
}
|
|
39
|
+
static fromMnemonic(seed) {
|
|
40
|
+
return new EVMVM(seed);
|
|
41
|
+
}
|
|
26
42
|
validateAddress(address) {
|
|
27
43
|
return ethers_1.ethers.isAddress(address);
|
|
28
44
|
}
|
|
@@ -45,7 +61,7 @@ class EVMChainWallet extends IChainWallet_1.ChainWallet {
|
|
|
45
61
|
this.connection = new ethers_1.JsonRpcProvider(config.rpcUrl);
|
|
46
62
|
}
|
|
47
63
|
getWallet() {
|
|
48
|
-
return new ethers_1.Wallet(this.privateKey);
|
|
64
|
+
return new ethers_1.Wallet(this.privateKey, this.connection);
|
|
49
65
|
}
|
|
50
66
|
generateAddress() {
|
|
51
67
|
return this.address;
|
|
@@ -68,5 +84,150 @@ class EVMChainWallet extends IChainWallet_1.ChainWallet {
|
|
|
68
84
|
const wallet = this.getWallet();
|
|
69
85
|
return await (0, utils_1.sendERC20Token)(wallet, tokenAddress.address, to, amount.toString(), undefined, this.config.confirmationNo || 5);
|
|
70
86
|
}
|
|
87
|
+
// Updated swap method signature to match base class so created another method to use it inside swap
|
|
88
|
+
async swap(tokenAddress, to, amount, slippage = 50) {
|
|
89
|
+
if (amount <= 0) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
hash: "",
|
|
93
|
+
error: "Amount must be greater than 0"
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const tokenOut = {
|
|
97
|
+
address: to,
|
|
98
|
+
name: '',
|
|
99
|
+
symbol: '',
|
|
100
|
+
decimals: 18
|
|
101
|
+
};
|
|
102
|
+
return await this.performCompleteSwap(tokenAddress, tokenOut, amount, slippage);
|
|
103
|
+
}
|
|
104
|
+
async performCompleteSwap(tokenIn, tokenOut, amount, slippage = 50, recipient, deadline) {
|
|
105
|
+
try {
|
|
106
|
+
const wallet = this.getWallet();
|
|
107
|
+
const chainId = (await this.connection.getNetwork()).chainId.toString();
|
|
108
|
+
console.log(` Starting swap on chain ${chainId}:`, {
|
|
109
|
+
from: tokenIn.symbol || tokenIn.address,
|
|
110
|
+
to: tokenOut.symbol || tokenOut.address,
|
|
111
|
+
amount: amount,
|
|
112
|
+
slippage: `${slippage / 100}%`
|
|
113
|
+
});
|
|
114
|
+
if (!(0, utils_1.isChainSupportedByKyber)(chainId)) {
|
|
115
|
+
throw new Error(`Chain ${chainId} is not supported by KyberSwap`);
|
|
116
|
+
}
|
|
117
|
+
const isNativeIn = tokenIn.address === 'native' ||
|
|
118
|
+
tokenIn.address.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
|
119
|
+
const isNativeOut = tokenOut.address === 'native' ||
|
|
120
|
+
tokenOut.address.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
|
121
|
+
let tokenInDecimals = 18;
|
|
122
|
+
if (!isNativeIn && tokenIn.decimals) {
|
|
123
|
+
tokenInDecimals = tokenIn.decimals;
|
|
124
|
+
}
|
|
125
|
+
else if (!isNativeIn) {
|
|
126
|
+
const tokenBalance = await this.getTokenBalance(tokenIn.address);
|
|
127
|
+
tokenInDecimals = tokenBalance.decimal;
|
|
128
|
+
}
|
|
129
|
+
const { tokenInAddress, tokenOutAddress, formattedAmountIn } = (0, utils_1.prepareSwapParams)(tokenIn.address, tokenOut.address, amount.toString(), tokenInDecimals, isNativeIn, isNativeOut);
|
|
130
|
+
console.log('Swap parameters:', {
|
|
131
|
+
tokenInAddress,
|
|
132
|
+
tokenOutAddress,
|
|
133
|
+
formattedAmountIn,
|
|
134
|
+
tokenInDecimals
|
|
135
|
+
});
|
|
136
|
+
if (isNativeIn) {
|
|
137
|
+
const nativeBalance = await this.getNativeBalance();
|
|
138
|
+
const requiredAmount = new bn_js_1.default(formattedAmountIn);
|
|
139
|
+
if (nativeBalance.balance.lt(requiredAmount)) {
|
|
140
|
+
throw new Error(`Insufficient native balance. Required: ${amount}, Available: ${nativeBalance.formatted}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const tokenBalance = await this.getTokenBalance(tokenIn.address);
|
|
145
|
+
const requiredAmount = new bn_js_1.default(formattedAmountIn);
|
|
146
|
+
if (tokenBalance.balance.lt(requiredAmount)) {
|
|
147
|
+
throw new Error(`Insufficient token balance. Required: ${amount}, Available: ${tokenBalance.formatted}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const swapTx = await (0, utils_1.performSwap)({
|
|
151
|
+
chainId,
|
|
152
|
+
tokenIn: tokenInAddress,
|
|
153
|
+
tokenOut: tokenOutAddress,
|
|
154
|
+
amountIn: formattedAmountIn,
|
|
155
|
+
sender: this.address,
|
|
156
|
+
recipient: recipient || this.address,
|
|
157
|
+
slippageTolerance: slippage,
|
|
158
|
+
deadline: deadline ? Math.floor(Date.now() / 1000) + deadline : Math.floor(Date.now() / 1000) + 1200, // 20 minutes default
|
|
159
|
+
clientId: 'EVMChainWallet'
|
|
160
|
+
});
|
|
161
|
+
console.log('Swap transaction prepared:', {
|
|
162
|
+
to: swapTx.to,
|
|
163
|
+
dataLength: swapTx.data?.length || 0,
|
|
164
|
+
gasLimit: swapTx.gasLimit?.toString(),
|
|
165
|
+
value: swapTx.value?.toString()
|
|
166
|
+
});
|
|
167
|
+
if (!isNativeIn) {
|
|
168
|
+
console.log('Checking token approval...');
|
|
169
|
+
const approvalResult = await (0, utils_1.checkAndApprove)(wallet, tokenIn.address, swapTx.to, formattedAmountIn, undefined, undefined, this.config.confirmationNo || 1);
|
|
170
|
+
if (approvalResult.approvalNeeded && approvalResult.approvalResult) {
|
|
171
|
+
if (!approvalResult.approvalResult.success) {
|
|
172
|
+
throw new Error('Token approval failed');
|
|
173
|
+
}
|
|
174
|
+
console.log('Token approval successful');
|
|
175
|
+
}
|
|
176
|
+
else if (approvalResult.approvalNeeded) {
|
|
177
|
+
throw new Error('Token approval was needed but failed');
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.log('Token approval not needed - sufficient allowance');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const result = await (0, utils_1.signSendAndConfirm)(wallet, {
|
|
184
|
+
to: swapTx.to,
|
|
185
|
+
data: swapTx.data,
|
|
186
|
+
value: swapTx.value || '0',
|
|
187
|
+
gasLimit: swapTx.gasLimit
|
|
188
|
+
}, this.config.confirmationNo || 1);
|
|
189
|
+
if (result.success) {
|
|
190
|
+
console.log(' Swap completed successfully:', {
|
|
191
|
+
hash: result.hash,
|
|
192
|
+
gasUsed: result.gasUsed?.toString(),
|
|
193
|
+
blockNumber: result.blockNumber
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
console.log(' Swap failed:', result);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error('Swap failed:', error);
|
|
203
|
+
throw new Error(`Swap failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async getSwapQuote(tokenIn, tokenOut, amount) {
|
|
207
|
+
try {
|
|
208
|
+
const chainId = (await this.connection.getNetwork()).chainId.toString();
|
|
209
|
+
if (!(0, utils_1.isChainSupportedByKyber)(chainId)) {
|
|
210
|
+
throw new Error(`Chain ${chainId} is not supported by KyberSwap`);
|
|
211
|
+
}
|
|
212
|
+
const isNativeIn = tokenIn.address === 'native' ||
|
|
213
|
+
tokenIn.address.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
|
214
|
+
const isNativeOut = tokenOut.address === 'native' ||
|
|
215
|
+
tokenOut.address.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
|
|
216
|
+
let tokenInDecimals = 18;
|
|
217
|
+
if (!isNativeIn && tokenIn.decimals) {
|
|
218
|
+
tokenInDecimals = tokenIn.decimals;
|
|
219
|
+
}
|
|
220
|
+
else if (!isNativeIn) {
|
|
221
|
+
const tokenBalance = await this.getTokenBalance(tokenIn.address);
|
|
222
|
+
tokenInDecimals = tokenBalance.decimal;
|
|
223
|
+
}
|
|
224
|
+
const { tokenInAddress, tokenOutAddress, formattedAmountIn } = (0, utils_1.prepareSwapParams)(tokenIn.address, tokenOut.address, amount.toString(), tokenInDecimals, isNativeIn, isNativeOut);
|
|
225
|
+
throw new Error("Quote functionality requires direct API integration - use the swap method for full execution");
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
console.error('Error getting swap quote:', error);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
71
232
|
}
|
|
72
233
|
exports.EVMChainWallet = EVMChainWallet;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Balance } from '../types';
|
|
2
2
|
import { JsonRpcProvider, Wallet, TransactionReceipt } from 'ethers';
|
|
3
|
-
interface TransactionParams {
|
|
3
|
+
export interface TransactionParams {
|
|
4
4
|
to: string;
|
|
5
5
|
value?: string | bigint;
|
|
6
6
|
data?: string;
|
|
@@ -19,6 +19,92 @@ interface TransactionResult {
|
|
|
19
19
|
blockNumber?: number;
|
|
20
20
|
confirmations: number;
|
|
21
21
|
}
|
|
22
|
+
export interface SwapParams {
|
|
23
|
+
tokenIn: string;
|
|
24
|
+
tokenOut: string;
|
|
25
|
+
amountIn: string;
|
|
26
|
+
slippageTolerance?: number;
|
|
27
|
+
recipient?: string;
|
|
28
|
+
deadline?: number;
|
|
29
|
+
feeAmount?: string;
|
|
30
|
+
feeReceiver?: string;
|
|
31
|
+
isInBps?: boolean;
|
|
32
|
+
chargeFeeBy?: 'currency_in' | 'currency_out';
|
|
33
|
+
}
|
|
34
|
+
export interface KyberRoute {
|
|
35
|
+
tokenIn: string;
|
|
36
|
+
amountIn: string;
|
|
37
|
+
tokenOut: string;
|
|
38
|
+
amountOut: string;
|
|
39
|
+
gas: string;
|
|
40
|
+
gasPrice: string;
|
|
41
|
+
gasUsd: number;
|
|
42
|
+
amountOutUsd: string;
|
|
43
|
+
receivedUsd: string;
|
|
44
|
+
swaps: Array<{
|
|
45
|
+
pool: string;
|
|
46
|
+
tokenIn: string;
|
|
47
|
+
tokenOut: string;
|
|
48
|
+
swapAmount: string;
|
|
49
|
+
amountOut: string;
|
|
50
|
+
limitReturnAmount: string;
|
|
51
|
+
maxPrice: string;
|
|
52
|
+
exchange: string;
|
|
53
|
+
poolLength: number;
|
|
54
|
+
poolType: string;
|
|
55
|
+
}>;
|
|
56
|
+
tokens: {
|
|
57
|
+
[address: string]: {
|
|
58
|
+
address: string;
|
|
59
|
+
symbol: string;
|
|
60
|
+
name: string;
|
|
61
|
+
decimals: number;
|
|
62
|
+
price: number;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export interface KyberSwapResponse {
|
|
67
|
+
code: number;
|
|
68
|
+
message: string;
|
|
69
|
+
data: {
|
|
70
|
+
routeSummary: KyberRoute;
|
|
71
|
+
routerAddress: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface KyberBuildResponse {
|
|
75
|
+
code: number;
|
|
76
|
+
message: string;
|
|
77
|
+
data: {
|
|
78
|
+
amountIn: string;
|
|
79
|
+
amountInUsd: string;
|
|
80
|
+
amountOut: string;
|
|
81
|
+
amountOutUsd: string;
|
|
82
|
+
gas: string;
|
|
83
|
+
gasUsd: string;
|
|
84
|
+
outputChange: {
|
|
85
|
+
amount: string;
|
|
86
|
+
percent: number;
|
|
87
|
+
level: number;
|
|
88
|
+
};
|
|
89
|
+
data: string;
|
|
90
|
+
routerAddress: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
interface KyberSwapParams {
|
|
94
|
+
chainId: string;
|
|
95
|
+
tokenIn: string;
|
|
96
|
+
tokenOut: string;
|
|
97
|
+
amountIn: string;
|
|
98
|
+
slippageTolerance?: number;
|
|
99
|
+
recipient?: string;
|
|
100
|
+
sender?: string;
|
|
101
|
+
deadline?: number;
|
|
102
|
+
feeAmount?: string;
|
|
103
|
+
feeReceiver?: string;
|
|
104
|
+
isInBps?: boolean;
|
|
105
|
+
chargeFeeBy?: 'currency_in' | 'currency_out';
|
|
106
|
+
clientId?: string;
|
|
107
|
+
}
|
|
22
108
|
export declare const getNativeBalance: (address: string, provider: JsonRpcProvider) => Promise<Balance>;
|
|
23
109
|
export declare const getTokenBalance: (tokenAddress: string, walletAddress: string, provider: JsonRpcProvider) => Promise<Balance>;
|
|
24
110
|
/**
|
|
@@ -89,4 +175,33 @@ export declare const safeApprove: (wallet: Wallet, tokenAddress: string, spender
|
|
|
89
175
|
resetResult: TransactionResult;
|
|
90
176
|
approveResult: TransactionResult;
|
|
91
177
|
}>;
|
|
178
|
+
export declare function getKyberSwapRoute(params: KyberSwapParams): Promise<KyberSwapResponse>;
|
|
179
|
+
export declare function buildKyberSwapTransaction(chainId: string, routeSummary: KyberRoute, sender: string, recipient: string, slippageTolerance?: number, deadline?: number, clientId?: string): Promise<KyberBuildResponse>;
|
|
180
|
+
export declare function performSwap(params: {
|
|
181
|
+
chainId: string;
|
|
182
|
+
tokenIn: string;
|
|
183
|
+
tokenOut: string;
|
|
184
|
+
amountIn: string;
|
|
185
|
+
sender: string;
|
|
186
|
+
recipient?: string;
|
|
187
|
+
slippageTolerance?: number;
|
|
188
|
+
deadline?: number;
|
|
189
|
+
feeAmount?: string;
|
|
190
|
+
feeReceiver?: string;
|
|
191
|
+
isInBps?: boolean;
|
|
192
|
+
chargeFeeBy?: 'currency_in' | 'currency_out';
|
|
193
|
+
clientId?: string;
|
|
194
|
+
}): Promise<TransactionParams>;
|
|
195
|
+
export declare function getKyberSupportedChains(): {
|
|
196
|
+
[key: string]: string;
|
|
197
|
+
};
|
|
198
|
+
export declare function isChainSupportedByKyber(chainId: string): boolean;
|
|
199
|
+
export declare function getNativeTokenAddress(): string;
|
|
200
|
+
export declare function formatAmountToWei(amount: string, decimals: number): string;
|
|
201
|
+
export declare function formatAmountFromWei(amountWei: string, decimals: number): string;
|
|
202
|
+
export declare function prepareSwapParams(tokenIn: string, tokenOut: string, amountIn: string, tokenInDecimals: number, isNativeIn?: boolean, isNativeOut?: boolean): {
|
|
203
|
+
tokenInAddress: string;
|
|
204
|
+
tokenOutAddress: string;
|
|
205
|
+
formattedAmountIn: string;
|
|
206
|
+
};
|
|
92
207
|
export {};
|
package/dist/utils/evm/utils.js
CHANGED
|
@@ -4,8 +4,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.safeApprove = exports.resetAllowance = exports.checkAndApprove = exports.approveTokenUnlimited = exports.approveToken = exports.isAllowanceSufficient = exports.checkAllowance = exports.estimateGas = exports.getGasPrices = exports.executeContractMethod = exports.sendERC20Token = exports.sendNativeToken = exports.signSendAndConfirm = exports.getTokenBalance = exports.getNativeBalance = void 0;
|
|
7
|
+
exports.getKyberSwapRoute = getKyberSwapRoute;
|
|
8
|
+
exports.buildKyberSwapTransaction = buildKyberSwapTransaction;
|
|
9
|
+
exports.performSwap = performSwap;
|
|
10
|
+
exports.getKyberSupportedChains = getKyberSupportedChains;
|
|
11
|
+
exports.isChainSupportedByKyber = isChainSupportedByKyber;
|
|
12
|
+
exports.getNativeTokenAddress = getNativeTokenAddress;
|
|
13
|
+
exports.formatAmountToWei = formatAmountToWei;
|
|
14
|
+
exports.formatAmountFromWei = formatAmountFromWei;
|
|
15
|
+
exports.prepareSwapParams = prepareSwapParams;
|
|
7
16
|
const ethers_1 = require("ethers");
|
|
8
17
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
18
|
+
const KYBER_BASE_URL = 'https://aggregator-api.kyberswap.com';
|
|
19
|
+
const KYBER_SUPPORTED_CHAINS = {
|
|
20
|
+
'1': 'ethereum',
|
|
21
|
+
'137': 'polygon',
|
|
22
|
+
'56': 'bsc',
|
|
23
|
+
'43114': 'avalanche',
|
|
24
|
+
'250': 'fantom',
|
|
25
|
+
'42161': 'arbitrum',
|
|
26
|
+
'10': 'optimism',
|
|
27
|
+
'8453': 'base',
|
|
28
|
+
'324': 'zksync',
|
|
29
|
+
'59144': 'linea'
|
|
30
|
+
};
|
|
9
31
|
// ERC-20 ABI
|
|
10
32
|
const ERC20_ABI = [
|
|
11
33
|
"function balanceOf(address owner) view returns (uint256)",
|
|
@@ -344,3 +366,172 @@ const safeApprove = async (wallet, tokenAddress, spender, amount, gasLimit, conf
|
|
|
344
366
|
};
|
|
345
367
|
exports.safeApprove = safeApprove;
|
|
346
368
|
//swaps
|
|
369
|
+
//kyber swap here
|
|
370
|
+
//docs -. https://docs.kyberswap.com/kyberswap-solutions/kyberswap-aggregator/developer-guides/execute-a-swap-with-the-aggregator-api
|
|
371
|
+
// the major constrain is that each function should return a transaction to sign, do not sign transaction or send transaction within util functions
|
|
372
|
+
// let the ChainWalletClass be the one to sign and send,
|
|
373
|
+
//so in you chainWallet.swap, you can have the futil swap function to get the transaction then another function to sign and send and confirm the transaction
|
|
374
|
+
async function getKyberSwapRoute(params) {
|
|
375
|
+
const chainName = KYBER_SUPPORTED_CHAINS[params.chainId];
|
|
376
|
+
if (!chainName) {
|
|
377
|
+
throw new Error(`Unsupported chain ID: ${params.chainId}`);
|
|
378
|
+
}
|
|
379
|
+
const queryParams = new URLSearchParams({
|
|
380
|
+
tokenIn: params.tokenIn,
|
|
381
|
+
tokenOut: params.tokenOut,
|
|
382
|
+
amountIn: params.amountIn,
|
|
383
|
+
});
|
|
384
|
+
if (params.feeAmount)
|
|
385
|
+
queryParams.append('feeAmount', params.feeAmount);
|
|
386
|
+
if (params.feeReceiver)
|
|
387
|
+
queryParams.append('feeReceiver', params.feeReceiver);
|
|
388
|
+
if (params.isInBps !== undefined)
|
|
389
|
+
queryParams.append('isInBps', params.isInBps.toString());
|
|
390
|
+
if (params.chargeFeeBy)
|
|
391
|
+
queryParams.append('chargeFeeBy', params.chargeFeeBy);
|
|
392
|
+
const url = `${KYBER_BASE_URL}/${chainName}/api/v1/routes?${queryParams}`;
|
|
393
|
+
const headers = {};
|
|
394
|
+
if (params.clientId) {
|
|
395
|
+
headers['x-client-id'] = params.clientId;
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
const response = await fetch(url, { headers });
|
|
399
|
+
const data = await response.json();
|
|
400
|
+
if (!response.ok) {
|
|
401
|
+
throw new Error(`KyberSwap API error: ${data.message || response.statusText}`);
|
|
402
|
+
}
|
|
403
|
+
return data;
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
console.error('Error fetching KyberSwap route:', error);
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async function buildKyberSwapTransaction(chainId, routeSummary, sender, recipient, slippageTolerance = 50, deadline, clientId) {
|
|
411
|
+
const chainName = KYBER_SUPPORTED_CHAINS[chainId];
|
|
412
|
+
if (!chainName) {
|
|
413
|
+
throw new Error(`Unsupported chain ID: ${chainId}`);
|
|
414
|
+
}
|
|
415
|
+
const url = `${KYBER_BASE_URL}/${chainName}/api/v1/route/build`;
|
|
416
|
+
const txDeadline = deadline || Math.floor(Date.now() / 1000) + 1200;
|
|
417
|
+
const body = {
|
|
418
|
+
routeSummary,
|
|
419
|
+
sender,
|
|
420
|
+
recipient,
|
|
421
|
+
slippageTolerance,
|
|
422
|
+
deadline: txDeadline,
|
|
423
|
+
source: clientId || 'MyWalletApp'
|
|
424
|
+
};
|
|
425
|
+
const headers = {
|
|
426
|
+
'Content-Type': 'application/json',
|
|
427
|
+
};
|
|
428
|
+
if (clientId) {
|
|
429
|
+
headers['x-client-id'] = clientId;
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
const response = await fetch(url, {
|
|
433
|
+
method: 'POST',
|
|
434
|
+
headers,
|
|
435
|
+
body: JSON.stringify(body)
|
|
436
|
+
});
|
|
437
|
+
const data = await response.json();
|
|
438
|
+
if (!response.ok) {
|
|
439
|
+
throw new Error(`KyberSwap build API error: ${data.message || response.statusText}`);
|
|
440
|
+
}
|
|
441
|
+
return data;
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
console.error('Error building KyberSwap transaction:', error);
|
|
445
|
+
throw error;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async function performSwap(params) {
|
|
449
|
+
try {
|
|
450
|
+
console.log('Starting KyberSwap aggregation...', {
|
|
451
|
+
tokenIn: params.tokenIn,
|
|
452
|
+
tokenOut: params.tokenOut,
|
|
453
|
+
amountIn: params.amountIn,
|
|
454
|
+
chainId: params.chainId
|
|
455
|
+
});
|
|
456
|
+
console.log('Fetching best swap route across all DEXs...');
|
|
457
|
+
const routeResponse = await getKyberSwapRoute({
|
|
458
|
+
chainId: params.chainId,
|
|
459
|
+
tokenIn: params.tokenIn,
|
|
460
|
+
tokenOut: params.tokenOut,
|
|
461
|
+
amountIn: params.amountIn,
|
|
462
|
+
feeAmount: params.feeAmount,
|
|
463
|
+
feeReceiver: params.feeReceiver,
|
|
464
|
+
isInBps: params.isInBps,
|
|
465
|
+
chargeFeeBy: params.chargeFeeBy,
|
|
466
|
+
clientId: params.clientId || 'MyWalletApp'
|
|
467
|
+
});
|
|
468
|
+
if (!routeResponse.data || !routeResponse.data.routeSummary) {
|
|
469
|
+
throw new Error('No valid route found for the swap');
|
|
470
|
+
}
|
|
471
|
+
const { routeSummary, routerAddress } = routeResponse.data;
|
|
472
|
+
console.log('✅ Best route found:', {
|
|
473
|
+
tokenIn: routeSummary.tokenIn,
|
|
474
|
+
tokenOut: routeSummary.tokenOut,
|
|
475
|
+
amountIn: routeSummary.amountIn,
|
|
476
|
+
amountOut: routeSummary.amountOut,
|
|
477
|
+
gasEstimate: routeSummary.gas,
|
|
478
|
+
routerAddress,
|
|
479
|
+
dexSources: routeSummary.swaps.map(swap => swap.exchange)
|
|
480
|
+
});
|
|
481
|
+
console.log(' Building executable transaction...');
|
|
482
|
+
const buildResponse = await buildKyberSwapTransaction(params.chainId, routeSummary, params.sender, params.recipient || params.sender, params.slippageTolerance || 50, params.deadline, params.clientId || 'MyWalletApp');
|
|
483
|
+
if (!buildResponse.data || !buildResponse.data.data) {
|
|
484
|
+
throw new Error('Failed to build transaction data');
|
|
485
|
+
}
|
|
486
|
+
const { data: encodedData, gas, routerAddress: finalRouterAddress } = buildResponse.data;
|
|
487
|
+
console.log('✅ Transaction built successfully:', {
|
|
488
|
+
to: finalRouterAddress,
|
|
489
|
+
dataLength: encodedData.length,
|
|
490
|
+
gasEstimate: gas,
|
|
491
|
+
expectedOutput: buildResponse.data.amountOut
|
|
492
|
+
});
|
|
493
|
+
return {
|
|
494
|
+
to: finalRouterAddress,
|
|
495
|
+
data: encodedData,
|
|
496
|
+
gasLimit: gas,
|
|
497
|
+
value: params.tokenIn.toLowerCase() === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
|
|
498
|
+
? params.amountIn
|
|
499
|
+
: '0'
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
console.error('❌ KyberSwap aggregation failed:', error);
|
|
504
|
+
throw new Error(`Swap preparation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function getKyberSupportedChains() {
|
|
508
|
+
return { ...KYBER_SUPPORTED_CHAINS };
|
|
509
|
+
}
|
|
510
|
+
function isChainSupportedByKyber(chainId) {
|
|
511
|
+
return chainId in KYBER_SUPPORTED_CHAINS;
|
|
512
|
+
}
|
|
513
|
+
function getNativeTokenAddress() {
|
|
514
|
+
return '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
515
|
+
}
|
|
516
|
+
function formatAmountToWei(amount, decimals) {
|
|
517
|
+
const amountBN = new bn_js_1.default(amount);
|
|
518
|
+
const multiplier = new bn_js_1.default(10).pow(new bn_js_1.default(decimals));
|
|
519
|
+
return amountBN.mul(multiplier).toString();
|
|
520
|
+
}
|
|
521
|
+
function formatAmountFromWei(amountWei, decimals) {
|
|
522
|
+
const amountBN = new bn_js_1.default(amountWei);
|
|
523
|
+
const divisor = new bn_js_1.default(10).pow(new bn_js_1.default(decimals));
|
|
524
|
+
return amountBN.div(divisor).toString();
|
|
525
|
+
}
|
|
526
|
+
function prepareSwapParams(tokenIn, tokenOut, amountIn, tokenInDecimals, isNativeIn = false, isNativeOut = false) {
|
|
527
|
+
const tokenInAddress = isNativeIn ? getNativeTokenAddress() : tokenIn;
|
|
528
|
+
const tokenOutAddress = isNativeOut ? getNativeTokenAddress() : tokenOut;
|
|
529
|
+
const formattedAmountIn = amountIn.includes('.')
|
|
530
|
+
? formatAmountToWei(amountIn, tokenInDecimals)
|
|
531
|
+
: amountIn;
|
|
532
|
+
return {
|
|
533
|
+
tokenInAddress,
|
|
534
|
+
tokenOutAddress,
|
|
535
|
+
formattedAmountIn
|
|
536
|
+
};
|
|
537
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
package/dist/utils/svm/svm.d.ts
CHANGED
|
@@ -2,17 +2,19 @@ import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
|
|
2
2
|
import { VM } from "../vm";
|
|
3
3
|
import { ChainWallet } from "../IChainWallet";
|
|
4
4
|
import { Balance, ChainWalletConfig, TokenInfo, TransactionResult } from "../types";
|
|
5
|
+
import { JupiterQuoteResponse } from "./utils";
|
|
5
6
|
export declare class SVMVM extends VM<PublicKey, Keypair, Connection> {
|
|
6
7
|
derivationPath: string;
|
|
7
|
-
constructor(
|
|
8
|
+
constructor(seed: string);
|
|
8
9
|
static validateAddress(address: PublicKey): boolean;
|
|
9
10
|
static getNativeBalance(address: PublicKey, connection: Connection): Promise<Balance>;
|
|
10
11
|
static getTokenBalance(address: PublicKey, tokenAddress: PublicKey, connection: Connection): Promise<Balance>;
|
|
11
12
|
static signAndSendTransaction: (transaction: import("@solana/web3.js").VersionedTransaction, connection: Connection, signers: Keypair[]) => Promise<string>;
|
|
12
|
-
generatePrivateKey(index: number,
|
|
13
|
+
generatePrivateKey(index: number, seed?: string, mnemonic?: string, derivationPath?: string): {
|
|
13
14
|
privateKey: Keypair;
|
|
14
15
|
index: number;
|
|
15
16
|
};
|
|
17
|
+
static fromMnemonic(seed: string): VM<PublicKey, Keypair, Connection>;
|
|
16
18
|
}
|
|
17
19
|
export declare class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Connection> {
|
|
18
20
|
constructor(config: ChainWalletConfig, privateKey: Keypair, index: number);
|
|
@@ -21,4 +23,14 @@ export declare class SVMChainWallet extends ChainWallet<PublicKey, Keypair, Conn
|
|
|
21
23
|
getTokenBalance(tokenAddress: PublicKey): Promise<Balance>;
|
|
22
24
|
transferNative(to: PublicKey, amount: number): Promise<TransactionResult>;
|
|
23
25
|
transferToken(token: TokenInfo, to: PublicKey, amount: number): Promise<TransactionResult>;
|
|
26
|
+
swap(fromToken: TokenInfo, toToken: PublicKey, amount: number, slippage?: number): Promise<TransactionResult>;
|
|
27
|
+
getSwapQuote(fromToken: TokenInfo, toToken: PublicKey, amount: number, slippage?: number): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
inputAmount?: string;
|
|
30
|
+
outputAmount?: string;
|
|
31
|
+
priceImpact?: string;
|
|
32
|
+
routePlan?: JupiterQuoteResponse['routePlan'];
|
|
33
|
+
slippageBps?: number;
|
|
34
|
+
error?: string;
|
|
35
|
+
}>;
|
|
24
36
|
}
|