github.com/diadata-org/diadata@v1.4.593/pkg/dia/scraper/liquidity-scrapers/AyinScraper.go (about)

     1  package liquidityscrapers
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/diadata-org/diadata/pkg/dia"
     9  	alephiumhelper "github.com/diadata-org/diadata/pkg/dia/helpers/alephium-helper"
    10  	models "github.com/diadata-org/diadata/pkg/model"
    11  	"github.com/diadata-org/diadata/pkg/utils"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  type AyinLiquidityScraper struct {
    16  	logger                    *logrus.Entry
    17  	api                       *alephiumhelper.AlephiumClient
    18  	poolChannel               chan dia.Pool
    19  	doneChannel               chan bool
    20  	blockchain                string
    21  	exchangeName              string
    22  	relDB                     *models.RelDB
    23  	datastore                 *models.DB
    24  	targetSwapContract        string
    25  	swapContractsLimit        int
    26  	handlerType               string
    27  	sleepBetweenContractCalls time.Duration
    28  }
    29  
    30  // NewAyinLiquidityScraper returns a new AyinLiquidityScraper initialized with default values.
    31  // The instance is asynchronously scraping as soon as it is created.
    32  // ENV values:
    33  //
    34  //	 	AYIN_SLEEP_TIMEOUT - (optional,millisecond), make timeout between API calls, default "alephiumhelper.DefaultSleepBetweenContractCalls" value
    35  //		AYIN_TARGET_SWAP_CONTRACT - (optional, string), useful for debug, default = ""
    36  //		AYIN_DEBUG - (optional, bool), make stdout output with alephium client http call, default = false
    37  func NewAyinLiquidityScraper(exchange dia.Exchange, relDB *models.RelDB, datastore *models.DB) *AyinLiquidityScraper {
    38  	targetSwapContract := utils.Getenv(
    39  		strings.ToUpper(exchange.Name)+"_TARGET_SWAP_CONTRACT",
    40  		"",
    41  	)
    42  	isDebug := utils.GetenvBool(strings.ToUpper(exchange.Name)+"_DEBUG", false)
    43  	sleepBetweenContractCalls := utils.GetTimeDurationFromIntAsMilliseconds(
    44  		utils.GetenvInt(
    45  			strings.ToUpper(exchange.Name)+"_SLEEP_TIMEOUT",
    46  			alephiumhelper.DefaultSleepBetweenContractCalls,
    47  		),
    48  	)
    49  	swapContractsLimit := utils.GetenvInt(
    50  		strings.ToUpper(exchange.Name)+"_SWAP_CONTRACTS_LIMIT",
    51  		alephiumhelper.DefaultSwapContractsLimit,
    52  	)
    53  
    54  	var (
    55  		poolChannel = make(chan dia.Pool)
    56  		doneChannel = make(chan bool)
    57  		scraper     *AyinLiquidityScraper
    58  	)
    59  
    60  	alephiumClient := alephiumhelper.NewAlephiumClient(
    61  		log.WithContext(context.Background()).WithField("context", "AlephiumClient"),
    62  		sleepBetweenContractCalls,
    63  		isDebug,
    64  	)
    65  
    66  	scraper = &AyinLiquidityScraper{
    67  		api:                       alephiumClient,
    68  		poolChannel:               poolChannel,
    69  		doneChannel:               doneChannel,
    70  		exchangeName:              exchange.Name,
    71  		blockchain:                exchange.BlockChain.Name,
    72  		relDB:                     relDB,
    73  		datastore:                 datastore,
    74  		targetSwapContract:        targetSwapContract,
    75  		swapContractsLimit:        swapContractsLimit,
    76  		handlerType:               "liquidity",
    77  		sleepBetweenContractCalls: sleepBetweenContractCalls,
    78  	}
    79  	scraper.logger = logrus.
    80  		New().
    81  		WithContext(context.Background()).
    82  		WithField("handlerType", scraper.handlerType).
    83  		WithField("context", "AyinLiquidityScraper")
    84  
    85  	go scraper.fetchPools()
    86  
    87  	return scraper
    88  }
    89  
    90  func (s *AyinLiquidityScraper) fetchPools() {
    91  	logger := s.logger.WithFields(logrus.Fields{
    92  		"function": "fetchPools",
    93  	})
    94  
    95  	contractAddresses, err := s.getSubcontracts()
    96  	if err != nil {
    97  		s.logger.WithError(err).Error("failed to get contract addresses")
    98  		return
    99  	}
   100  	log.Infof("fetched %v contract addresses.", len(contractAddresses))
   101  
   102  	// Fetch all pool addresses from on-chain
   103  	for _, contractAddress := range contractAddresses {
   104  		var decimals []int64
   105  
   106  		tokenPairs, err := s.api.GetTokenPairAddresses(contractAddress)
   107  		if err != nil {
   108  			s.logger.
   109  				WithField("contractAddress", contractAddress).
   110  				WithError(err).
   111  				Error("failed to get GetTokenPairAddresses")
   112  			continue
   113  		}
   114  
   115  		pool := dia.Pool{
   116  			Exchange:     dia.Exchange{Name: s.exchangeName},
   117  			Blockchain:   dia.BlockChain{Name: s.blockchain},
   118  			Address:      contractAddress,
   119  			Time:         time.Now(),
   120  			Assetvolumes: make([]dia.AssetVolume, 2),
   121  		}
   122  
   123  		for i := 0; i < 2; i++ {
   124  			asset, err := s.relDB.GetAsset(tokenPairs[i], dia.ALEPHIUM)
   125  			if err != nil {
   126  				log.Error("GetAsset from DB: ", err)
   127  			}
   128  			pool.Assetvolumes[i] = dia.AssetVolume{
   129  				Index: uint8(i),
   130  				Asset: asset,
   131  			}
   132  			decimals = append(decimals, int64(asset.Decimals))
   133  		}
   134  
   135  		contractState, err := s.api.GetContractState(contractAddress)
   136  		if err != nil {
   137  			logger.
   138  				WithError(err).
   139  				Error("failed to GetContractState")
   140  			continue
   141  		}
   142  
   143  		pool.Assetvolumes[0].Volume, _ = utils.StringToFloat64(
   144  			contractState.MutFields[0].Value,
   145  			decimals[0],
   146  		)
   147  		pool.Assetvolumes[1].Volume, _ = utils.StringToFloat64(
   148  			contractState.MutFields[1].Value,
   149  			decimals[1],
   150  		)
   151  
   152  		// Determine USD liquidity.
   153  		if pool.SufficientNativeBalance(GLOBAL_NATIVE_LIQUIDITY_THRESHOLD) {
   154  			s.datastore.GetPoolLiquiditiesUSD(&pool, priceCache)
   155  		}
   156  		s.poolChannel <- pool
   157  
   158  	}
   159  
   160  	s.doneChannel <- true
   161  }
   162  
   163  func (s *AyinLiquidityScraper) getSubcontracts() ([]string, error) {
   164  	if s.targetSwapContract != "" {
   165  		return []string{s.targetSwapContract}, nil
   166  	}
   167  	contractAddresses, err := s.api.GetSwapPairsContractAddresses(s.swapContractsLimit)
   168  	return contractAddresses.SubContracts, err
   169  }
   170  
   171  func (s *AyinLiquidityScraper) Pool() chan dia.Pool {
   172  	return s.poolChannel
   173  }
   174  
   175  func (s *AyinLiquidityScraper) Done() chan bool {
   176  	return s.doneChannel
   177  }