github.com/diadata-org/diadata@v1.4.593/pkg/dia/scraper/liquidity-scrapers/Bancor.go (about) 1 package liquidityscrapers 2 3 import ( 4 "encoding/json" 5 "errors" 6 "math" 7 "math/big" 8 "strings" 9 "time" 10 11 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/curvefi/token" 12 models "github.com/diadata-org/diadata/pkg/model" 13 "github.com/diadata-org/diadata/pkg/utils" 14 15 "github.com/diadata-org/diadata/pkg/dia" 16 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/bancor/ConverterTypeFour" 17 ConvertertypeOne "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/bancor/ConverterTypeOne" 18 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/bancor/ConverterTypeThree" 19 20 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/bancor/ConverterTypeZero" 21 "github.com/ethereum/go-ethereum/accounts/abi/bind" 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/ethclient" 24 ) 25 26 type BancorPoolScraper struct { 27 RestClient *ethclient.Client 28 datastore *models.DB 29 poolChannel chan dia.Pool 30 doneChannel chan bool 31 blockchain string 32 exchangeName string 33 pool string 34 } 35 36 type BancorPool struct { 37 Reserves []struct { 38 DltID string `json:"dlt_id"` 39 Symbol string `json:"symbol"` 40 Name string `json:"name"` 41 Balance struct { 42 Usd string `json:"usd"` 43 } `json:"balance"` 44 Weight int `json:"weight"` 45 Price struct { 46 Usd string `json:"usd"` 47 } `json:"price"` 48 Price24HAgo struct { 49 Usd string `json:"usd"` 50 } `json:"price_24h_ago"` 51 Volume24H struct { 52 Usd string `json:"usd"` 53 Base string `json:"base"` 54 } `json:"volume_24h"` 55 } `json:"reserves"` 56 DltType string `json:"dlt_type"` 57 DltID string `json:"dlt_id"` 58 Type int `json:"type"` 59 Version int `json:"version"` 60 Symbol string `json:"symbol"` 61 Name string `json:"name"` 62 Supply string `json:"supply"` 63 ConverterDltID string `json:"converter_dlt_id"` 64 ConversionFee string `json:"conversion_fee"` 65 Liquidity struct { 66 Usd string `json:"usd"` 67 } `json:"liquidity"` 68 Volume24H struct { 69 Usd string `json:"usd"` 70 } `json:"volume_24h"` 71 Fees24H struct { 72 Usd string `json:"usd"` 73 } `json:"fees_24h"` 74 } 75 76 type BancorPools struct { 77 Data []BancorPool `json:"data"` 78 Timestamp struct { 79 Ethereum struct { 80 Block int `json:"block"` 81 Timestamp int64 `json:"timestamp"` 82 } `json:"ethereum"` 83 } `json:"timestamp"` 84 } 85 86 func NewBancorPoolScraper(exchange dia.Exchange, datastore *models.DB) *BancorPoolScraper { 87 var ( 88 restClient *ethclient.Client 89 err error 90 poolChannel = make(chan dia.Pool) 91 doneChannel = make(chan bool) 92 scraper *BancorPoolScraper 93 pool = "0xC0205e203F423Bcd8B2a4d6f8C8A154b0Aa60F19" 94 ) 95 96 log.Infof("Init rest client for %s.", exchange.BlockChain.Name) 97 restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", curveRestDial)) 98 if err != nil { 99 log.Fatal("init rest client: ", err) 100 } 101 102 scraper = &BancorPoolScraper{ 103 RestClient: restClient, 104 datastore: datastore, 105 poolChannel: poolChannel, 106 doneChannel: doneChannel, 107 blockchain: exchange.BlockChain.Name, 108 exchangeName: exchange.Name, 109 pool: pool, 110 } 111 112 go func() { 113 scraper.fetchPools() 114 scraper.doneChannel <- true 115 }() 116 117 return scraper 118 } 119 120 func (scraper *BancorPoolScraper) readPools() ([]BancorPool, error) { 121 var bpools BancorPools 122 pairs, _, err := utils.GetRequest("https://api-v2.bancor.network/pools") 123 if err != nil { 124 return nil, err 125 } 126 err = json.Unmarshal(pairs, &bpools) 127 if err != nil { 128 log.Error("Error reading json", err) 129 130 } 131 return bpools.Data, nil 132 133 } 134 135 func (scraper *BancorPoolScraper) fetchpooltokenaddress(pool BancorPool) (address []common.Address, balances []*big.Int, err error) { 136 137 switch pool.Type { 138 case 0: 139 { 140 address, balances, err = scraper.ConverterTypeZero(common.HexToAddress(pool.ConverterDltID)) 141 if err != nil { 142 log.Errorln("Error getting Address", err) 143 } 144 145 } 146 case 1: 147 { 148 address, balances, err = scraper.ConverterTypeOne(common.HexToAddress(pool.ConverterDltID)) 149 if err != nil { 150 log.Errorln("Error getting Address", err) 151 } 152 } 153 case 3: 154 { 155 address, balances, err = scraper.ConverterTypeThree(common.HexToAddress(pool.ConverterDltID)) 156 if err != nil { 157 log.Errorln("Error getting Address", err) 158 } 159 } 160 case 4: 161 { 162 address, balances, err = scraper.ConverterTypeFour(common.HexToAddress(pool.ConverterDltID)) 163 if err != nil { 164 log.Errorln("Error getting Address", err) 165 } 166 } 167 default: 168 err = errors.New("type not available") 169 } 170 171 return 172 } 173 174 func (scraper *BancorPoolScraper) loadPoolData(poolCoinAddresses []common.Address, poolBalances []*big.Int, poolAddress common.Address) (pool dia.Pool) { 175 176 var ( 177 poolAssets []dia.Asset 178 ) 179 180 var err error 181 for _, c := range poolCoinAddresses { 182 var ( 183 coinCaller *token.TokenCaller 184 symbol string 185 decimals uint8 186 decimalsBig *big.Int 187 name string 188 ) 189 if c == common.HexToAddress("0x0000000000000000000000000000000000000000") { 190 continue 191 } else if c == common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") { 192 symbol = "ETH" 193 decimals = uint8(18) 194 name = "Ether" 195 c = common.HexToAddress("0x0000000000000000000000000000000000000000") 196 } else { 197 log.Infoln("Getting token details for : ", c) 198 199 coinCaller, err = token.NewTokenCaller(c, scraper.RestClient) 200 if err != nil { 201 log.Error("NewTokenCaller: ", err) 202 continue 203 } 204 symbol, err = coinCaller.Symbol(&bind.CallOpts{}) 205 if err != nil { 206 log.Error("Symbol: ", err, c.Hex()) 207 continue 208 } 209 decimalsBig, err = coinCaller.Decimals(&bind.CallOpts{}) 210 if err != nil { 211 log.Error("Decimals: ", err) 212 continue 213 } 214 decimals = uint8(decimalsBig.Uint64()) 215 name, err = coinCaller.Name(&bind.CallOpts{}) 216 if err != nil { 217 log.Error("Name: ", err) 218 continue 219 } 220 } 221 log.Info(symbol, " ", decimals, " ", "'", name, "'", " ", c) 222 223 poolAssets = append(poolAssets, dia.Asset{ 224 Address: c.Hex(), 225 Blockchain: scraper.blockchain, 226 Decimals: decimals, 227 Symbol: symbol, 228 Name: name, 229 }) 230 231 } 232 233 for i := range poolAssets { 234 var volume float64 235 if poolBalances[i] != nil { 236 volume, _ = new(big.Float).Quo(big.NewFloat(0).SetInt(poolBalances[i]), new(big.Float).SetFloat64(math.Pow10(int(poolAssets[i].Decimals)))).Float64() 237 238 } 239 pool.Assetvolumes = append(pool.Assetvolumes, dia.AssetVolume{ 240 Asset: poolAssets[i], 241 Volume: volume, 242 }) 243 } 244 pool.Exchange = dia.Exchange{Name: scraper.exchangeName} 245 pool.Blockchain = dia.BlockChain{Name: scraper.blockchain} 246 pool.Address = poolAddress.Hex() 247 248 // Determine USD liquidity. 249 if pool.SufficientNativeBalance(GLOBAL_NATIVE_LIQUIDITY_THRESHOLD) { 250 scraper.datastore.GetPoolLiquiditiesUSD(&pool, priceCache) 251 } 252 253 pool.Time = time.Now() 254 255 return pool 256 } 257 258 func (scraper *BancorPoolScraper) ConverterTypeZero(address common.Address) (tokenAddress []common.Address, poolBalances []*big.Int, err error) { 259 260 contract, err := ConverterTypeZero.NewConverterTypeZeroCaller(address, scraper.RestClient) 261 if err != nil { 262 return 263 } 264 265 tokenCount, err := contract.ConnectorTokenCount(&bind.CallOpts{}) 266 if err != nil { 267 return 268 } 269 270 var i uint16 271 272 for i = 0; i < tokenCount; i++ { 273 token1, err := contract.ConnectorTokens(&bind.CallOpts{}, big.NewInt(int64(i))) 274 if err != nil { 275 log.Errorln("Error", err) 276 } 277 tokenAddress = append(tokenAddress, token1) 278 279 reserve, err := contract.GetReserveBalance(&bind.CallOpts{}, tokenAddress[int64(i)]) 280 if err != nil { 281 log.Errorln("Error", err) 282 } 283 poolBalances = append(poolBalances, reserve) 284 } 285 286 return 287 288 } 289 290 func (scraper *BancorPoolScraper) ConverterTypeOne(address common.Address) (tokenAddress []common.Address, poolBalances []*big.Int, err error) { 291 292 contract, err := ConvertertypeOne.NewConvertertypeOne(address, scraper.RestClient) 293 if err != nil { 294 return 295 } 296 297 tokenCount, err := contract.ConnectorTokenCount(&bind.CallOpts{}) 298 if err != nil { 299 return 300 } 301 302 var i uint16 303 304 for i = 0; i < tokenCount; i++ { 305 token1, err := contract.ConnectorTokens(&bind.CallOpts{}, big.NewInt(int64(i))) 306 if err != nil { 307 log.Errorln("Error", err) 308 } 309 tokenAddress = append(tokenAddress, token1) 310 311 reserve, err := contract.ReserveBalance(&bind.CallOpts{}, tokenAddress[int64(i)]) 312 if err != nil { 313 log.Errorln("Error", err) 314 } 315 poolBalances = append(poolBalances, reserve) 316 } 317 318 return 319 320 } 321 322 func (scraper *BancorPoolScraper) ConverterTypeThree(address common.Address) (tokenAddress []common.Address, poolBalances []*big.Int, err error) { 323 324 contract, err := ConverterTypeThree.NewConverterTypeThree(address, scraper.RestClient) 325 if err != nil { 326 return 327 } 328 329 tokenCount, err := contract.ConnectorTokenCount(&bind.CallOpts{}) 330 if err != nil { 331 return 332 } 333 334 var i uint16 335 336 for i = 0; i < tokenCount; i++ { 337 token1, err := contract.ConnectorTokens(&bind.CallOpts{}, big.NewInt(int64(i))) 338 if err != nil { 339 log.Errorln("Error", err) 340 } 341 tokenAddress = append(tokenAddress, token1) 342 343 reserve, err := contract.ReserveBalance(&bind.CallOpts{}, tokenAddress[int64(i)]) 344 if err != nil { 345 log.Errorln("Error", err) 346 } 347 poolBalances = append(poolBalances, reserve) 348 } 349 350 return 351 352 } 353 354 func (scraper *BancorPoolScraper) ConverterTypeFour(address common.Address) (tokenAddress []common.Address, poolBalances []*big.Int, err error) { 355 356 contract, err := ConverterTypeFour.NewConverterTypeFour(address, scraper.RestClient) 357 if err != nil { 358 return 359 } 360 361 tokenCount, err := contract.ConnectorTokenCount(&bind.CallOpts{}) 362 if err != nil { 363 return 364 } 365 366 var i uint16 367 368 for i = 0; i < tokenCount; i++ { 369 token1, err := contract.ConnectorTokens(&bind.CallOpts{}, big.NewInt(int64(i))) 370 if err != nil { 371 log.Errorln("Error", err) 372 } 373 tokenAddress = append(tokenAddress, token1) 374 375 reserve, err := contract.GetReserveBalance(&bind.CallOpts{}, tokenAddress[int64(i)]) 376 if err != nil { 377 log.Errorln("Error", err) 378 } 379 poolBalances = append(poolBalances, reserve) 380 } 381 382 return 383 384 } 385 386 // fetchPools collects all available pools and sends them into the pool channel. 387 func (scraper *BancorPoolScraper) fetchPools() { 388 389 bpools, err := scraper.readPools() 390 if err != nil { 391 log.Error("Couldn't obtain Bancor product ids:", err) 392 } 393 394 for _, bpool := range bpools { 395 396 poolassetaddress, balances, err := scraper.fetchpooltokenaddress(bpool) 397 if err != nil { 398 log.Errorln("error getting pool detal", err) 399 continue 400 } 401 402 pool := scraper.loadPoolData(poolassetaddress, balances, common.HexToAddress(bpool.ConverterDltID)) 403 scraper.poolChannel <- pool 404 405 } 406 407 } 408 409 func (scraper *BancorPoolScraper) Pool() chan dia.Pool { 410 return scraper.poolChannel 411 } 412 413 func (scraper *BancorPoolScraper) Done() chan bool { 414 return scraper.doneChannel 415 }