def get_contract_params(web3, contract, events): output = {} for event in events: abi = getattr(contract.events, event)._get_event_abi() topic = construct_event_topic_set(abi, web3.codec) output[event] = (abi, topic[0]) return output
async def process_storage_history(start_height=0): web3 = get_web3() contract = get_storage_contract(web3) abi = contract.events.NewHash._get_event_abi() topic = construct_event_topic_set(abi, web3.codec) start = max(start_height, settings.ethereum_min_height) last_height = start end_height = web3.eth.blockNumber count = 0 async for i in get_logs(web3, contract, start, topics=topic): count += 1 evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] LOGGER.debug(f"{height}: {evt_data}") context = { "source_chain": 'ETH', "source_contract": settings.ethereum_event_contract, "tx_hash": evt_data.transactionHash.hex(), "height": evt_data.blockNumber, "submitter": args['hashSubmitter'] } yield (context, args["hash"]) LOGGER.info(f"Scanned {count} events")
def get_netting_channel_closed_events( proxy_manager: ProxyManager, token_network_address: TokenNetworkAddress, netting_channel_identifier: ChannelID, contract_manager: ContractManager, from_block: BlockIdentifier = GENESIS_BLOCK_NUMBER, to_block: BlockIdentifier = BLOCK_ID_LATEST, ) -> List[Dict]: closed_event_abi = contract_manager.get_event_abi(CONTRACT_TOKEN_NETWORK, ChannelEvent.CLOSED) topic_set = construct_event_topic_set( event_abi=closed_event_abi, abi_codec=proxy_manager.client.web3.codec, arguments={"channel_identifier": netting_channel_identifier}, ) return get_contract_events( proxy_manager=proxy_manager, abi=contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), contract_address=Address(token_network_address), topics=topic_set, # type: ignore from_block=from_block, to_block=to_block, )
def construct_event_filter_params( event_abi: ABIEvent, abi_codec: ABICodec, contract_address: Optional[ChecksumAddress] = None, argument_filters: Optional[Dict[str, Any]] = None, topics: Optional[Sequence[HexStr]] = None, fromBlock: Optional[BlockIdentifier] = None, toBlock: Optional[BlockIdentifier] = None, address: Optional[ChecksumAddress] = None ) -> Tuple[List[List[Optional[HexStr]]], FilterParams]: filter_params: FilterParams = {} topic_set: Sequence[HexStr] = construct_event_topic_set( event_abi, abi_codec, argument_filters) if topics is not None: if len(topic_set) > 1: raise TypeError( "Merging the topics argument with topics generated " "from argument_filters is not supported.") topic_set = topics if len(topic_set) == 1 and is_list_like(topic_set[0]): # type ignored b/c list-like check on line 88 filter_params['topics'] = topic_set[0] # type: ignore else: filter_params['topics'] = topic_set if address and contract_address: if is_list_like(address): filter_params['address'] = [address] + [contract_address] elif is_string(address): filter_params['address'] = [address, contract_address] else: raise ValueError( "Unsupported type for `address` parameter: {0}".format( type(address))) elif address: filter_params['address'] = address elif contract_address: filter_params['address'] = contract_address if 'address' not in filter_params: pass elif is_list_like(filter_params['address']): for addr in filter_params['address']: validate_address(addr) else: validate_address(filter_params['address']) if fromBlock is not None: filter_params['fromBlock'] = fromBlock if toBlock is not None: filter_params['toBlock'] = toBlock data_filters_set = construct_event_data_set(event_abi, abi_codec, argument_filters) return data_filters_set, filter_params
def load_from_ens(self): # track older registries to pull experiments resolver = contract('0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41') topics = construct_event_topic_set( filter_by_name('AddressChanged', resolver.abi)[0], web3.codec, {'node': web3.ens.namehash('v2.registry.ychad.eth')}, ) events = decode_logs(get_logs_asap(str(resolver), topics)) logger.info('loaded %d registry versions', len(events)) return [Contract(event['newAddress']) for event in events]
def process_pool_history(pool, per_block, start_height, end_height): abi = pool['contract'].events.Transfer._get_event_abi() web3 = get_web3() topic = construct_event_topic_set(abi, web3.codec) weights = dict() balances = dict() reward_start = max(pool['start_height'], config['reward_start'], start_height) last_height = reward_start end_height = min(web3.eth.blockNumber, end_height) def update_weights(since, current): for addr, value in balances.items(): if value > 0: weights[addr] = weights.get(addr, 0) + (value * (current - since)) for i in get_logs(web3, pool['contract'], pool['start_height'], topics=topic): evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] if height > end_height: break if height > reward_start: update_weights(last_height, height) # to handle gaps in our staking contract's reward distribution, # a user's balance accumulates whenever they stake to the contract if args['src'] == '0xFe82ea0Ef14DfdAcd5dB1D49F563497A1a751bA1': balances[args.dst] = balances.get(args.dst, 0) - args.amt elif args.dst == '0xFe82ea0Ef14DfdAcd5dB1D49F563497A1a751bA1': balances[args['src']] = balances.get(args['src'], 0) + args.amt last_height = height height = end_height update_weights(last_height, height) total_weight = sum(weights.values()) total_balance = sum([b for b in balances.values() if b > 0]) weights = {a: w / total_weight for a, w in weights.items() if w > 0} print(weights) balparts = {a: w / total_balance for a, w in balances.items() if w > 0} print(balparts) total_blocks = height - reward_start reward_owed = {a: w * per_block * total_blocks for a, w in weights.items()} print(reward_owed) print("Total", sum(reward_owed.values())) return reward_owed, start_height, end_height
async def process_contract_history(contract_address, start_height, platform="ETH", balances=None, last_seen=None): web3 = get_web3() contract = get_contract(contract_address, web3) abi = contract.events.Transfer._get_event_abi() topic = construct_event_topic_set(abi, web3.codec) if balances is None: balances = { settings.ethereum_deployer: settings.ethereum_total_supply * DECIMALS } last_height = start_height end_height = web3.eth.blockNumber changed_addresses = set() to_append = list() async for i in get_logs(web3, contract, start_height, topics=topic): evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] if height != last_height: yield (last_height, (balances, platform, changed_addresses)) changed_addresses = set() if last_seen is not None: last_seen.extend(to_append) to_append = list() if last_seen is not None: tx_hash = evt_data.transactionHash.hex() if tx_hash in last_seen: continue else: to_append.append(tx_hash) balances[args['_from']] = (balances.get(args['_from'], 0) - args['_value']) balances[args['_to']] = balances.get(args['_to'], 0) + args['_value'] changed_addresses.add(args['_from']) changed_addresses.add(args['_to']) last_height = height if len(changed_addresses): yield (last_height, (balances, platform, changed_addresses))
def process_pool_history(pool, per_block, start_height, end_height): abi = pool['contract'].events.Transfer._get_event_abi() web3 = get_web3() topic = construct_event_topic_set(abi, web3.codec) weights = dict() balances = dict() reward_start = max(pool['start_height'], config['reward_start'], start_height) last_height = reward_start end_height = min(web3.eth.blockNumber, end_height) def update_weights(since, current): for addr, value in balances.items(): # skip LBP deployer address if addr == '0xC98A0A4d9D9F789b86f03AbfdcEaEE7e3538e3dF': continue if value > 0: weights[addr] = weights.get(addr, 0) + (value * (current-since)) for i in get_logs(web3, pool['contract'], pool['start_height'], topics=topic): evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] if height > end_height: break if height > reward_start: update_weights(last_height, height) # to handle gaps in our staking contract's reward distribution, # a user's balance accumulates whenever they stake to the contract if args['from'] == '0x0310DEE97b42063BbB46d02a674727C13eb79cFD': balances[args.to] = balances.get(args.to, 0) - args.value elif args.to == '0x0310DEE97b42063BbB46d02a674727C13eb79cFD': balances[args['from']] = balances.get(args['from'], 0) + args.value last_height = height height = end_height update_weights(last_height, height) total_weight = sum(weights.values()) total_balance = sum([b for b in balances.values() if b > 0]) weights = {a: w / total_weight for a, w in weights.items() if w > 0} print(weights) balparts = {a: w / total_balance for a, w in balances.items() if w > 0} print(balparts) total_blocks = height - reward_start reward_owed = {a: w*per_block*total_blocks for a, w in weights.items()} print(reward_owed) print("Total", sum(reward_owed.values())) return reward_owed, start_height, end_height
def process_pool_history(pool, per_block, start_height, end_height): abi = pool['contract'].events.Transfer._get_event_abi() web3 = get_web3() topic = construct_event_topic_set(abi, web3.codec) weights = dict() balances = dict() reward_start = max(pool['start_height'], config['reward_start'], start_height) last_height = reward_start end_height = min(web3.eth.blockNumber, end_height) def update_weights(since, current): for addr, value in balances.items(): if value > 0: weights[addr] = weights.get(addr, 0) + (value * (current - since)) for i in get_logs(web3, pool['contract'], pool['start_height'], topics=topic): evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] if height > end_height: break if height > reward_start: update_weights(last_height, height) balances[args['from']] = balances.get(args['from'], 0) - args.value balances[args.to] = balances.get(args.to, 0) + args.value last_height = height height = end_height update_weights(last_height, height) total_weight = sum(weights.values()) total_balance = sum([b for b in balances.values() if b > 0]) weights = {a: w / total_weight for a, w in weights.items() if w > 0} print(weights) balparts = {a: w / total_balance for a, w in balances.items() if w > 0} print(balparts) total_blocks = height - reward_start reward_owed = {a: w * per_block * total_blocks for a, w in weights.items()} print(reward_owed) print("Total", sum(reward_owed.values())) return reward_owed, start_height, end_height
def get_token_transfers(token, start_block, end_block) -> pd.DataFrame: topics = construct_event_topic_set( filter_by_name('Transfer', token.abi)[0], web3.codec, ) postgres.cache_token(token.address) decimals = contract(token.address).decimals() events = decode_logs( get_logs_asap(token.address, topics, from_block=start_block, to_block=end_block)) return pd.DataFrame( Parallel(1, 'threading')( delayed(_process_transfer_event)(event, token, decimals) for event in events))
def prepare_events(contract): with open(contract['abi'], 'r') as file: abi = json.loads(file.read()) for element in abi: if element['type'] == 'event': topic = construct_event_topic_set(element)[0] if element['name'] in contract['tracked_event_names']: if topic not in tracked_events: tracked_events[topic] = element logger.info( f'Added event {contract["abi"]} - {element["name"]}' ) if 'addresses' not in tracked_events[topic]: tracked_events[topic]['addresses'] = [] tracked_events[topic]['addresses'].append( contract['address'])
def get_protocol_fees(address): """ Get all protocol fee payouts for a given vault. Fees can be found as vault share transfers to the rewards address. """ vault = Vault.from_address(address) rewards = vault.vault.rewards() topics = construct_event_topic_set( filter_by_name('Transfer', vault.vault.abi)[0], web3.codec, { 'sender': address, 'receiver': rewards }, ) logs = decode_logs(get_logs_asap(address, topics)) return {log.block_number: log['value'] / vault.scale for log in logs}
def unwrap(self) -> List[Wrapper]: registry = Registry() wrappers = [self.wrapper] if isinstance(self.wrapper, str) else self.wrapper topics = construct_event_topic_set( filter_by_name('Transfer', registry.vaults[0].vault.abi)[0], web3.codec, {'receiver': wrappers}, ) addresses = [str(vault.vault) for vault in registry.vaults] from_block = min(ThreadPoolExecutor().map(contract_creation_block, addresses)) # wrapper -> {vaults} deposits = defaultdict(set) for log in decode_logs(get_logs_asap(addresses, topics, from_block)): deposits[log['receiver']].add(log.address) return [ Wrapper(name=vault.name, vault=str(vault.vault), wrapper=wrapper) for wrapper in wrappers for vault in registry.vaults if str(vault.vault) in deposits[wrapper] ]
def process_contract_history(contract_address, start_height, end_height): web3 = get_web3() contract = get_contract(contract_address, web3) abi = contract.events.Transfer._get_event_abi() topic = construct_event_topic_set(abi, web3.codec) weights = dict() balances = dict() last_height = start_height end_height = min(web3.eth.blockNumber, end_height) for i in get_logs(web3, contract, start_height, topics=topic): evt_data = get_event_data(web3.codec, abi, i) args = evt_data['args'] height = evt_data['blockNumber'] if height > end_height: break balances[args['_from']] = balances.get(args['_from'], 0) - args['_value'] balances[args['_to']] = balances.get(args['_to'], 0) + args['_value'] last_height = height height = end_height return balances
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.proxy_factory_contract = get_proxy_factory_contract(self.ethereum_client.w3) self.proxy_creation_topic = construct_event_topic_set(self.proxy_factory_contract.events.ProxyCreation().abi, None)[0]
def test_construct_event_topics(event_abi, arguments, expected): actual = construct_event_topic_set(event_abi, arguments) assert actual == expected
def test_construct_event_topics(web3, arguments, expected): actual = construct_event_topic_set(EVENT_1_ABI, web3.codec, arguments) assert actual == expected
'indexed': True, 'name': 'to', 'type': 'address' }, { 'indexed': False, 'name': 'value', 'type': 'uint256' }, ], 'name': 'Transfer', 'type': 'event', } TOPICS_IN = construct_event_topic_set(ABI, {'from': ZERO_ADDRESS}) TOPICS_OUT = construct_event_topic_set(ABI, {'to': ZERO_ADDRESS}) ts_cache = {} pool = ThreadPoolExecutor(10) label = colored('Ethereum', 'blue') def fetch(): start = Bridge.last_block('ethereum') or LTO_BLOCK print(label, 'fetching since', start) end = w3.eth.blockNumber txs = [] logs_in = get_logs_multipart(w3, start, end, LTO_TOKEN, TOPICS_IN, 10000) logs_out = get_logs_multipart(w3, start, end, LTO_TOKEN, TOPICS_OUT, 10000) for batch in chain.from_iterable(zip(logs_in, logs_out)):
def test_construct_event_topics_strict(w3_strict_abi, arguments, expected): actual = construct_event_topic_set(EVENT_1_ABI, w3_strict_abi.codec, arguments) assert actual == expected
def test_construct_event_topics_strict_errors(w3_strict_abi, arguments, error): with pytest.raises(error): construct_event_topic_set(EVENT_2_ABI, w3_strict_abi.codec, arguments)
def find_transfers(address, from_address, to_address, start_block, end_block): topics = construct_event_topic_set(abi, web3.codec, { "from": from_address, "to": to_address }) return get_logs_asap(address, topics, start_block, end_block)