github.com/diadata-org/diadata@v1.4.593/pkg/dia/service/assetservice/source/traderjoev2_1.go (about)

     1  package source
     2  
     3  import (
     4  	"math/big"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/diadata-org/diadata/pkg/dia"
     9  	"github.com/diadata-org/diadata/pkg/dia/helpers/ethhelper"
    10  	traderjoe "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/traderjoe2.1"
    11  	models "github.com/diadata-org/diadata/pkg/model"
    12  	"github.com/diadata-org/diadata/pkg/utils"
    13  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/ethereum/go-ethereum/ethclient"
    16  )
    17  
    18  // TraderJoeAssetSource manages the scraping of assets for the Trader Joe exchange.
    19  type TraderJoeAssetSource struct {
    20  	RestClient             *ethclient.Client
    21  	WsClient               *ethclient.Client
    22  	relDB                  *models.RelDB
    23  	assetChannel           chan dia.Asset
    24  	doneChannel            chan bool
    25  	exchange               dia.Exchange
    26  	startBlock             uint64
    27  	factoryContractAddress common.Address
    28  	waitTime               int
    29  }
    30  
    31  // NewTraderJoeAssetSource initializes a Trader Joe asset sourcer, creating an instance of the
    32  // NewTraderJoeAssetSource struct. It configures necessary parameters, initiates asset fetching, and returns
    33  // the initialized scraper.
    34  func NewTraderJoeAssetSource(exchange dia.Exchange, relDB *models.RelDB) *TraderJoeAssetSource {
    35  	log.Info("NewTraderJoeLiquidityScraper ", exchange.Name)
    36  	log.Info("NewTraderJoeLiquidityScraper Address ", exchange.Contract)
    37  
    38  	var tjas *TraderJoeAssetSource
    39  
    40  	switch exchange.Name {
    41  	case dia.TraderJoeExchangeV2_1:
    42  		tjas = makeTraderJoeAssetSource(exchange, "", "", relDB, "200", uint64(17821282))
    43  	case dia.TraderJoeExchangeV2_1Arbitrum:
    44  		tjas = makeTraderJoeAssetSource(exchange, "", "", relDB, "200", uint64(77473199))
    45  	case dia.TraderJoeExchangeV2_1Avalanche:
    46  		tjas = makeTraderJoeAssetSource(exchange, "", "", relDB, "200", uint64(28371397))
    47  	case dia.TraderJoeExchangeV2_1BNB:
    48  		tjas = makeTraderJoeAssetSource(exchange, "", "", relDB, "200", uint64(27099340))
    49  	case dia.TraderJoeExchangeV2_2Avalanche:
    50  		tjas = makeTraderJoeAssetSource(exchange, "", "", relDB, "200", uint64(46536129))
    51  	}
    52  
    53  	go func() {
    54  		tjas.fetchAssets()
    55  	}()
    56  	return tjas
    57  }
    58  
    59  // makeTraderJoeAssetSource initializes a Trader Joe asset source, creating an instance of the
    60  // TraderJoeAssetSource struct with the specified configuration and parameters.
    61  func makeTraderJoeAssetSource(exchange dia.Exchange, restDial string, wsDial string, relDB *models.RelDB, waitMilliSeconds string, startBlock uint64) *TraderJoeAssetSource {
    62  	var (
    63  		restClient   *ethclient.Client
    64  		wsClient     *ethclient.Client
    65  		err          error
    66  		assetChannel = make(chan dia.Asset)
    67  		doneChannel  = make(chan bool)
    68  		tjas         *TraderJoeAssetSource
    69  	)
    70  
    71  	log.Infof("Init rest and ws client for %s.", exchange.BlockChain.Name)
    72  	restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", restDial))
    73  	if err != nil {
    74  		log.Fatal("init rest client: ", err)
    75  	}
    76  	wsClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_WS", wsDial))
    77  	if err != nil {
    78  		log.Fatal("init ws client: ", err)
    79  	}
    80  
    81  	var waitTime int
    82  	waitTimeString := utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_WAIT_TIME", waitMilliSeconds)
    83  	waitTime, err = strconv.Atoi(waitTimeString)
    84  	if err != nil {
    85  		log.Error("could not parse wait time: ", err)
    86  		waitTime = 500
    87  	}
    88  
    89  	tjas = &TraderJoeAssetSource{
    90  		RestClient:             restClient,
    91  		WsClient:               wsClient,
    92  		relDB:                  relDB,
    93  		assetChannel:           assetChannel,
    94  		doneChannel:            doneChannel,
    95  		exchange:               exchange,
    96  		waitTime:               waitTime,
    97  		startBlock:             startBlock,
    98  		factoryContractAddress: common.HexToAddress(exchange.Contract),
    99  	}
   100  	return tjas
   101  }
   102  
   103  // fetchAssets retrieves pool creation events from the Trader Joe factory contract address and processes them.
   104  func (tjas *TraderJoeAssetSource) fetchAssets() {
   105  
   106  	log.Info("Fetching Trader Joe LBPairCreated events...")
   107  	log.Info("Getting lb pairs creations from address: ", tjas.factoryContractAddress.Hex())
   108  
   109  	var blocknumber int64
   110  	_, startblock, err := tjas.relDB.GetScraperIndex(tjas.exchange.Name, dia.SCRAPER_TYPE_ASSETCOLLECTOR)
   111  	if err != nil {
   112  		log.Error("GetScraperIndex: ", err)
   113  	} else {
   114  		tjas.startBlock = uint64(startblock)
   115  	}
   116  
   117  	// Initialize an Ethereum event filter for the Trader Joe factory contract.
   118  	contractFilter, err := traderjoe.NewTraderjoeFilterer(tjas.factoryContractAddress, tjas.WsClient)
   119  	if err != nil {
   120  		log.Error(err)
   121  	}
   122  
   123  	// Retrieve LBPairCreated events using the event filter.
   124  	lbPairCreated, err := contractFilter.FilterLBPairCreated(
   125  		&bind.FilterOpts{Start: tjas.startBlock},
   126  		[]common.Address{},
   127  		[]common.Address{},
   128  		[]*big.Int{},
   129  	)
   130  	if err != nil {
   131  		log.Error("filter pool created: ", err)
   132  	}
   133  
   134  	// Don't send duplicate assets to the main.
   135  	checkMap := make(map[string]struct{})
   136  
   137  	// Iterate through the LBPairCreated events.
   138  	for lbPairCreated.Next() {
   139  		blocknumber = int64(lbPairCreated.Event.Raw.BlockNumber)
   140  
   141  		asset0, err := ethhelper.ETHAddressToAsset(lbPairCreated.Event.TokenX, tjas.RestClient, tjas.exchange.BlockChain.Name)
   142  		if err != nil {
   143  			log.Errorf("ETHAddressToAsset for address %s: %v", lbPairCreated.Event.TokenX.Hex(), err)
   144  		}
   145  		asset1, err := ethhelper.ETHAddressToAsset(lbPairCreated.Event.TokenY, tjas.RestClient, tjas.exchange.BlockChain.Name)
   146  		if err != nil {
   147  			log.Errorf("ETHAddressToAsset for address %s: %v", lbPairCreated.Event.TokenX.Hex(), err)
   148  		}
   149  
   150  		if _, ok := checkMap[asset0.Address]; !ok {
   151  			if asset0.Symbol != "" {
   152  				checkMap[asset0.Address] = struct{}{}
   153  				tjas.assetChannel <- asset0
   154  			}
   155  		}
   156  		if _, ok := checkMap[asset1.Address]; !ok {
   157  			if asset1.Symbol != "" {
   158  				checkMap[asset1.Address] = struct{}{}
   159  				tjas.assetChannel <- asset1
   160  			}
   161  		}
   162  
   163  	}
   164  	err = tjas.relDB.SetScraperIndex(tjas.exchange.Name, dia.SCRAPER_TYPE_ASSETCOLLECTOR, dia.INDEX_TYPE_BLOCKNUMBER, blocknumber)
   165  	if err != nil {
   166  		log.Error("SetScraperIndex: ", err)
   167  	}
   168  	// Signal that pool retrieval and processing is complete.
   169  	tjas.doneChannel <- true
   170  }
   171  
   172  // Asset returns a channel for receiving dia.Asset instances scraped by the Trader Joe asset source.
   173  func (tjas *TraderJoeAssetSource) Asset() chan dia.Asset {
   174  	return tjas.assetChannel
   175  }
   176  
   177  // Done returns a channel for signaling the completion of Trader Joe asset scraping.
   178  func (tjas *TraderJoeAssetSource) Done() chan bool {
   179  	return tjas.doneChannel
   180  }