github.com/diadata-org/diadata@v1.4.593/pkg/dia/service/assetservice/source/uniswap.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/uniswap" 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 UniswapPair struct { 20 Token0 dia.Asset 21 Token1 dia.Asset 22 ForeignName string 23 Address common.Address 24 } 25 26 const ( 27 restDial = "" 28 restDialBase = "" 29 restDialBSC = "" 30 restDialPolygon = "" 31 restDialCelo = "" 32 restDialFantom = "" 33 restDialMoonriver = "" 34 restDialAurora = "" 35 restDialArbitrum = "" 36 restDialMetis = "" 37 restDialAvalanche = "" 38 restDialTelos = "" 39 restDialEvmos = "https://evmos-evm.publicnode.com" 40 restDialAstar = "" 41 restDialMoonbeam = "" 42 restDialWanchain = "" 43 restDialUnrealTestnet = "" 44 restDialUnreal = "" 45 restDialLinea = "" 46 47 uniswapWaitMilliseconds = "25" 48 baseWaitMilliseconds = "200" 49 sushiswapWaitMilliseconds = "100" 50 pancakeswapWaitMilliseconds = "100" 51 dfynWaitMilliseconds = "100" 52 ubeswapWaitMilliseconds = "200" 53 spookyswapWaitMilliseconds = "200" 54 spiritswapWaitMilliseconds = "200" 55 solarbeamWaitMilliseconds = "200" 56 trisolarisWaitMilliseconds = "200" 57 metisWaitMilliseconds = "200" 58 moonriverWaitMilliseconds = "500" 59 avalancheWaitMilliseconds = "200" 60 telosWaitMilliseconds = "400" 61 evmosWaitMilliseconds = "400" 62 astarWaitMilliseconds = "1000" 63 moonbeamWaitMilliseconds = "1000" 64 wanchainWaitMilliseconds = "1000" 65 ) 66 67 type UniswapAssetSource struct { 68 RestClient *ethclient.Client 69 relDB *models.RelDB 70 assetChannel chan dia.Asset 71 doneChannel chan bool 72 exchange dia.Exchange 73 waitTime int 74 } 75 76 var exchangeFactoryContractAddress string 77 78 func NewUniswapAssetSource(exchange dia.Exchange, relDB *models.RelDB) (uas *UniswapAssetSource) { 79 80 switch exchange.Name { 81 case dia.UniswapExchange: 82 uas = makeUniswapAssetSource(exchange, restDial, relDB, uniswapWaitMilliseconds) 83 case dia.SushiSwapExchange: 84 uas = makeUniswapAssetSource(exchange, restDial, relDB, sushiswapWaitMilliseconds) 85 case dia.SushiSwapExchangeArbitrum: 86 uas = makeUniswapAssetSource(exchange, restDialArbitrum, relDB, sushiswapWaitMilliseconds) 87 case dia.SushiSwapExchangeFantom: 88 uas = makeUniswapAssetSource(exchange, restDialFantom, relDB, sushiswapWaitMilliseconds) 89 case dia.SushiSwapExchangePolygon: 90 uas = makeUniswapAssetSource(exchange, restDialPolygon, relDB, sushiswapWaitMilliseconds) 91 case dia.ApeswapExchange: 92 uas = makeUniswapAssetSource(exchange, restDialBSC, relDB, sushiswapWaitMilliseconds) 93 case dia.CamelotExchange: 94 uas = makeUniswapAssetSource(exchange, restDialArbitrum, relDB, sushiswapWaitMilliseconds) 95 case dia.PanCakeSwap: 96 uas = makeUniswapAssetSource(exchange, restDialBSC, relDB, pancakeswapWaitMilliseconds) 97 case dia.DfynNetwork: 98 uas = makeUniswapAssetSource(exchange, restDialPolygon, relDB, dfynWaitMilliseconds) 99 case dia.QuickswapExchange: 100 uas = makeUniswapAssetSource(exchange, restDialPolygon, relDB, dfynWaitMilliseconds) 101 case dia.UbeswapExchange: 102 uas = makeUniswapAssetSource(exchange, restDialCelo, relDB, ubeswapWaitMilliseconds) 103 case dia.SpookyswapExchange: 104 uas = makeUniswapAssetSource(exchange, restDialFantom, relDB, spookyswapWaitMilliseconds) 105 case dia.SpiritswapExchange: 106 uas = makeUniswapAssetSource(exchange, restDialFantom, relDB, spiritswapWaitMilliseconds) 107 case dia.SolarbeamExchange: 108 uas = makeUniswapAssetSource(exchange, restDialMoonriver, relDB, solarbeamWaitMilliseconds) 109 case dia.TrisolarisExchange: 110 uas = makeUniswapAssetSource(exchange, restDialAurora, relDB, trisolarisWaitMilliseconds) 111 case dia.NetswapExchange: 112 uas = makeUniswapAssetSource(exchange, restDialMetis, relDB, metisWaitMilliseconds) 113 case dia.HuckleberryExchange: 114 uas = makeUniswapAssetSource(exchange, restDialMoonriver, relDB, moonriverWaitMilliseconds) 115 case dia.TraderJoeExchange: 116 uas = makeUniswapAssetSource(exchange, restDialAvalanche, relDB, avalancheWaitMilliseconds) 117 case dia.PangolinExchange: 118 uas = makeUniswapAssetSource(exchange, restDialAvalanche, relDB, avalancheWaitMilliseconds) 119 case dia.TethysExchange: 120 uas = makeUniswapAssetSource(exchange, restDialMetis, relDB, metisWaitMilliseconds) 121 case dia.HermesExchange: 122 uas = makeUniswapAssetSource(exchange, restDialMetis, relDB, metisWaitMilliseconds) 123 case dia.OmniDexExchange: 124 uas = makeUniswapAssetSource(exchange, restDialTelos, relDB, telosWaitMilliseconds) 125 case dia.DiffusionExchange: 126 uas = makeUniswapAssetSource(exchange, restDialEvmos, relDB, evmosWaitMilliseconds) 127 case dia.ArthswapExchange: 128 uas = makeUniswapAssetSource(exchange, restDialAstar, relDB, astarWaitMilliseconds) 129 case dia.StellaswapExchange: 130 uas = makeUniswapAssetSource(exchange, restDialMoonbeam, relDB, moonbeamWaitMilliseconds) 131 case dia.WanswapExchange: 132 uas = makeUniswapAssetSource(exchange, restDialWanchain, relDB, wanchainWaitMilliseconds) 133 case dia.PearlfiExchangeTestnet: 134 uas = makeUniswapAssetSource(exchange, restDialUnrealTestnet, relDB, wanchainWaitMilliseconds) 135 case dia.PearlfiExchange: 136 uas = makeUniswapAssetSource(exchange, restDialUnreal, relDB, wanchainWaitMilliseconds) 137 case dia.PearlfiStableswapExchange: 138 uas = makeUniswapAssetSource(exchange, restDialUnreal, relDB, wanchainWaitMilliseconds) 139 case dia.RamsesV1Exchange: 140 uas = makeUniswapAssetSource(exchange, restDialArbitrum, relDB, wanchainWaitMilliseconds) 141 case dia.NileV1Exchange: 142 uas = makeUniswapAssetSource(exchange, restDialLinea, relDB, wanchainWaitMilliseconds) 143 case dia.ThenaExchange: 144 uas = makeUniswapAssetSource(exchange, restDialBSC, relDB, sushiswapWaitMilliseconds) 145 case dia.UniswapExchangeBase: 146 uas = makeUniswapAssetSource(exchange, restDialBase, relDB, baseWaitMilliseconds) 147 } 148 149 exchangeFactoryContractAddress = exchange.Contract 150 151 go func() { 152 uas.fetchAssets() 153 }() 154 return uas 155 156 } 157 158 // makeUniswapAssetSource returns an asset source as used in NewUniswapAssetSource. 159 func makeUniswapAssetSource(exchange dia.Exchange, restDial string, relDB *models.RelDB, waitMilliseconds string) *UniswapAssetSource { 160 var ( 161 restClient *ethclient.Client 162 err error 163 assetChannel = make(chan dia.Asset) 164 doneChannel = make(chan bool) 165 uas *UniswapAssetSource 166 ) 167 168 log.Infof("Init rest client for %s.", exchange.BlockChain.Name) 169 restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", restDial)) 170 if err != nil { 171 log.Fatal("init rest client: ", err) 172 } 173 var waitTime int 174 waitTimeString := utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_WAIT_TIME", waitMilliseconds) 175 waitTime, err = strconv.Atoi(waitTimeString) 176 if err != nil { 177 log.Error("could not parse wait time: ", err) 178 waitTime = 500 179 } 180 uas = &UniswapAssetSource{ 181 RestClient: restClient, 182 relDB: relDB, 183 assetChannel: assetChannel, 184 doneChannel: doneChannel, 185 exchange: exchange, 186 waitTime: waitTime, 187 } 188 return uas 189 } 190 191 func (uas *UniswapAssetSource) Asset() chan dia.Asset { 192 return uas.assetChannel 193 } 194 195 func (uas *UniswapAssetSource) Done() chan bool { 196 return uas.doneChannel 197 } 198 199 func (uas *UniswapAssetSource) getNumPairs() (int, error) { 200 var contract *uniswap.IUniswapV2FactoryCaller 201 contract, err := uniswap.NewIUniswapV2FactoryCaller(common.HexToAddress(exchangeFactoryContractAddress), uas.RestClient) 202 if err != nil { 203 log.Error(err) 204 } 205 numPairs, err := contract.AllPairsLength(&bind.CallOpts{}) 206 return int(numPairs.Int64()), err 207 } 208 209 func (uas *UniswapAssetSource) fetchAssets() { 210 211 numPairs, err := uas.getNumPairs() 212 if err != nil { 213 log.Fatal(err) 214 } 215 log.Info("Found ", numPairs, " pairs") 216 checkMap := make(map[string]struct{}) 217 218 _, index, err := uas.relDB.GetScraperIndex(uas.exchange.Name, dia.SCRAPER_TYPE_ASSETCOLLECTOR) 219 if err != nil { 220 log.Error("GetScraperIndex: ", err) 221 } 222 log.Info("Start at index ", index) 223 224 for index < int64(numPairs) { 225 log.Info("index: ", index) 226 time.Sleep(time.Duration(uas.waitTime) * time.Millisecond) 227 pair, err := uas.GetPairByID(index) 228 if err != nil { 229 log.Errorln("Error getting pair with ID ", index) 230 } 231 asset0 := pair.Token0 232 asset1 := pair.Token1 233 asset0.Blockchain = uas.exchange.BlockChain.Name 234 asset1.Blockchain = uas.exchange.BlockChain.Name 235 // Don't repeat sending already sent assets 236 if _, ok := checkMap[asset0.Address]; !ok { 237 if asset0.Symbol != "" { 238 checkMap[asset0.Address] = struct{}{} 239 uas.assetChannel <- asset0 240 } 241 } 242 if _, ok := checkMap[asset1.Address]; !ok { 243 if asset1.Symbol != "" { 244 checkMap[asset1.Address] = struct{}{} 245 uas.assetChannel <- asset1 246 } 247 } 248 index++ 249 } 250 err = uas.relDB.SetScraperIndex(uas.exchange.Name, dia.SCRAPER_TYPE_ASSETCOLLECTOR, dia.INDEX_TYPE_INDEX, index) 251 if err != nil { 252 log.Error("SetScraperIndex: ", err) 253 } 254 uas.doneChannel <- true 255 } 256 257 // GetPairByID returns the UniswapPair with the integer id @num 258 func (uas *UniswapAssetSource) GetPairByID(num int64) (UniswapPair, error) { 259 var contract *uniswap.IUniswapV2FactoryCaller 260 contract, err := uniswap.NewIUniswapV2FactoryCaller(common.HexToAddress(exchangeFactoryContractAddress), uas.RestClient) 261 if err != nil { 262 log.Error(err) 263 return UniswapPair{}, err 264 } 265 numToken := big.NewInt(num) 266 pairAddress, err := contract.AllPairs(&bind.CallOpts{}, numToken) 267 if err != nil { 268 log.Error(err) 269 return UniswapPair{}, err 270 } 271 272 pair, err := uas.GetPairByAddress(pairAddress) 273 if err != nil { 274 log.Error(err) 275 return UniswapPair{}, err 276 } 277 // log.Infof("Get pair with ID %v: %v", num, pair) 278 return pair, err 279 } 280 281 func (uas *UniswapAssetSource) GetPairByAddress(pairAddress common.Address) (pair UniswapPair, err error) { 282 connection := uas.RestClient 283 var pairContract *uniswap.IUniswapV2PairCaller 284 pairContract, err = uniswap.NewIUniswapV2PairCaller(pairAddress, connection) 285 if err != nil { 286 log.Error(err) 287 return UniswapPair{}, err 288 } 289 290 // Getting tokens from pair --------------------- 291 address0, _ := pairContract.Token0(&bind.CallOpts{}) 292 address1, _ := pairContract.Token1(&bind.CallOpts{}) 293 var token0Contract *uniswap.IERC20Caller 294 var token1Contract *uniswap.IERC20Caller 295 token0Contract, err = uniswap.NewIERC20Caller(address0, connection) 296 if err != nil { 297 log.Error(err) 298 } 299 token1Contract, err = uniswap.NewIERC20Caller(address1, connection) 300 if err != nil { 301 log.Error(err) 302 } 303 symbol0, err := token0Contract.Symbol(&bind.CallOpts{}) 304 if err != nil { 305 log.Error(err) 306 } 307 symbol1, err := token1Contract.Symbol(&bind.CallOpts{}) 308 if err != nil { 309 log.Error(err) 310 } 311 decimals0, err := token0Contract.Decimals(&bind.CallOpts{}) 312 if err != nil { 313 log.Error(err) 314 } 315 decimals1, err := token1Contract.Decimals(&bind.CallOpts{}) 316 if err != nil { 317 log.Error(err) 318 } 319 320 name0, err := uas.GetName(address0) 321 if err != nil { 322 log.Error(err) 323 return UniswapPair{}, err 324 } 325 name1, err := uas.GetName(address1) 326 if err != nil { 327 log.Error(err) 328 return UniswapPair{}, err 329 } 330 token0 := dia.Asset{ 331 Address: address0.Hex(), 332 Symbol: symbol0, 333 Name: name0, 334 Decimals: decimals0, 335 } 336 token1 := dia.Asset{ 337 Address: address1.Hex(), 338 Symbol: symbol1, 339 Name: name1, 340 Decimals: decimals1, 341 } 342 pair.Token0 = token0 343 pair.Token1 = token1 344 345 return pair, nil 346 } 347 348 // GetDecimals returns the decimals of the token with address @tokenAddress 349 func (uas *UniswapAssetSource) GetDecimals(tokenAddress common.Address) (decimals uint8, err error) { 350 351 var contract *uniswap.IERC20Caller 352 contract, err = uniswap.NewIERC20Caller(tokenAddress, uas.RestClient) 353 if err != nil { 354 log.Error(err) 355 return 356 } 357 decimals, err = contract.Decimals(&bind.CallOpts{}) 358 359 return 360 } 361 362 func (uas *UniswapAssetSource) GetName(tokenAddress common.Address) (name string, err error) { 363 364 var contract *uniswap.IERC20Caller 365 contract, err = uniswap.NewIERC20Caller(tokenAddress, uas.RestClient) 366 if err != nil { 367 log.Error(err) 368 return 369 } 370 name, err = contract.Name(&bind.CallOpts{}) 371 372 return 373 }