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 }