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  }