github.com/diadata-org/diadata@v1.4.593/pkg/dia/helpers/ethhelper/tokenInfo.go (about) 1 package ethhelper 2 3 import ( 4 "encoding/json" 5 "errors" 6 "io/ioutil" 7 "math/big" 8 "os" 9 "os/user" 10 "strings" 11 12 "github.com/diadata-org/diadata/pkg/dia" 13 "github.com/ethereum/go-ethereum/accounts/abi" 14 "github.com/ethereum/go-ethereum/accounts/abi/bind" 15 "github.com/ethereum/go-ethereum/common" 16 "github.com/ethereum/go-ethereum/ethclient" 17 log "github.com/sirupsen/logrus" 18 ) 19 20 const tokenABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"mintingFinished\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"unpause\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"finishMinting\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"pause\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\"},{\"name\":\"_releaseTime\",\"type\":\"uint256\"}],\"name\":\"mintTimelocked\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"MintFinished\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Pause\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Unpause\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"}]" //nolint:gosec 21 22 // const tokenABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\": \"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\": \"_owner\",\"type\":\"address\"}],\"name\": \"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"}]" 23 24 // TokenCaller is an auto generated read-only Go binding around an Ethereum contract. 25 type TokenCaller struct { 26 Contract *bind.BoundContract // Generic contract wrapper for the low level calls 27 } 28 29 // NewETHClient returns an ethclient, using either our node for production or infura for testing 30 func NewETHClient() (*ethclient.Client, error) { 31 executionMode := os.Getenv("EXEC_MODE") 32 var connection *ethclient.Client 33 var err error 34 if executionMode == "production" { 35 connection, err = ethclient.Dial("http://159.69.120.42:8545/") 36 if err != nil { 37 log.Error("Error connecting Eth Client") 38 } 39 } else { 40 connection, err = ethclient.Dial("https://mainnet.infura.io/v3/806b0419b2d041869fc83727e0043236") 41 if err != nil { 42 log.Error("Error connecting Eth Client") 43 } 44 } 45 return connection, err 46 } 47 48 // NewTokenCaller creates a new read-only instance of token, bound to a specific deployed contract. 49 func NewTokenCaller(address common.Address, caller bind.ContractCaller) (*TokenCaller, error) { 50 contract, err := bindToken(address, caller, nil) 51 if err != nil { 52 return nil, err 53 } 54 return &TokenCaller{Contract: contract}, nil 55 } 56 57 // bindToken binds a generic wrapper to an already deployed contract. 58 func bindToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) { 59 parsed, err := abi.JSON(strings.NewReader(tokenABI)) 60 if err != nil { 61 return nil, err 62 } 63 return bind.NewBoundContract(address, parsed, caller, transactor, nil), nil 64 } 65 66 func GetBalanceOf(tokenAddress common.Address, walletAddress common.Address, client *ethclient.Client) (*big.Int, error) { 67 var balance []interface{} 68 tokenCaller, err := NewTokenCaller(tokenAddress, client) 69 if err != nil { 70 return big.NewInt(0), err 71 } 72 err = tokenCaller.Contract.Call(&bind.CallOpts{}, &balance, "balanceOf", walletAddress) 73 if err != nil { 74 return big.NewInt(0), err 75 } 76 if len(balance) > 0 { 77 return balance[0].(*big.Int), nil 78 } 79 return big.NewInt(0), errors.New("Not enough data.") 80 } 81 82 // ETHAddressToAsset takes an Ethereum address and returns the underlying 83 // token as a dia.Asset. 84 func ETHAddressToAsset(address common.Address, client *ethclient.Client, blockchainName string) (dia.Asset, error) { 85 var asset dia.Asset 86 tc, err := NewTokenCaller(address, client) 87 if err != nil { 88 log.Error("error: ", err) 89 } 90 91 asset.Address = address.Hex() 92 93 var symbol []interface{} 94 err = tc.Contract.Call(&bind.CallOpts{}, &symbol, "symbol") 95 if err != nil { 96 return dia.Asset{}, err 97 } 98 asset.Symbol = symbol[0].(string) 99 100 var name []interface{} 101 err = tc.Contract.Call(&bind.CallOpts{}, &name, "name") 102 if err != nil { 103 return dia.Asset{}, err 104 } 105 asset.Name = name[0].(string) 106 107 var decimals []interface{} 108 err = tc.Contract.Call(&bind.CallOpts{}, &decimals, "decimals") 109 if err != nil { 110 return dia.Asset{}, err 111 } 112 aux := decimals[0].(*big.Int) 113 asset.Decimals = uint8(aux.Int64()) 114 asset.Blockchain = blockchainName 115 return asset, err 116 } 117 118 func ConfigFilePath(filename string) string { 119 usr, _ := user.Current() 120 dir := usr.HomeDir 121 if dir == "/root" || dir == "/home" { 122 return "/config/token_supply/" + filename + ".json" //hack for docker... 123 } 124 if dir == "/home/travis" { 125 return "../config/token_supply/" + filename + ".json" //hack for travis 126 } 127 return os.Getenv("GOPATH") + "/src/github.com/diadata-org/diadata/config/token_supply/" + filename + ".json" 128 } 129 130 // GetAddressesFromFile fetches token addresses from a config file available here: 131 // https://etherscan.io/exportData?type=open-source-contract-codes 132 func GetAddressesFromFile(filename string) (addresses []string, err error) { 133 jsonFile, err := os.Open(ConfigFilePath(filename)) 134 if err != nil { 135 log.Errorln("Error opening file", err) 136 return 137 } 138 defer func() { 139 cerr := jsonFile.Close() 140 if err == nil { 141 err = cerr 142 } 143 }() 144 145 byteData, err := ioutil.ReadAll(jsonFile) 146 if err != nil { 147 log.Error(err) 148 return 149 } 150 // For now we only return token address. Name can be retrieved through contract. 151 type token struct { 152 Address string 153 Name string 154 } 155 type TokenInfo struct { 156 Tokens []token `json:"Tokens"` 157 } 158 var tokeninfo TokenInfo 159 err = json.Unmarshal(byteData, &tokeninfo) 160 if err != nil { 161 return 162 } 163 for _, token := range tokeninfo.Tokens { 164 addresses = append(addresses, token.Address) 165 } 166 return 167 }