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

     1  package source
     2  
     3  import (
     4  	"math/big"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/velodrome"
    10  	models "github.com/diadata-org/diadata/pkg/model"
    11  
    12  	"github.com/diadata-org/diadata/pkg/dia"
    13  	"github.com/diadata-org/diadata/pkg/utils"
    14  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    15  	"github.com/ethereum/go-ethereum/common"
    16  	"github.com/ethereum/go-ethereum/ethclient"
    17  )
    18  
    19  type VelodromePair struct {
    20  	Token0      dia.Asset
    21  	Token1      dia.Asset
    22  	ForeignName string
    23  	Address     common.Address
    24  }
    25  
    26  const (
    27  	velodromeWaitMilliseconds = "500"
    28  	restDialOptimism          = ""
    29  	restDialSwellchain        = ""
    30  )
    31  
    32  var velodromeExchangeFactoryContractAddress string
    33  
    34  type VelodromeAssetSource struct {
    35  	RestClient   *ethclient.Client
    36  	relDB        *models.RelDB
    37  	assetChannel chan dia.Asset
    38  	doneChannel  chan bool
    39  	exchange     dia.Exchange
    40  	blockchain   string
    41  	waitTime     int
    42  }
    43  
    44  func NewVelodromeAssetSource(exchange dia.Exchange, relDB *models.RelDB) (uas *VelodromeAssetSource) {
    45  	switch exchange.Name {
    46  	case dia.VelodromeExchange:
    47  		uas = makeVelodromeAssetSource(exchange, restDialOptimism, relDB, velodromeWaitMilliseconds)
    48  	case dia.VelodromeSlipstreamExchange:
    49  		uas = makeVelodromeAssetSource(exchange, restDialOptimism, relDB, velodromeWaitMilliseconds)
    50  	case dia.AerodromeSlipstreamExchange:
    51  		uas = makeVelodromeAssetSource(exchange, restDialBase, relDB, velodromeWaitMilliseconds)
    52  	case dia.AerodromeV1Exchange:
    53  		uas = makeVelodromeAssetSource(exchange, restDialBase, relDB, velodromeWaitMilliseconds)
    54  	case dia.VelodromeExchangeSwellchain:
    55  		uas = makeVelodromeAssetSource(exchange, restDialSwellchain, relDB, velodromeWaitMilliseconds)
    56  	}
    57  
    58  	velodromeExchangeFactoryContractAddress = exchange.Contract
    59  
    60  	go func() {
    61  		uas.fetchAssets()
    62  	}()
    63  	return uas
    64  
    65  }
    66  
    67  // makeVelodromeAssetSource returns an asset source as used in NewVelodromeAssetSource.
    68  func makeVelodromeAssetSource(exchange dia.Exchange, restDial string, relDB *models.RelDB, waitMilliseconds string) *VelodromeAssetSource {
    69  	var (
    70  		restClient   *ethclient.Client
    71  		err          error
    72  		assetChannel = make(chan dia.Asset)
    73  		doneChannel  = make(chan bool)
    74  		uas          *VelodromeAssetSource
    75  	)
    76  
    77  	log.Infof("Init rest client for %s.", exchange.BlockChain.Name)
    78  	restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", restDial))
    79  	if err != nil {
    80  		log.Fatal("init rest client: ", err)
    81  	}
    82  	var waitTime int
    83  	waitTimeString := utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_WAIT_TIME", waitMilliseconds)
    84  	waitTime, err = strconv.Atoi(waitTimeString)
    85  	if err != nil {
    86  		log.Error("could not parse wait time: ", err)
    87  		waitTime = 500
    88  	}
    89  	uas = &VelodromeAssetSource{
    90  		RestClient:   restClient,
    91  		relDB:        relDB,
    92  		assetChannel: assetChannel,
    93  		doneChannel:  doneChannel,
    94  		exchange:     exchange,
    95  		blockchain:   exchange.BlockChain.Name,
    96  		waitTime:     waitTime,
    97  	}
    98  	return uas
    99  }
   100  
   101  func (uas *VelodromeAssetSource) Asset() chan dia.Asset {
   102  	return uas.assetChannel
   103  }
   104  
   105  func (uas *VelodromeAssetSource) Done() chan bool {
   106  	return uas.doneChannel
   107  }
   108  
   109  func (uas *VelodromeAssetSource) getNumPairs() (int, error) {
   110  	var contract *velodrome.PoolFactoryCaller
   111  	contract, err := velodrome.NewPoolFactoryCaller(common.HexToAddress(velodromeExchangeFactoryContractAddress), uas.RestClient)
   112  	if err != nil {
   113  		log.Error("getNumPairs: ", err)
   114  	}
   115  
   116  	numPairs, err := contract.AllPoolsLength(&bind.CallOpts{})
   117  	return int(numPairs.Int64()), err
   118  }
   119  
   120  func (uas *VelodromeAssetSource) fetchAssets() {
   121  
   122  	numPairs, err := uas.getNumPairs()
   123  	if err != nil {
   124  		log.Fatal(err)
   125  	}
   126  	log.Info("Found ", numPairs, " pairs")
   127  	checkMap := make(map[string]struct{})
   128  
   129  	_, index, err := uas.relDB.GetScraperIndex(uas.exchange.Name, dia.SCRAPER_TYPE_ASSETCOLLECTOR)
   130  	if err != nil {
   131  		log.Error("GetScraperIndex: ", err)
   132  	}
   133  	log.Info("Start at index ", index)
   134  
   135  	for index < int64(numPairs) {
   136  		log.Info("index: ", index)
   137  		time.Sleep(time.Duration(uas.waitTime) * time.Millisecond)
   138  		pair, err := uas.GetPairByID(int64(numPairs) - 1 - index)
   139  		if err != nil {
   140  			log.Errorln("Error getting pair with ID ", numPairs-1-int(index))
   141  		}
   142  		asset0 := pair.Token0
   143  		asset1 := pair.Token1
   144  		asset0.Blockchain = uas.blockchain
   145  		asset1.Blockchain = uas.blockchain
   146  		// Don't repeat sending already sent assets
   147  		if _, ok := checkMap[asset0.Address]; !ok {
   148  			if asset0.Symbol != "" {
   149  				checkMap[asset0.Address] = struct{}{}
   150  				uas.assetChannel <- asset0
   151  			}
   152  		}
   153  		if _, ok := checkMap[asset1.Address]; !ok {
   154  			if asset1.Symbol != "" {
   155  				checkMap[asset1.Address] = struct{}{}
   156  				uas.assetChannel <- asset1
   157  			}
   158  		}
   159  		index++
   160  	}
   161  	uas.doneChannel <- true
   162  }
   163  
   164  // GetPairByID returns the VelodromePair with the integer id @num
   165  func (uas *VelodromeAssetSource) GetPairByID(num int64) (VelodromePair, error) {
   166  	var contract *velodrome.PoolFactoryCaller
   167  	contract, err := velodrome.NewPoolFactoryCaller(common.HexToAddress(velodromeExchangeFactoryContractAddress), uas.RestClient)
   168  	if err != nil {
   169  		log.Error(err)
   170  		return VelodromePair{}, err
   171  	}
   172  	numToken := big.NewInt(num)
   173  	pairAddress, err := contract.AllPools(&bind.CallOpts{}, numToken)
   174  	if err != nil {
   175  		log.Error(err)
   176  		return VelodromePair{}, err
   177  	}
   178  
   179  	pair, err := uas.GetPairByAddress(pairAddress)
   180  	if err != nil {
   181  		log.Error(err)
   182  		return VelodromePair{}, err
   183  	}
   184  	// log.Infof("Get pair with ID %v: %v", num, pair)
   185  	return pair, err
   186  }
   187  
   188  func (uas *VelodromeAssetSource) GetPairByAddress(pairAddress common.Address) (pair VelodromePair, err error) {
   189  	connection := uas.RestClient
   190  	var pairContract *velodrome.IPoolCaller
   191  	pairContract, err = velodrome.NewIPoolCaller(pairAddress, connection)
   192  	if err != nil {
   193  		log.Error(err)
   194  		return VelodromePair{}, err
   195  	}
   196  
   197  	// Getting tokens from pair ---------------------
   198  	address0, _ := pairContract.Token0(&bind.CallOpts{})
   199  	address1, _ := pairContract.Token1(&bind.CallOpts{})
   200  	var token0Contract *velodrome.IERC20MetadataCaller
   201  	var token1Contract *velodrome.IERC20MetadataCaller
   202  	token0Contract, err = velodrome.NewIERC20MetadataCaller(address0, connection)
   203  	if err != nil {
   204  		log.Error(err)
   205  	}
   206  	token1Contract, err = velodrome.NewIERC20MetadataCaller(address1, connection)
   207  	if err != nil {
   208  		log.Error(err)
   209  	}
   210  	symbol0, err := token0Contract.Symbol(&bind.CallOpts{})
   211  	if err != nil {
   212  		log.Error(err)
   213  	}
   214  	symbol1, err := token1Contract.Symbol(&bind.CallOpts{})
   215  	if err != nil {
   216  		log.Error(err)
   217  	}
   218  	decimals0, err := token0Contract.Decimals(&bind.CallOpts{})
   219  	if err != nil {
   220  		log.Error(err)
   221  	}
   222  	decimals1, err := token1Contract.Decimals(&bind.CallOpts{})
   223  	if err != nil {
   224  		log.Error(err)
   225  	}
   226  
   227  	name0, err := uas.GetName(address0)
   228  	if err != nil {
   229  		log.Error(err)
   230  		return VelodromePair{}, err
   231  	}
   232  	name1, err := uas.GetName(address1)
   233  	if err != nil {
   234  		log.Error(err)
   235  		return VelodromePair{}, err
   236  	}
   237  	token0 := dia.Asset{
   238  		Address:  address0.Hex(),
   239  		Symbol:   symbol0,
   240  		Name:     name0,
   241  		Decimals: decimals0,
   242  	}
   243  	token1 := dia.Asset{
   244  		Address:  address1.Hex(),
   245  		Symbol:   symbol1,
   246  		Name:     name1,
   247  		Decimals: decimals1,
   248  	}
   249  	pair.Token0 = token0
   250  	pair.Token1 = token1
   251  
   252  	return pair, nil
   253  }
   254  
   255  // GetDecimals returns the decimals of the token with address @tokenAddress
   256  func (uas *VelodromeAssetSource) GetDecimals(tokenAddress common.Address) (decimals uint8, err error) {
   257  
   258  	var contract *velodrome.IERC20MetadataCaller
   259  	contract, err = velodrome.NewIERC20MetadataCaller(tokenAddress, uas.RestClient)
   260  	if err != nil {
   261  		log.Error(err)
   262  		return
   263  	}
   264  	decimals, err = contract.Decimals(&bind.CallOpts{})
   265  
   266  	return
   267  }
   268  
   269  func (uas *VelodromeAssetSource) GetName(tokenAddress common.Address) (name string, err error) {
   270  
   271  	var contract *velodrome.IERC20MetadataCaller
   272  	contract, err = velodrome.NewIERC20MetadataCaller(tokenAddress, uas.RestClient)
   273  	if err != nil {
   274  		log.Error(err)
   275  		return
   276  	}
   277  	name, err = contract.Name(&bind.CallOpts{})
   278  
   279  	return
   280  }