github.com/diadata-org/diadata@v1.4.593/pkg/dia/service/assetservice/source/platypus.go (about) 1 package source 2 3 import ( 4 "math/big" 5 "strconv" 6 "strings" 7 8 "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/platypusfinance" 9 platypusAssetABI "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/platypusfinance/asset" 10 platypusPoolABI "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/platypusfinance/pool" 11 platypusTokenABI "github.com/diadata-org/diadata/pkg/dia/scraper/exchange-scrapers/platypusfinance/token" 12 "github.com/diadata-org/diadata/pkg/utils" 13 14 "github.com/diadata-org/diadata/pkg/dia" 15 "github.com/ethereum/go-ethereum/accounts/abi/bind" 16 "github.com/ethereum/go-ethereum/common" 17 "github.com/ethereum/go-ethereum/ethclient" 18 ) 19 20 const ( 21 platypusRestDialAvalanche = "https://api.avax.network/ext/bc/C/rpc" 22 platypusMasterRegV3Addr = "0x7125B4211357d7C3a90F796c956c12c681146EbB" 23 platypusMasterRegV2Addr = "0x68c5f4374228BEEdFa078e77b5ed93C28a2f713E" 24 platypusMasterRegV1Addr = "0xB0523f9F473812FB195Ee49BC7d2ab9873a98044" 25 waitMilliseconds = "" 26 ) 27 28 type platypusRegistry struct { 29 Address common.Address 30 Version int 31 } 32 33 type PlatypusCoin struct { 34 Symbol string 35 Decimals uint8 36 Address string 37 Name string 38 } 39 40 // The scraper object for Platypus Finance. 41 type PlatypusAssetSource struct { 42 RestClient *ethclient.Client 43 assetChannel chan dia.Asset 44 doneChannel chan bool 45 blockchain string 46 registries []platypusRegistry 47 waitTime int 48 } 49 50 // Returns a new platypus asset scraper. 51 func NewPlatypusScraper(exchange dia.Exchange) *PlatypusAssetSource { 52 53 var ( 54 restClient *ethclient.Client 55 err error 56 assetChannel = make(chan dia.Asset) 57 doneChannel = make(chan bool) 58 pas *PlatypusAssetSource 59 ) 60 61 registries := []platypusRegistry{ 62 {Version: 3, Address: common.HexToAddress(platypusMasterRegV3Addr)}, 63 {Version: 2, Address: common.HexToAddress(platypusMasterRegV2Addr)}, 64 {Version: 1, Address: common.HexToAddress(platypusMasterRegV1Addr)}, 65 } 66 67 log.Infof("Init rest client for %s.", exchange.BlockChain.Name) 68 restClient, err = ethclient.Dial(utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_URI_REST", platypusRestDialAvalanche)) 69 if err != nil { 70 log.Fatal("init rest client: ", err) 71 } 72 73 var waitTime int 74 waitTimeString := utils.Getenv(strings.ToUpper(exchange.BlockChain.Name)+"_WAIT_TIME", waitMilliseconds) 75 waitTime, err = strconv.Atoi(waitTimeString) 76 if err != nil { 77 log.Error("could not parse wait time: ", err) 78 waitTime = 500 79 } 80 pas = &PlatypusAssetSource{ 81 RestClient: restClient, 82 assetChannel: assetChannel, 83 doneChannel: doneChannel, 84 blockchain: exchange.BlockChain.Name, 85 waitTime: waitTime, 86 registries: registries, 87 } 88 go func() { 89 pas.fetchAssets() 90 }() 91 92 return pas 93 } 94 95 func (pas *PlatypusAssetSource) fetchAssets() { 96 for _, registry := range pas.registries { 97 err := pas.fetchPools(registry) 98 if err != nil { 99 log.Error("loadPoolsAndCoins: ", err) 100 } 101 } 102 pas.doneChannel <- true 103 } 104 105 // Load pools and coins metadata from master registry 106 func (scraper *PlatypusAssetSource) fetchPools(registry platypusRegistry) error { 107 log.Infof("loading master contract %s version %d and querying registry", registry.Address.Hex(), registry.Version) 108 contractMaster, err := platypusfinance.NewBaseMasterPlatypusCaller(registry.Address, scraper.RestClient) 109 if err != nil { 110 log.Error("NewBaseMasterPlatypusCaller: ", err) 111 return err 112 } 113 114 poolCount, err := contractMaster.PoolLength(&bind.CallOpts{}) 115 if err != nil { 116 log.Error("PoolLength: ", err) 117 return err 118 } 119 120 for i := 0; i < int(poolCount.Int64()); i++ { 121 asset, errPoolInfo := contractMaster.PoolInfo(&bind.CallOpts{}, big.NewInt(int64(i))) 122 if errPoolInfo != nil { 123 log.Error("PoolInfo: ", errPoolInfo) 124 return err 125 } 126 127 errPoolData := scraper.loadPoolData(asset.LpToken.Hex()) 128 if errPoolData != nil { 129 log.Errorf("loadPoolData error at asset %s: %s", asset.LpToken.Hex(), errPoolData) 130 return errPoolData 131 } 132 133 } 134 135 return err 136 } 137 138 func (scraper *PlatypusAssetSource) loadPoolData(poolAddress string) (err error) { 139 140 contractAsset, err := platypusAssetABI.NewAssetCaller(common.HexToAddress(poolAddress), scraper.RestClient) 141 if err != nil { 142 log.Error("NewAssetCaller: ", err) 143 } 144 145 poolContract, err := contractAsset.Pool(&bind.CallOpts{}) 146 if err != nil { 147 log.Error("Pool: ", err) 148 } 149 150 poolCaller, err := platypusPoolABI.NewPoolCaller(poolContract, scraper.RestClient) 151 if err != nil { 152 log.Error("NewPoolCaller: ", err) 153 } 154 155 poolTokenAddresses, errGetTokens := poolCaller.GetTokenAddresses(&bind.CallOpts{}) 156 if errGetTokens != nil { 157 symbol, err := contractAsset.Symbol(&bind.CallOpts{}) 158 if err != nil { 159 log.Error("contractAsset.Symbol: ", err) 160 } 161 log.Warnf("error calling GetTokenAddresses for %s %s asset: %s", symbol, poolAddress, errGetTokens) 162 } 163 164 for _, c := range poolTokenAddresses { 165 var ( 166 symbol string 167 decimalsBig *big.Int 168 decimals uint8 169 name string 170 ) 171 172 if c == common.HexToAddress("0x0000000000000000000000000000000000000000") { 173 continue 174 } else { 175 contractToken, err := platypusTokenABI.NewTokenCaller(c, scraper.RestClient) 176 if err != nil { 177 log.Error("NewTokenCaller: ", err) 178 continue 179 } 180 181 symbol, err = contractToken.Symbol(&bind.CallOpts{}) 182 if err != nil { 183 log.Error("Symbol: ", err, c.Hex()) 184 continue 185 } 186 187 decimalsBig, err = contractToken.Decimals(&bind.CallOpts{}) 188 if err != nil { 189 log.Error("Decimals: ", err) 190 continue 191 } 192 decimals = uint8(decimalsBig.Uint64()) 193 194 name, err = contractToken.Name(&bind.CallOpts{}) 195 if err != nil { 196 log.Error("Name: ", err) 197 continue 198 } 199 200 } 201 202 poolAsset := dia.Asset{ 203 Address: c.Hex(), 204 Blockchain: scraper.blockchain, 205 Decimals: decimals, 206 Symbol: symbol, 207 Name: name, 208 } 209 210 scraper.Asset() <- poolAsset 211 212 } 213 return 214 } 215 216 func (pas *PlatypusAssetSource) Asset() chan dia.Asset { 217 return pas.assetChannel 218 } 219 220 func (pas *PlatypusAssetSource) Done() chan bool { 221 return pas.doneChannel 222 }