github.com/diadata-org/diadata@v1.4.593/pkg/dia/service/assetservice/source/ayin.go (about) 1 package source 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 // AlphiumAssetSource aset collector object - which serves assetCollector command 16 type AyinAssetSource struct { 17 // client - interaction with alephium REST API services 18 alephiumClient *alephiumhelper.AlephiumClient 19 // channel to store received asset info 20 assetChannel chan dia.Asset 21 // channel which informs about work is finished 22 doneChannel chan bool 23 // blockchain name 24 blockchain string 25 // DB connector to interact with databases 26 relDB *models.RelDB 27 // logs all events here 28 logger *logrus.Entry 29 // swap contracts count limitation in alephium REST API 30 swapContractsLimit int 31 32 sleepTimeout time.Duration 33 exchangeName string 34 targetSwapContract string 35 } 36 37 // NewAlephiumAssetSource creates object to get alephium assets 38 // ENV values: 39 // 40 // AYIN_ASSETS_SLEEP_TIMEOUT - (optional,millisecond), make timeout between API calls, default "alephiumhelper.DefaultSleepBetweenContractCalls" value 41 // AYIN_SWAP_CONTRACTS_LIMIT - (optional, int), limit to get swap contact addresses, default "alephiumhelper.DefaultSwapContractsLimit" value 42 // AYIN_TARGET_SWAP_CONTRACT - (optional, string), useful for debug, default = "" 43 // AYIN_DEBUG - (optional, bool), make stdout output with alephium client http call, default = false 44 func NewAyinAssetSource(exchange dia.Exchange, relDB *models.RelDB) *AyinAssetSource { 45 sleepBetweenContractCalls := utils.GetTimeDurationFromIntAsMilliseconds( 46 utils.GetenvInt(strings.ToUpper(exchange.Name)+"_SLEEP_TIMEOUT", alephiumhelper.DefaultSleepBetweenContractCalls), 47 ) 48 swapContractsLimit := utils.GetenvInt( 49 strings.ToUpper(exchange.Name)+"_SWAP_CONTRACTS_LIMIT", 50 alephiumhelper.DefaultSwapContractsLimit, 51 ) 52 targetSwapContract := utils.Getenv(strings.ToUpper(exchange.Name)+"_TARGET_SWAP_CONTRACT", "") 53 isDebug := utils.GetenvBool(strings.ToUpper(exchange.Name)+"_DEBUG", false) 54 55 var ( 56 assetChannel = make(chan dia.Asset) 57 doneChannel = make(chan bool) 58 ) 59 60 alephiumClient := alephiumhelper.NewAlephiumClient( 61 log.WithContext(context.Background()).WithField("context", "AlephiumClient"), 62 sleepBetweenContractCalls, 63 isDebug, 64 ) 65 66 logger := log. 67 WithContext(context.Background()). 68 WithField("service", "assetCollector"). 69 WithField("network", exchange.BlockChain.Name) 70 71 scraper := &AyinAssetSource{ 72 alephiumClient: alephiumClient, 73 assetChannel: assetChannel, 74 doneChannel: doneChannel, 75 blockchain: exchange.BlockChain.Name, 76 relDB: relDB, 77 logger: logger, 78 swapContractsLimit: swapContractsLimit, 79 exchangeName: exchange.Name, 80 sleepTimeout: sleepBetweenContractCalls, 81 targetSwapContract: targetSwapContract, 82 } 83 84 go scraper.fetchAssets() 85 86 return scraper 87 } 88 89 func (s *AyinAssetSource) getSubcontracts() ([]string, error) { 90 if s.targetSwapContract != "" { 91 return []string{s.targetSwapContract}, nil 92 } 93 contractAddresses, err := s.alephiumClient.GetSwapPairsContractAddresses(s.swapContractsLimit) 94 return contractAddresses.SubContracts, err 95 } 96 97 func (s *AyinAssetSource) fetchAssets() { 98 s.logger.Info("started") 99 100 contractAddresses, err := s.getSubcontracts() 101 if err != nil { 102 s.logger.WithError(err).Error("failed to get contract addresses") 103 return 104 } 105 106 pools := make(map[string]dia.Pool) 107 108 for _, contractAddress := range contractAddresses { 109 tokenPairs, err := s.alephiumClient.GetTokenPairAddresses(contractAddress) 110 111 if err != nil { 112 s.logger. 113 WithField("contractAddress", contractAddress). 114 WithError(err). 115 Error("failed to get GetTokenPairAddresses") 116 continue 117 } 118 119 pools[contractAddress] = dia.Pool{ 120 Exchange: dia.Exchange{Name: s.exchangeName}, 121 Blockchain: dia.BlockChain{Name: s.blockchain}, 122 Address: contractAddress, 123 Assetvolumes: make([]dia.AssetVolume, 2), 124 } 125 126 for i := 0; i < 2; i++ { 127 128 // native ALPH token has no contract - use data from variable 129 if tokenPairs[i] == alephiumhelper.ALPHNativeToken.Address { 130 pools[contractAddress].Assetvolumes[i].Asset = alephiumhelper.ALPHNativeToken 131 pools[contractAddress].Assetvolumes[i].Asset.Blockchain = s.blockchain 132 133 s.assetChannel <- pools[contractAddress].Assetvolumes[i].Asset 134 135 continue 136 } 137 138 asset, err := s.alephiumClient.GetTokenInfoForContractDecoded(tokenPairs[i], s.blockchain) 139 if err != nil { 140 s.logger. 141 WithField("contractAddress", contractAddress). 142 WithField("tokenPairs[i]", tokenPairs[i]). 143 WithError(err). 144 Error("failed to get GetTokenInfoForContract") 145 146 delete(pools, contractAddress) 147 continue 148 } 149 pools[contractAddress].Assetvolumes[i].Asset = *asset 150 151 s.assetChannel <- *asset 152 } 153 } 154 155 s.doneChannel <- true 156 } 157 158 func (s *AyinAssetSource) Asset() chan dia.Asset { 159 return s.assetChannel 160 } 161 162 func (s *AyinAssetSource) Done() chan bool { 163 return s.doneChannel 164 }