@@ -15,7 +15,9 @@ import { eq, inArray } from "drizzle-orm";
1515import { Hono } from "hono" ;
1616import * as v from "valibot" ;
1717import { bytesToBigInt , hexToBigInt } from "viem" ;
18+ import { anvil } from "viem/chains" ;
1819
20+ import chain from "@exactly/common/generated/chain" ;
1921import {
2022 exaAccountFactoryAbi ,
2123 exaPreviewerAbi ,
@@ -33,6 +35,7 @@ import keeper from "../utils/keeper";
3335import { sendPushNotification } from "../utils/onesignal" ;
3436import { autoCredit } from "../utils/panda" ;
3537import publicClient from "../utils/publicClient" ;
38+ import redis from "../utils/redis" ;
3639import revertFingerprint from "../utils/revertFingerprint" ;
3740import { track } from "../utils/segment" ;
3841import validatorHook from "../utils/validatorHook" ;
@@ -117,25 +120,65 @@ export default new Hono().post(
117120 if ( rawContract ?. address && markets . has ( rawContract . address ) ) continue ;
118121 const asset = rawContract ?. address ?? ETH ;
119122 const underlying = asset === ETH ? WETH : asset ;
120- sendPushNotification ( {
121- userId : account ,
122- headings : t ( "Funds received" ) ,
123- contents : t (
124- marketsByAsset . has ( underlying )
125- ? "{{amount}} received and instantly started earning yield"
126- : "{{amount}} received" ,
127- {
128- amount : value
129- ? Object . fromEntries (
130- Object . entries ( f ( value ) ) . map ( ( [ language , amount ] ) => [
131- language ,
132- assetSymbol ? `${ amount } ${ assetSymbol } ` : amount ,
133- ] ) ,
134- )
135- : assetSymbol ,
136- } ,
137- ) ,
138- } ) . catch ( ( error : unknown ) => captureException ( error ) ) ;
123+ let knownToken = true ;
124+ if ( chain . id !== anvil . id ) {
125+ const key = `lifi:tokens:${ chain . id } ` ;
126+ const address = underlying . toLowerCase ( ) ;
127+ try {
128+ const [ [ , isMember ] , [ , count ] ] = v . parse (
129+ v . tuple ( [ v . tuple ( [ v . null ( ) , v . number ( ) ] ) , v . tuple ( [ v . null ( ) , v . number ( ) ] ) ] ) ,
130+ await redis . pipeline ( ) . sismember ( key , address ) . scard ( key ) . exec ( ) ,
131+ ) ;
132+ if ( ! isMember ) {
133+ if ( count > 0 ) {
134+ knownToken = false ;
135+ } else {
136+ const response = await fetch ( `https://li.quest/v1/tokens?chains=${ chain . id } ` , {
137+ signal : AbortSignal . timeout ( 5000 ) ,
138+ } ) ;
139+ if ( response . ok ) {
140+ const { tokens } = v . parse (
141+ v . object ( { tokens : v . record ( v . string ( ) , v . array ( v . object ( { address : v . string ( ) } ) ) ) } ) ,
142+ await response . json ( ) ,
143+ ) ;
144+ const tokenList = ( tokens [ String ( chain . id ) ] ?? [ ] ) . map ( ( t ) => t . address . toLowerCase ( ) ) ;
145+ if ( tokenList . length > 0 ) {
146+ await redis
147+ . multi ( )
148+ . del ( key )
149+ . sadd ( key , ...tokenList )
150+ . expire ( key , 120 )
151+ . exec ( ) ;
152+ knownToken = tokenList . includes ( address ) ;
153+ }
154+ }
155+ }
156+ }
157+ } catch ( error : unknown ) {
158+ captureException ( error , { level : "error" } ) ;
159+ }
160+ }
161+ if ( marketsByAsset . has ( underlying ) || knownToken ) {
162+ sendPushNotification ( {
163+ userId : account ,
164+ headings : t ( "Funds received" ) ,
165+ contents : t (
166+ marketsByAsset . has ( underlying )
167+ ? "{{amount}} received and instantly started earning yield"
168+ : "{{amount}} received" ,
169+ {
170+ amount : value
171+ ? Object . fromEntries (
172+ Object . entries ( f ( value ) ) . map ( ( [ language , amount ] ) => [
173+ language ,
174+ assetSymbol ? `${ amount } ${ assetSymbol } ` : amount ,
175+ ] ) ,
176+ )
177+ : assetSymbol ,
178+ } ,
179+ ) ,
180+ } ) . catch ( ( error : unknown ) => captureException ( error ) ) ;
181+ }
139182 accounts . add ( account ) ;
140183 }
141184 const { "sentry-trace" : sentryTrace , baggage } = getTraceData ( ) ;
0 commit comments