github.com/pdaian/flashboys2@v0.0.0-20190718175736-b101c35361f0/exchanges.py (about) 1 import json 2 from persistence import persist_to_file 3 import web3 4 from web3 import Web3 5 from eth_abi import decode_abi 6 7 ERC20_ABI = json.loads('[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"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"},{"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"}]') # noqa: 501 8 UNISWAP_ABI = json.loads('[{"name": "TokenPurchase", "inputs": [{"type": "address", "name": "buyer", "indexed": true}, {"type": "uint256", "name": "eth_sold", "indexed": true}, {"type": "uint256", "name": "tokens_bought", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "EthPurchase", "inputs": [{"type": "address", "name": "buyer", "indexed": true}, {"type": "uint256", "name": "tokens_sold", "indexed": true}, {"type": "uint256", "name": "eth_bought", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "AddLiquidity", "inputs": [{"type": "address", "name": "provider", "indexed": true}, {"type": "uint256", "name": "eth_amount", "indexed": true}, {"type": "uint256", "name": "token_amount", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "RemoveLiquidity", "inputs": [{"type": "address", "name": "provider", "indexed": true}, {"type": "uint256", "name": "eth_amount", "indexed": true}, {"type": "uint256", "name": "token_amount", "indexed": true}], "anonymous": false, "type": "event"}, {"name": "Transfer", "inputs": [{"type": "address", "name": "_from", "indexed": true}, {"type": "address", "name": "_to", "indexed": true}, {"type": "uint256", "name": "_value", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "Approval", "inputs": [{"type": "address", "name": "_owner", "indexed": true}, {"type": "address", "name": "_spender", "indexed": true}, {"type": "uint256", "name": "_value", "indexed": false}], "anonymous": false, "type": "event"}, {"name": "setup", "outputs": [], "inputs": [{"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 175875}, {"name": "addLiquidity", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_liquidity"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 82616}, {"name": "removeLiquidity", "outputs": [{"type": "uint256", "name": "out"}, {"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "amount"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 116814}, {"name": "__default__", "outputs": [], "inputs": [], "constant": false, "payable": true, "type": "function"}, {"name": "ethToTokenSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 12757}, {"name": "ethToTokenTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "min_tokens"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": true, "type": "function", "gas": 12965}, {"name": "ethToTokenSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": true, "type": "function", "gas": 50463}, {"name": "ethToTokenTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": true, "type": "function", "gas": 50671}, {"name": "tokenToEthSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 47503}, {"name": "tokenToEthTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_eth"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": false, "type": "function", "gas": 47712}, {"name": "tokenToEthSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}], "constant": false, "payable": false, "type": "function", "gas": 50175}, {"name": "tokenToEthTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}, {"type": "uint256", "name": "max_tokens"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}], "constant": false, "payable": false, "type": "function", "gas": 50384}, {"name": "tokenToTokenSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 51007}, {"name": "tokenToTokenTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 51098}, {"name": "tokenToTokenSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 54928}, {"name": "tokenToTokenTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "token_addr"}], "constant": false, "payable": false, "type": "function", "gas": 55019}, {"name": "tokenToExchangeSwapInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 49342}, {"name": "tokenToExchangeTransferInput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}, {"type": "uint256", "name": "min_tokens_bought"}, {"type": "uint256", "name": "min_eth_bought"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 49532}, {"name": "tokenToExchangeSwapOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 53233}, {"name": "tokenToExchangeTransferOutput", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}, {"type": "uint256", "name": "max_tokens_sold"}, {"type": "uint256", "name": "max_eth_sold"}, {"type": "uint256", "name": "deadline"}, {"type": "address", "name": "recipient"}, {"type": "address", "name": "exchange_addr"}], "constant": false, "payable": false, "type": "function", "gas": 53423}, {"name": "getEthToTokenInputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_sold"}], "constant": true, "payable": false, "type": "function", "gas": 5542}, {"name": "getEthToTokenOutputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_bought"}], "constant": true, "payable": false, "type": "function", "gas": 6872}, {"name": "getTokenToEthInputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "tokens_sold"}], "constant": true, "payable": false, "type": "function", "gas": 5637}, {"name": "getTokenToEthOutputPrice", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "uint256", "name": "eth_bought"}], "constant": true, "payable": false, "type": "function", "gas": 6897}, {"name": "tokenAddress", "outputs": [{"type": "address", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1413}, {"name": "factoryAddress", "outputs": [{"type": "address", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1443}, {"name": "balanceOf", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "address", "name": "_owner"}], "constant": true, "payable": false, "type": "function", "gas": 1645}, {"name": "transfer", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_to"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 75034}, {"name": "transferFrom", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_from"}, {"type": "address", "name": "_to"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 110907}, {"name": "approve", "outputs": [{"type": "bool", "name": "out"}], "inputs": [{"type": "address", "name": "_spender"}, {"type": "uint256", "name": "_value"}], "constant": false, "payable": false, "type": "function", "gas": 38769}, {"name": "allowance", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [{"type": "address", "name": "_owner"}, {"type": "address", "name": "_spender"}], "constant": true, "payable": false, "type": "function", "gas": 1925}, {"name": "name", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1623}, {"name": "symbol", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1653}, {"name": "decimals", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1683}, {"name": "totalSupply", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1713}]') 9 10 my_provider = Web3.HTTPProvider('https://mainnet.infura.io/v3/c534d76d934f40498f6d6113a46c6ab3') 11 w3 = Web3(my_provider) 12 13 14 """1 IDEX 57849 55.5056% 0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208 15 2 DEx.top 11628 11.1570% 0x7600977eb9effa627d6bd0da2e5be35e11566341 16 3 Ether Delta 6596 6.3288% 0x8d12a197cb00d4747a1fe03395095ce2a5cc6819 17 4 Bancor Network 6569 6.3029% ??? 18 5 DDEX 5146 4.9375% 0x12459c951127e0c374ff9105dda097662a027093 19 6 Token Store 3750 3.5981% 0x1ce7ae555139c5ef5a57cc8d814a867ee6ee33d8 20 7 Star Bit 3448 3.3083% 0x12459c951127e0c374ff9105dda097662a027093 21 8 Kyber Network 2550 2.4467% ????? 22 9 Joyso 2205 2.1157% 0x04f062809b244e37e7fdc21d9409469c989c2342 23 10 Oasis Dex 1865 1.7894% 0x12459c951127e0c374ff9105dda097662a027093 24 11 Radar Relay 1303 1.2502% 0x12459c951127e0c374ff9105dda097662a027093 25 12 Paradex 820 0.7868% 0x12459c951127e0c374ff9105dda097662a027093 26 13 Airswap 243 0.2332% 0x8fd3121013a07c57f0d69646e86e7a4880b467b7 27 14 TokenJar 106 0.1017% 0x12459c951127e0c374ff9105dda097662a027093 28 15 The Ocean 91 0.0873% 0x12459c951127e0c374ff9105dda097662a027093 29 16 Erc dEX 25 0.0240% 0x12459c951127e0c374ff9105dda097662a027093 30 17 Enclaves 22 0.0211% 0xed06d46ffb309128c4458a270c99c824dc127f5d 31 18 Shark Relay 6 0.0058% 0x12459c951127e0c374ff9105dda097662a027093 32 19 Bamboo Relay 0 0.0000% 33 20 IDT Exchange 0 0.0000% 34 21 Tokenlon 0 0.0000% 35 36 Source: dexwatch Thus Sep 20 3:48PM EST 37 """ 38 39 40 dex_list = ["0x2a0c0dbecc7e4d658f48e01e3fa353f44050c208", # IDEX 41 "0x7600977eb9effa627d6bd0da2e5be35e11566341", # DEx.top 42 "0x8d12a197cb00d4747a1fe03395095ce2a5cc6819", # Etherdelta (done) 43 "0x12459c951127e0c374ff9105dda097662a027093", # 0x v1 (done) 44 "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", # 0x v2 (done) 45 "0x1ce7ae555139c5ef5a57cc8d814a867ee6ee33d8", # Token Store (done) 46 "0x04f062809b244e37e7fdc21d9409469c989c2342", # Joyso 47 "0x8fd3121013a07c57f0d69646e86e7a4880b467b7", # Airswap 48 "0xed06d46ffb309128c4458a270c99c824dc127f5d", # Enclaves 49 ] 50 51 52 bancor_relayers = open('data/bancor_relayers').read().strip().splitlines() 53 kyber_relayers = open('data/kyber_relayers').read().strip().splitlines() 54 uniswap_relayers = open('data/uniswap_relayers').read().strip().splitlines() 55 56 dex_list = dex_list + bancor_relayers + kyber_relayers + uniswap_relayers 57 58 def parse_address(raw_hex): 59 """ Extract address from lowest hex bits, ignoring junk. """ 60 return raw_hex[-40:] 61 62 def parse_amount(raw_hex): 63 return int(raw_hex, 16) 64 65 @persist_to_file('uniswap.dat') 66 def get_uniswap_token(address): 67 token_addr = address 68 erc20 = w3.eth.contract(address=Web3.toChecksumAddress('0x' + address), abi=UNISWAP_ABI) 69 try: 70 token_addr = erc20.functions.tokenAddress().call() 71 except web3.exceptions.BadFunctionCallOutput: # todo handle chainsync errors? 72 pass 73 return token_addr.lower().replace("0x", "") 74 75 @persist_to_file('decimals.dat') 76 def get_decimals_for(address): 77 if int(address, 16) == 0 or int(address, 16) == 1364068194842176056990105843868530818345537040110: 78 return 18 79 erc20 = w3.eth.contract(address=Web3.toChecksumAddress('0x' + address), abi=ERC20_ABI) 80 try: 81 decimals = int(erc20.functions.decimals().call()) 82 except web3.exceptions.BadFunctionCallOutput: # todo handle chainsync errors? 83 return 0 84 return decimals 85 86 @persist_to_file('labels.dat') 87 def get_node_label_for(address): 88 if int(address, 16) == 0 or int(address, 16) == 1364068194842176056990105843868530818345537040110 or address.lower() == "c0829421c1d260bd3cb3e0f06cfe2d52db2ce315" or address.lower() == "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" or address.lower() == "2956356cd2a2bf3202f771f50d3d14a367b48070": 89 return ("ETH", "ETH") 90 erc20 = w3.eth.contract(address=Web3.toChecksumAddress('0x' + address), abi=ERC20_ABI) 91 name = "Unknown" 92 symbol = "Unknown" 93 try: 94 name = erc20.functions.name().call() 95 except OverflowError: 96 pass 97 except web3.exceptions.BadFunctionCallOutput: 98 pass 99 try: 100 symbol = erc20.functions.symbol().call() 101 except OverflowError: 102 pass 103 except web3.exceptions.BadFunctionCallOutput: 104 pass 105 return (symbol, "%s (%s)\n0x%s" % (name, symbol, address)) 106 107 def parse_bancor(topics, data, address): 108 tokenget_addr = parse_address(topics[1]) 109 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 110 amountget = (parse_amount(data[0:64]) / (10 ** get_decimals_for(tokenget_addr))) 111 tokengive_addr = parse_address(topics[2]) 112 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 113 amountgive = (parse_amount(data[64:128]) / (10 ** get_decimals_for(tokengive_addr))) 114 assert(len(data) == 192) 115 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 116 117 def parse_etherdelta_clone(topics, data, address, data_length): 118 tokenget_addr = parse_address(data[0:64]) 119 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 120 amountget = (parse_amount(data[64:128]) / (10 ** get_decimals_for(tokenget_addr))) 121 tokengive_addr = parse_address(data[128:192]) 122 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 123 amountgive = (parse_amount(data[192:256]) / (10 ** get_decimals_for(tokengive_addr))) 124 assert(len(data) == data_length) 125 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 126 127 parse_etherdelta = lambda topics, data, address : parse_etherdelta_clone(topics, data, address, 384) 128 parse_tokenstore = lambda topics, data, address : parse_etherdelta_clone(topics, data, address, 448) 129 130 def parse_0x(topics, data, address): 131 tokenget_addr = parse_address(data[128:192]) 132 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 133 amountget = (parse_amount(data[256:320]) / (10 ** get_decimals_for(tokenget_addr))) 134 tokengive_addr = parse_address(data[64:128]) 135 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 136 amountgive = (parse_amount(data[192:256]) / (10 ** get_decimals_for(tokengive_addr))) 137 assert(len(data) == 512) 138 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 139 140 def parse_0x_v2(topics, data, address): 141 abi_data = decode_abi(['address', 'address', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes', 'bytes'], bytes(Web3.toBytes(hexstr=data))) 142 tokenget_addr = parse_address(Web3.toHex(abi_data[-1])[2:]) 143 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 144 amountget = (parse_amount(data[192:256]) / (10 ** get_decimals_for(tokenget_addr))) 145 tokengive_addr = parse_address(Web3.toHex(abi_data[-2])[2:]) 146 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 147 amountgive = (parse_amount(data[128:192]) / (10 ** get_decimals_for(tokengive_addr))) 148 assert(len(data) >= 896) 149 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 150 151 def parse_kyber(topics, data, address): 152 abi_data = decode_abi(['address', 'address', 'uint256', 'uint256', 'address', 'uint256', 'address', 'address', 'bytes'], bytes(Web3.toBytes(hexstr=data))) 153 tokenget_addr = parse_address(abi_data[0]) 154 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 155 amountget = (abi_data[2] / (10 ** get_decimals_for(tokenget_addr))) 156 tokengive_addr = parse_address(abi_data[1]) 157 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 158 amountgive = (abi_data[3] / (10 ** get_decimals_for(tokengive_addr))) 159 assert(len(data) >= 512) 160 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 161 162 def parse_uniswap_tokenpurchase(topics, data, address): 163 abi_data = decode_abi(['uint256', 'address', 'uint256', 'uint256'], Web3.toBytes(hexstr="".join([x.replace("0x", "") for x in topics]))) 164 tokenget_addr = get_uniswap_token(address[2:]) 165 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 166 amountget = (abi_data[-1] / (10 ** get_decimals_for(tokenget_addr))) 167 tokengive_addr = "0"*40 # (eth given by definition) 168 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 169 amountgive = (abi_data[-2] / (10 ** get_decimals_for(tokengive_addr))) 170 assert(len(topics) == 4) 171 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 172 173 def parse_uniswap_ethpurchase(topics, data, address): 174 abi_data = decode_abi(['uint256', 'address', 'uint256', 'uint256'], Web3.toBytes(hexstr="".join([x.replace("0x", "") for x in topics]))) 175 tokenget_addr = "0"*40 # (eth gotten by definition) 176 tokenget,tokenget_label = get_node_label_for(tokenget_addr) 177 amountget = (abi_data[-1] / (10 ** get_decimals_for(tokenget_addr))) 178 tokengive_addr = get_uniswap_token(address[2:]) 179 tokengive,tokengive_label = get_node_label_for(tokengive_addr) 180 amountgive = (abi_data[-2] / (10 ** get_decimals_for(tokengive_addr))) 181 assert(len(topics) == 4) 182 return (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) 183 184 185 def get_trade_data_from_log_item(topics, data, address): 186 exchange = None 187 parser = None 188 if address == '0x8d12a197cb00d4747a1fe03395095ce2a5cc6819': # etherdelta 189 # TODO handle clones 190 if topics[0] == '0x6effdda786735d5033bfad5f53e5131abcced9e52be6c507b62d639685fbed6d': # trade log event 191 exchange = "Etherdelta" 192 parser = parse_etherdelta 193 elif address == '0x1ce7ae555139c5ef5a57cc8d814a867ee6ee33d8': # Tokenstore 194 if topics[0] == '0x3314c351c2a2a45771640a1442b843167a4da29bd543612311c031bbfb4ffa98': 195 exchange = "Tokenstore" 196 parser = parse_tokenstore 197 elif address == '0x12459c951127e0c374ff9105dda097662a027093': # 0x v1 198 if topics[0] == '0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3': 199 exchange = "0x v1" 200 parser = parse_0x 201 elif address == '0x4f833a24e1f95d70f028921e27040ca56e09ab0b': # 0x v2 202 if topics[0] == '0x0bcc4c97732e47d9946f229edb95f5b6323f601300e4690de719993f3c371129': 203 exchange = "0x v2" 204 parser = parse_0x_v2 205 elif address in bancor_relayers: 206 if topics[0] == '0x276856b36cbc45526a0ba64f44611557a2a8b68662c5388e9fe6d72e86e1c8cb': 207 exchange = "Bancor" 208 parser = parse_bancor 209 elif address in kyber_relayers: 210 if topics[0] == '0xd30ca399cb43507ecec6a629a35cf45eb98cda550c27696dcb0d8c4a3873ce6c': 211 exchange = "Kyber" 212 parser = parse_kyber 213 elif address in uniswap_relayers: 214 if topics[0] == '0x7f4091b46c33e918a0f3aa42307641d17bb67029427a5369e54b353984238705': 215 exchange = "Uniswap" 216 parser = parse_uniswap_ethpurchase 217 if topics[0] == '0xcd60aa75dea3072fbc07ae6d7d856b5dc5f4eee88854f5b4abf7b680ef8bc50f' and len(topics) == 4: # (ZRXcoin has same event; eg https://etherscan.io/tx/0x3d774851984b665b6db16d8bbf7a138520c76db923599fc8929b29edd384db7b#eventlog) 218 exchange = "Uniswap" 219 parser = parse_uniswap_tokenpurchase 220 else: 221 # parsing failed 222 return None 223 224 if not parser: 225 # no logs to parse 226 return [] 227 228 # 1 log generated; return it 229 (tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive) = parser(topics, data, address) 230 return [(tokenget_addr, tokenget_label, tokenget, amountget, tokengive_addr, tokengive_label, tokengive, amountgive, exchange)]