@@ -27,7 +27,9 @@ const wrapperRouterAbi = [
2727// Uniswap V2
2828const uniswapV2RouterAbi = [
2929 "function factory() view returns (address)" ,
30- "function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) returns (uint256[])"
30+ "function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) returns (uint256[])" ,
31+ "function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)" ,
32+ "function swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) payable"
3133] ;
3234const uniswapV2FactoryAbi = [
3335 "function allPairsLength() view returns (uint256)" ,
@@ -43,10 +45,12 @@ const uniswapV2PairAbi = [
4345const uniswapV3PairAbi = [ "function slot0() view returns (uint160 sqrtPriceX96, int24, uint16, uint16, uint16, uint8, bool)" , "function liquidity() view returns (uint128)" ] ;
4446
4547const uniswapV3RouterAbi = [
46- // exactInputSingle params in struct form
47- //"function exactInputSingle((address,address,uint24,address,uint256,uint256,uint160)) external payable returns (uint256 amountOut)",
4848 "function exactInput((bytes path,address recipient,uint256 amountIn,uint256 amountOutMinimum)) external payable returns (uint256 amountOut)"
4949] ;
50+ const wethAbi = [
51+ "function withdraw(uint256 wad) external" ,
52+ "function balanceOf(address owner) view returns (uint256)"
53+ ] ;
5054
5155/**
5256 * helper JSON stringify that converts BigInt to string
@@ -102,14 +106,20 @@ export function js_on_accounts_changed(callback) {
102106}
103107
104108// ERC20
105- export async function js_get_token_balance ( user , token ) {
109+ export async function js_get_token_balance ( user , token , isNative ) {
106110 try {
107111 if ( ! window . ethereum ) throw new Error ( "MetaMask not installed" ) ;
108112 await window . ethereum . request ( { method : 'eth_requestAccounts' } ) ;
109113 let provider = new ethers . BrowserProvider ( window . ethereum ) ;
110114
111- const erc20 = new ethers . Contract ( token , erc20Abi , provider ) ;
112- const [ bal , decimals ] = await Promise . all ( [ erc20 . balanceOf ( user ) , 18 ] ) ;
115+ let bal , decimals ;
116+
117+ if ( isNative ) {
118+ [ bal , decimals ] = await Promise . all ( [ provider . getBalance ( user ) , 18 ] ) ;
119+ } else {
120+ const erc20 = new ethers . Contract ( token , erc20Abi , provider ) ;
121+ [ bal , decimals ] = await Promise . all ( [ erc20 . balanceOf ( user ) , erc20 . decimals ( ) ] ) ;
122+ }
113123 return {
114124 ok : true ,
115125 value : JSON . stringify ( ethers . formatUnits ( bal , decimals ) )
@@ -337,37 +347,61 @@ export async function js_get_uniswap_v2_pairs(routerAddr) {
337347 }
338348}
339349
340- export async function js_uniswap_v2_swap_tokens ( tokenIn , tokenOut , amountIn , amountOutMin , routerAddress ) {
350+ export async function js_uniswap_v2_swap_tokens ( tokenIn , tokenOut , amountIn , amountOutMin , routerAddress , isNativeIn , isNativeOut ) {
341351 try {
342352 if ( ! window . ethereum ) throw new Error ( "MetaMask not installed" ) ;
343353 await window . ethereum . request ( { method : 'eth_requestAccounts' } ) ;
344354 let provider = new ethers . BrowserProvider ( window . ethereum ) ;
345355 let signer = await provider . getSigner ( ) ;
346356
347-
348357 const router = new ethers . Contract ( routerAddress , uniswapV2RouterAbi , signer ) ;
349358
350359 const tokenInContract = new ethers . Contract ( tokenIn , erc20Abi , signer ) ;
351360 const decimals = await tokenInContract . decimals ( ) ;
352- const amount_in_u256 = amountIn ; //thers.parseUnits(amountIn,decimals);
353-
354- // Approve
355- const allowance = await tokenInContract . allowance ( signer , routerAddress ) ;
356- if ( allowance < amount_in_u256 ) {
357- const approve_tx = await tokenInContract . approve ( routerAddress , amount_in_u256 ) ;
358- await approve_tx . wait ( ) ;
359- }
361+ const amount_in_u256 = amountIn ;
360362
361363 const path = [ tokenIn , tokenOut ] ;
362364 const deadline = Math . floor ( Date . now ( ) / 1000 ) + 60 * 10 ;
363365
364- const tx = await router . swapExactTokensForTokensSupportingFeeOnTransferTokens (
365- amountIn ,
366- amountOutMin ,
367- path ,
368- await signer . getAddress ( ) ,
369- deadline ,
370- ) ;
366+ let tx ;
367+ if ( isNativeIn ) {
368+ tx = await router . swapExactETHForTokensSupportingFeeOnTransferTokens (
369+ amountOutMin ,
370+ path ,
371+ await signer . getAddress ( ) ,
372+ deadline ,
373+ {
374+ value : amountIn
375+ }
376+ ) ;
377+ } else {
378+ // Approve
379+ const allowance = await tokenInContract . allowance ( signer , routerAddress ) ;
380+ if ( allowance < amount_in_u256 ) {
381+ const approve_tx = await tokenInContract . approve ( routerAddress , amount_in_u256 ) ;
382+ await approve_tx . wait ( ) ;
383+ }
384+
385+
386+ if ( isNativeOut ) {
387+ tx = await router . swapExactTokensForETHSupportingFeeOnTransferTokens (
388+ amountIn ,
389+ amountOutMin ,
390+ path ,
391+ await signer . getAddress ( ) ,
392+ deadline ,
393+ ) ;
394+ } else {
395+ tx = await router . swapExactTokensForTokensSupportingFeeOnTransferTokens (
396+ amountIn ,
397+ amountOutMin ,
398+ path ,
399+ await signer . getAddress ( ) ,
400+ deadline ,
401+ ) ;
402+ }
403+
404+ }
371405 const receipt = await tx . wait ( ) ;
372406
373407 return {
@@ -428,7 +462,7 @@ function encodePath(tokenIn, fee, tokenOut) {
428462 ] ) ;
429463}
430464
431- export async function js_uniswap_v3_swap_tokens ( tokenIn , tokenOut , amountIn , amountOutMin , fee , routerAddress ) {
465+ export async function js_uniswap_v3_swap_tokens ( tokenIn , tokenOut , amountIn , amountOutMin , fee , routerAddress , isNativeIn , isNativeOut ) {
432466 try {
433467 if ( ! window . ethereum ) throw new Error ( "MetaMask not installed" ) ;
434468 await window . ethereum . request ( { method : 'eth_requestAccounts' } ) ;
@@ -450,17 +484,23 @@ export async function js_uniswap_v3_swap_tokens(tokenIn, tokenOut, amountIn, amo
450484 }
451485
452486 const path = encodePath ( tokenIn , fee , tokenOut ) ;
453- console . log ( "Path len " , path . length ) ;
454487 const recipient = await signer . getAddress ( ) ;
455488 const params = {
456489 path :path ,
457490 recipient :recipient ,
458491 amountIn :amount_in_u256 ,
459492 amountOutMinimum : amountOutMin
460493 } ;
461- const tx = await router . exactInput ( params , { value : 0n } ) ;
494+ const tx = await router . exactInput ( params , isNativeIn ? { value : amountIn } : { } ) ;
462495 const receipt = await tx . wait ( ) ;
463-
496+ if ( isNativeOut ) {
497+ const wethContract = new ethers . Contract ( tokenOut , wethAbi , signer ) ;
498+ const balance = await wethContract . balanceOf ( recipient ) ;
499+ if ( balance > 0n ) {
500+ const unwrapTx = await wethContract . withdraw ( balance ) ;
501+ await unwrapTx . wait ( ) ;
502+ }
503+ }
464504 return {
465505 ok : true ,
466506 value : JSON . stringify ( `${ receipt . hash } ` )
0 commit comments