github.com/diadata-org/diadata@v1.4.593/pkg/dia/scraper/liquidity-scrapers/TraderJoeScraper.go (about) 1 package liquidityscrapers 2 3 import ( 4 "math" 5 "math/big" 6 "strconv" 7 "strings" 8 "time" 9 10 "github.com/diadata-org/diadata/pkg/dia" 11 "github.com/diadata-org/diadata/pkg/dia/helpers/ethhelper" 12 traderjoe "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/traderjoe2.1" 13 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/traderjoe2.1/traderjoeILBPair" 14 models "github.com/diadata-org/diadata/pkg/model" 15 "github.com/diadata-org/diadata/pkg/utils" 16 "github.com/ethereum/go-ethereum/accounts/abi/bind" 17 "github.com/ethereum/go-ethereum/common" 18 "github.com/ethereum/go-ethereum/ethclient" 19 ) 20 21 // TraderJoeLiquidityScraper manages the scraping of liquidity data for the Trader Joe exchange. 22 type TraderJoeLiquidityScraper struct { 23 RestClient *ethclient.Client 24 WsClient *ethclient.Client 25 relDB *models.RelDB 26 datastore *models.DB 27 poolChannel chan dia.Pool 28 doneChannel chan bool 29 blockchain string 30 startBlock uint64 31 factoryContract string 32 exchangeName string 33 waitTime int 34 } 35 36 // NewTraderJoeLiquidityScraper initializes a Trader Joe liquidity scraper, creating an instance of the 37 // TraderJoeLiquidityScraper struct. It configures necessary parameters, initiates pool fetching, and returns 38 // the initialized scraper. 39 func NewTraderJoeLiquidityScraper(exchange dia.Exchange, relDB *models.RelDB, datastore *models.DB) *TraderJoeLiquidityScraper { 40 log.Info("NewTraderJoeLiquidityScraper ", exchange.Name) 41 log.Info("NewTraderJoeLiquidityScraper Address ", exchange.Contract) 42 43 var tjls *TraderJoeLiquidityScraper 44 45 switch exchange.Name { 46 case dia.TraderJoeExchangeV2_1: 47 tjls = makeTraderJoeScraper(exchange, "", "", relDB, datastore, "200", uint64(17821282)) 48 case dia.TraderJoeExchangeV2_1Arbitrum: 49 tjls = makeTraderJoeScraper(exchange, "", "", relDB, datastore, "200", uint64(77473199)) 50 case dia.TraderJoeExchangeV2_1Avalanche: 51 tjls = makeTraderJoeScraper(exchange, "", "", relDB, datastore, "200", uint64(28371397)) 52 case dia.TraderJoeExchangeV2_1BNB: 53 tjls = makeTraderJoeScraper(exchange, "", "", relDB, datastore, "200", uint64(27099340)) 54 case dia.TraderJoeExchangeV2_2Avalanche: 55 tjls = makeTraderJoeScraper(exchange, "", "", relDB, datastore, "200", uint64(46536129)) 56 } 57 58 go func() { 59 tjls.fetchPools() 60 }() 61 return tjls 62 } 63 64 // makeTraderJoeScraper initializes a Trader Joe liquidity scraper, creating an instance of the 65 // TraderJoeLiquidityScraper struct with the specified configuration and parameters. 66 func makeTraderJoeScraper(exchange dia.Exchange, restDial string, wsDial string, relDB *models.RelDB, datastore *models.DB, waitMilliSeconds string, startBlock uint64) *TraderJoeLiquidityScraper { 67 var ( 68 restClient *ethclient.Client 69 wsClient *ethclient.Client 70 err error 71 poolChannel = make(chan dia.Pool) 72 doneChannel = make(chan bool) 73 tjls *TraderJoeLiquidityScraper 74 ) 75 76 log.Infof("Init rest and ws client for %s.", exchange.BlockChain.Name) 77 restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", restDial)) 78 if err != nil { 79 log.Fatal("init rest client: ", err) 80 } 81 wsClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_WS", wsDial)) 82 if err != nil { 83 log.Fatal("init ws client: ", err) 84 } 85 86 var waitTime int 87 waitTimeString := utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_WAIT_TIME", waitMilliSeconds) 88 waitTime, err = strconv.Atoi(waitTimeString) 89 if err != nil { 90 log.Error("could not parse wait time: ", err) 91 waitTime = 500 92 } 93 94 tjls = &TraderJoeLiquidityScraper{ 95 WsClient: wsClient, 96 RestClient: restClient, 97 relDB: relDB, 98 datastore: datastore, 99 poolChannel: poolChannel, 100 doneChannel: doneChannel, 101 blockchain: exchange.BlockChain.Name, 102 startBlock: startBlock, 103 factoryContract: exchange.Contract, 104 exchangeName: exchange.Name, 105 waitTime: waitTime, 106 } 107 return tjls 108 } 109 110 // fetchPools retrieves pool creation events from the Trader Joe factory contract address and processes them. 111 func (tjls *TraderJoeLiquidityScraper) fetchPools() { 112 113 log.Info("Fetching Trader Joe LBPairCreated events...") 114 log.Info("Getting lb pairs creations from address: ", tjls.factoryContract) 115 116 // Initialize a count for the number of pairs processed. 117 pairCount := 0 118 119 // Initialize an Ethereum event filter for the Trader Joe factory contract. 120 contractFilter, err := traderjoe.NewTraderjoeFilterer(common.HexToAddress(tjls.factoryContract), tjls.WsClient) 121 if err != nil { 122 log.Error(err) 123 } 124 125 // Retrieve LBPairCreated events using the event filter. 126 lbPairCreated, err := contractFilter.FilterLBPairCreated( 127 &bind.FilterOpts{Start: tjls.startBlock}, 128 []common.Address{}, 129 []common.Address{}, 130 []*big.Int{}, 131 ) 132 if err != nil { 133 log.Error("filter pool created: ", err) 134 } 135 136 // Iterate through the LBPairCreated events. 137 for lbPairCreated.Next() { 138 pairCount++ 139 var ( 140 pool dia.Pool 141 asset0 dia.Asset 142 asset1 dia.Asset 143 ) 144 log.Info("pairs count: ", pairCount) 145 time.Sleep(time.Duration(tjls.waitTime) * time.Millisecond) 146 147 // Retrieve information about the first token of the liquidity pool. 148 asset0, err = tjls.relDB.GetAsset(lbPairCreated.Event.TokenX.Hex(), tjls.blockchain) 149 if err != nil { 150 // If asset information cannot be retrieved from the database, try fetching it from the Ethereum network. 151 asset0, err = ethhelper.ETHAddressToAsset(lbPairCreated.Event.TokenX, tjls.RestClient, tjls.blockchain) 152 if err != nil { 153 log.Warn("cannot fetch asset from address ", lbPairCreated.Event.TokenX.Hex()) 154 continue 155 } 156 } 157 158 // Retrieve information about the second token of the liquidity pool. 159 asset1, err = tjls.relDB.GetAsset(lbPairCreated.Event.TokenY.Hex(), tjls.blockchain) 160 if err != nil { 161 // If asset information cannot be retrieved from the database, try fetching it from the Ethereum network. 162 asset1, err = ethhelper.ETHAddressToAsset(lbPairCreated.Event.TokenY, tjls.RestClient, tjls.blockchain) 163 if err != nil { 164 log.Warn("cannot fetch asset from address ", lbPairCreated.Event.TokenY.Hex()) 165 continue 166 } 167 } 168 169 // Populate pool information. 170 pool.Exchange = dia.Exchange{Name: tjls.exchangeName} 171 pool.Blockchain = dia.BlockChain{Name: tjls.blockchain} 172 pool.Address = lbPairCreated.Event.LBPair.Hex() 173 174 pairFiltererContract, err := traderjoeILBPair.NewILBPairCaller(lbPairCreated.Event.LBPair, tjls.RestClient) 175 if err != nil { 176 log.Fatal(err) 177 } 178 reserves, err := pairFiltererContract.GetReserves(&bind.CallOpts{}) 179 if err != nil { 180 log.Fatal("get reserves on pool ", lbPairCreated.Event.LBPair.Hex()) 181 } 182 183 // Calculate token balances in floating-point format. 184 balance0, _ := new(big.Float).Quo(big.NewFloat(0).SetInt(reserves.ReserveX), new(big.Float).SetFloat64(math.Pow10(int(asset0.Decimals)))).Float64() 185 balance1, _ := new(big.Float).Quo(big.NewFloat(0).SetInt(reserves.ReserveY), new(big.Float).SetFloat64(math.Pow10(int(asset1.Decimals)))).Float64() 186 187 // Append asset volumes to the pool. 188 pool.Assetvolumes = append(pool.Assetvolumes, dia.AssetVolume{Asset: asset0, Volume: balance0, Index: uint8(0)}) 189 pool.Assetvolumes = append(pool.Assetvolumes, dia.AssetVolume{Asset: asset1, Volume: balance1, Index: uint8(1)}) 190 191 // Determine USD liquidity for the pool if both token balances meet the threshold. 192 if balance0 > GLOBAL_NATIVE_LIQUIDITY_THRESHOLD && balance1 > GLOBAL_NATIVE_LIQUIDITY_THRESHOLD { 193 tjls.datastore.GetPoolLiquiditiesUSD(&pool, priceCache) 194 } 195 196 // Set the timestamp for the pool. 197 pool.Time = time.Now() 198 199 // Send the processed pool information to the channel. 200 tjls.poolChannel <- pool 201 } 202 203 // Signal that pool retrieval and processing is complete. 204 tjls.doneChannel <- true 205 } 206 207 // Pool returns a channel for receiving dia.Pool instances scraped by the Trader Joe liquidity scraper. 208 func (tjls *TraderJoeLiquidityScraper) Pool() chan dia.Pool { 209 return tjls.poolChannel 210 } 211 212 // Done returns a channel for signaling the completion of Trader Joe liquidity scraping. 213 func (tjls *TraderJoeLiquidityScraper) Done() chan bool { 214 return tjls.doneChannel 215 }