11import { FarcasterUser } from "@mod-protocol/core" ;
2+ import { Protocol } from "@uniswap/router-sdk" ;
3+ import { Percent , Token , TradeType } from "@uniswap/sdk-core" ;
4+ import {
5+ AlphaRouter ,
6+ AlphaRouterConfig ,
7+ CurrencyAmount ,
8+ SwapOptions ,
9+ SwapType ,
10+ nativeOnChain ,
11+ } from "@uniswap/smart-order-router" ;
12+ import { ethers } from "ethers" ;
13+ import JSBI from "jsbi" ;
214import { NextRequest } from "next/server" ;
315import { publicActionReverseMirage } from "reverse-mirage" ;
416import { createPublicClient , http } from "viem2" ;
@@ -10,9 +22,21 @@ export function numberWithCommas(x: string | number) {
1022 return parts . join ( "." ) ;
1123}
1224
13- const { ERC_20_AIRSTACK_API_KEY } = process . env ;
14- const AIRSTACK_API_URL = "https://api.airstack.xyz/gql" ;
15- const airstackQuery = `
25+ export async function getFollowingHolderInfo ( {
26+ fid,
27+ tokenAddress,
28+ blockchain,
29+ } : {
30+ fid : string ;
31+ tokenAddress : string ;
32+ blockchain : string ;
33+ } ) : Promise < {
34+ holders : { user : FarcasterUser ; amount : number } [ ] ;
35+ holdersCount : number ;
36+ } > {
37+ const { ERC_20_AIRSTACK_API_KEY } = process . env ;
38+ const AIRSTACK_API_URL = "https://api.airstack.xyz/gql" ;
39+ const airstackQuery = `
1640query MyQuery($identity: Identity!, $token_address: Address!, $blockchain: TokenBlockchain, $cursor: String) {
1741 SocialFollowings(
1842 input: {
@@ -58,18 +82,6 @@ query MyQuery($identity: Identity!, $token_address: Address!, $blockchain: Token
5882}
5983` ;
6084
61- export async function getFollowingHolderInfo ( {
62- fid,
63- tokenAddress,
64- blockchain,
65- } : {
66- fid : string ;
67- tokenAddress : string ;
68- blockchain : string ;
69- } ) : Promise < {
70- holders : { user : FarcasterUser ; amount : number } [ ] ;
71- holdersCount : number ;
72- } > {
7385 const acc : any [ ] = [ ] ;
7486
7587 let hasNextPage = true ;
@@ -314,6 +326,108 @@ export async function getEthUsdPrice(): Promise<number> {
314326 return ethPriceUsd ;
315327}
316328
329+ export async function getSwapTransaction ( {
330+ outTokenAddress,
331+ blockchain,
332+ ethInputAmountFormatted,
333+ recipientAddress,
334+ feeRecipientAddress,
335+ feePercentageInt,
336+ } : {
337+ outTokenAddress : string ;
338+ blockchain : string ;
339+ ethInputAmountFormatted : string ;
340+ recipientAddress : string ;
341+ feePercentageInt ?: number ;
342+ feeRecipientAddress ?: string ;
343+ } ) {
344+ const tokenOut = await getUniswapToken ( {
345+ tokenAddress : outTokenAddress ,
346+ blockchain,
347+ } ) ;
348+ const chain = chainByName [ blockchain ] ;
349+ const provider = new ethers . providers . JsonRpcProvider (
350+ chain . rpcUrls . default . http [ 0 ]
351+ ) ;
352+
353+ const router = new AlphaRouter ( {
354+ chainId : chain . id ,
355+ provider,
356+ } ) ;
357+
358+ const tokenIn = nativeOnChain ( chain . id ) ;
359+ const amountIn = CurrencyAmount . fromRawAmount (
360+ tokenIn ,
361+ JSBI . BigInt (
362+ ethers . utils . parseUnits ( ethInputAmountFormatted , tokenIn . decimals )
363+ )
364+ ) ;
365+
366+ let swapOptions : SwapOptions = {
367+ type : SwapType . UNIVERSAL_ROUTER ,
368+ recipient : recipientAddress ,
369+ slippageTolerance : new Percent ( 5 , 100 ) ,
370+ deadlineOrPreviousBlockhash : parseDeadline ( "360" ) ,
371+ fee :
372+ feeRecipientAddress && feePercentageInt
373+ ? {
374+ fee : new Percent ( feePercentageInt , 100 ) ,
375+ recipient : feeRecipientAddress ,
376+ }
377+ : undefined ,
378+ } ;
379+
380+ const partialRoutingConfig : Partial < AlphaRouterConfig > = {
381+ protocols : [ Protocol . V2 , Protocol . V3 ] ,
382+ } ;
383+
384+ const quote = await router . route (
385+ amountIn ,
386+ tokenOut ,
387+ TradeType . EXACT_INPUT ,
388+ swapOptions ,
389+ partialRoutingConfig
390+ ) ;
391+
392+ if ( ! quote ) return ;
393+ return quote ;
394+ }
395+
396+ async function getUniswapToken ( {
397+ tokenAddress,
398+ blockchain,
399+ } : {
400+ tokenAddress : string ;
401+ blockchain : string ;
402+ } ) : Promise < Token > {
403+ const chain = chainByName [ blockchain ] ;
404+ const client = createPublicClient ( {
405+ transport : http ( ) ,
406+ chain,
407+ } ) . extend ( publicActionReverseMirage ) ;
408+
409+ const token = await client . getERC20 ( {
410+ erc20 : {
411+ address : tokenAddress as `0x${string } `,
412+ chainID : chain . id ,
413+ } ,
414+ } ) ;
415+
416+ const uniswapToken = new Token (
417+ chain . id ,
418+ tokenAddress ,
419+ token . decimals ,
420+ token . symbol ,
421+ token . name
422+ ) ;
423+
424+ return uniswapToken ;
425+ }
426+
427+ function parseDeadline ( deadline : string ) : number {
428+ return Math . floor ( Date . now ( ) / 1000 ) + parseInt ( deadline ) ;
429+ }
430+
317431export function parseInfoRequestParams ( request : NextRequest ) {
318432 const fid = request . nextUrl . searchParams . get ( "fid" ) ;
319433 const token = request . nextUrl . searchParams . get ( "token" ) ?. toLowerCase ( ) ;
0 commit comments