1
1
import { 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" ;
2
14
import { NextRequest } from "next/server" ;
3
15
import { publicActionReverseMirage } from "reverse-mirage" ;
4
16
import { createPublicClient , http } from "viem2" ;
@@ -10,9 +22,21 @@ export function numberWithCommas(x: string | number) {
10
22
return parts . join ( "." ) ;
11
23
}
12
24
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 = `
16
40
query MyQuery($identity: Identity!, $token_address: Address!, $blockchain: TokenBlockchain, $cursor: String) {
17
41
SocialFollowings(
18
42
input: {
@@ -58,18 +82,6 @@ query MyQuery($identity: Identity!, $token_address: Address!, $blockchain: Token
58
82
}
59
83
` ;
60
84
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
- } > {
73
85
const acc : any [ ] = [ ] ;
74
86
75
87
let hasNextPage = true ;
@@ -314,6 +326,108 @@ export async function getEthUsdPrice(): Promise<number> {
314
326
return ethPriceUsd ;
315
327
}
316
328
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
+
317
431
export function parseInfoRequestParams ( request : NextRequest ) {
318
432
const fid = request . nextUrl . searchParams . get ( "fid" ) ;
319
433
const token = request . nextUrl . searchParams . get ( "token" ) ?. toLowerCase ( ) ;
0 commit comments