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 }