2018-08-15 12:51:52 +00:00
import logging
2018-10-11 20:28:52 +00:00
from typing import List
2018-05-25 17:29:07 +00:00
import pytest
import requests
import time
2018-09-03 12:52:31 +00:00
from json import JSONDecodeError
2019-10-04 13:50:44 +00:00
from decimal import Decimal
2020-02-24 11:30:45 +00:00
from os import environ
2019-11-29 11:48:07 +00:00
import tests
2018-05-25 17:29:07 +00:00
2022-03-31 15:34:34 +00:00
2022-03-07 21:17:39 +00:00
class NetworkApi ( object ) :
2018-05-25 17:29:07 +00:00
def __init__ ( self ) :
2022-07-20 14:03:42 +00:00
self . network_url = ' http://api-goerli.etherscan.io/api? '
2019-10-02 07:20:53 +00:00
self . headers = {
2021-02-04 12:51:01 +00:00
' User-Agent ' : " Mozilla \\ 5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit \\ 537.36 (KHTML, like Gecko) Chrome \\ 7 "
" 7.0.3865.90 Safari \\ 537.36 " , }
2018-06-07 15:13:37 +00:00
self . chat_bot_url = ' http://offsite.chat:8099 '
2020-02-24 12:53:16 +00:00
self . api_key = environ . get ( ' ETHERSCAN_API_KEY ' )
2018-05-25 17:29:07 +00:00
2020-04-13 19:03:00 +00:00
def log ( self , text : str ) :
tests . test_suite_data . current_test . testruns [ - 1 ] . steps . append ( text )
logging . info ( text )
2022-09-08 14:27:38 +00:00
def send_etherscan_request ( self , method , extracted_param : str ) :
2022-02-11 15:17:54 +00:00
for attempt in range ( 3 ) :
try :
2022-09-08 14:27:38 +00:00
response = requests . request ( ' GET ' , url = method , headers = self . headers ) . json ( )
if response :
return response [ extracted_param ]
2022-02-11 15:17:54 +00:00
except TypeError as e :
2022-09-08 14:27:38 +00:00
self . log ( " Check response from etherscan API. Returned values do not match expected. %s " % str ( e ) )
2022-02-11 15:17:54 +00:00
except JSONDecodeError as e :
self . log ( " No valid JSON response from Etherscan: %s " % str ( e ) )
pass
time . sleep ( 30 )
2018-05-25 17:29:07 +00:00
2018-10-11 20:28:52 +00:00
def get_token_transactions ( self , address : str ) - > List [ dict ] :
2022-09-08 14:27:38 +00:00
method = self . network_url + ' module=account&action=tokentx&address=0x %s &sort=desc&apikey= %s ' % (
address , self . api_key )
return self . send_etherscan_request ( method , ' result ' )
def get_transactions ( self , address : str ) - > List [ dict ] :
method = self . network_url + ' module=account&action=txlist&address=0x %s &sort=desc&apikey= %s ' % ( address , self . api_key )
return self . send_etherscan_request ( method , ' result ' )
2018-07-03 18:50:18 +00:00
2018-05-25 17:29:07 +00:00
def is_transaction_successful ( self , transaction_hash : str ) - > int :
2018-08-07 09:08:54 +00:00
method = self . network_url + ' module=transaction&action=getstatus&txhash= %s ' % transaction_hash
2019-10-02 07:20:53 +00:00
return not int ( requests . request ( ' GET ' , url = method , headers = self . headers ) . json ( ) [ ' result ' ] [ ' isError ' ] )
2018-05-25 17:29:07 +00:00
def get_balance ( self , address ) :
2020-12-08 15:56:57 +00:00
address = ' 0x ' + address
2022-09-08 14:27:38 +00:00
method = self . network_url + ' module=account&action=balance&address= %s &tag=latest&apikey= %s ' % (
address , self . api_key )
balance = self . send_etherscan_request ( method , ' result ' )
if balance :
self . log ( ' Balance is %s Gwei ' % balance )
return int ( balance )
else :
self . log ( ' Cannot extract balance! ' )
2018-05-25 17:29:07 +00:00
2018-06-30 12:17:38 +00:00
def get_latest_block_number ( self ) - > int :
2018-08-07 09:08:54 +00:00
method = self . network_url + ' module=proxy&action=eth_blockNumber '
2018-06-30 12:17:38 +00:00
return int ( requests . request ( ' GET ' , url = method ) . json ( ) [ ' result ' ] , 0 )
2022-09-05 12:08:43 +00:00
def find_transaction_by_hash ( self , transaction_hash : str ) :
method = self . network_url + ' module=transaction&action=gettxreceiptstatus&txhash= %s &apikey= %s ' % (
transaction_hash , self . api_key )
2022-09-08 14:27:38 +00:00
result = self . send_etherscan_request ( method , ' result ' )
if result :
final_status = True
if result [ ' status ' ] == ' 1 ' :
self . log ( " TX %s is found and confirmed " % transaction_hash )
elif result [ ' status ' ] == ' 0 ' :
self . log ( " TX %s is found and failed: " % transaction_hash )
else :
final_status = False
self . log ( " TX %s is not found! " % transaction_hash )
return final_status
2018-05-25 17:29:07 +00:00
2021-06-08 10:58:26 +00:00
def find_transaction_by_unique_amount ( self , address , amount , token = False , decimals = 18 , wait_time = 300 ) :
2021-01-25 16:35:40 +00:00
additional_info = ' token transactions ' if token else ' ETH transactions '
2018-05-25 17:29:07 +00:00
counter = 0
while True :
if counter > = wait_time :
2022-03-31 15:34:34 +00:00
for entry in range ( 0 , 5 ) :
2020-06-17 14:45:40 +00:00
self . log ( ' Transaction # %s , amount is %s ' % ( entry + 1 , float ( int ( transactions [ entry ] [ ' value ' ] ) / 10 * * decimals ) ) )
self . log ( str ( transactions [ entry ] ) )
2018-05-25 17:29:07 +00:00
pytest . fail (
2021-01-25 16:35:40 +00:00
' Transaction with amount %s is not found in list of %s , address is %s during %s s ' %
( amount , additional_info , address , wait_time ) )
2018-05-25 17:29:07 +00:00
else :
2021-06-08 10:58:26 +00:00
self . log ( " Finding tx in %s , attempt # %s " % ( additional_info , str ( int ( counter / 30 ) + 1 ) ) )
2018-09-03 12:52:31 +00:00
try :
if token :
transactions = self . get_token_transactions ( address )
else :
transactions = self . get_transactions ( address )
2021-06-08 10:58:26 +00:00
counter + = 30
time . sleep ( 30 )
2020-04-13 19:03:00 +00:00
except JSONDecodeError as e :
2021-02-08 12:52:20 +00:00
self . log ( " No valid JSON response from Etherscan: %s " % str ( e ) )
2018-09-03 12:52:31 +00:00
continue
2020-04-13 19:03:00 +00:00
try :
for transaction in transactions :
if float ( int ( transaction [ ' value ' ] ) / 10 * * decimals ) == float ( amount ) :
2022-03-31 15:34:34 +00:00
self . log ( " Tx is found: %s (etherscan API) " % transaction [ ' hash ' ] )
2020-04-13 19:03:00 +00:00
return transaction
except TypeError as e :
2022-02-11 15:17:54 +00:00
self . log ( " Failed iterate transactions(Etherscan unexpected error): " + str ( e ) )
continue
2018-07-13 10:56:36 +00:00
2022-07-20 14:03:42 +00:00
def wait_for_confirmation_of_transaction ( self , address , amount , confirmations = 6 , token = False ) :
2018-07-13 10:56:36 +00:00
start_time = time . time ( )
2021-01-25 16:35:40 +00:00
if token :
token_info = " token transaction "
else :
token_info = " ETH transaction "
self . log ( ' Waiting %s %s for %s to have %s confirmations ' % ( amount , token_info , address , confirmations ) )
2021-06-08 10:58:26 +00:00
while round ( time . time ( ) - start_time , ndigits = 2 ) < 600 : # should be < idleTimeout capability
2019-11-07 13:38:14 +00:00
transaction = self . find_transaction_by_unique_amount ( address , amount , token )
2020-10-28 19:39:02 +00:00
self . log (
' Expected amount of confirmations is %s , in fact %s ' % ( confirmations , transaction [ ' confirmations ' ] ) )
2020-01-03 15:27:50 +00:00
if int ( transaction [ ' confirmations ' ] ) > = confirmations :
2018-07-13 10:56:36 +00:00
return
2020-10-28 19:39:02 +00:00
time . sleep ( 20 )
2020-07-22 13:30:07 +00:00
pytest . fail ( ' Transaction with amount %s was not confirmed, address is %s , still has %s confirmations ' % ( amount , address , int ( transaction [ ' confirmations ' ] ) ) )
2018-05-25 17:29:07 +00:00
def verify_balance_is_updated ( self , initial_balance , recipient_address , wait_time = 360 ) :
counter = 0
while True :
if counter > = wait_time :
2020-10-20 15:34:52 +00:00
pytest . fail ( ' Balance is not changed during %s seconds ' % wait_time )
2018-05-25 17:29:07 +00:00
elif initial_balance == self . get_balance ( recipient_address ) :
counter + = 10
time . sleep ( 10 )
2020-10-20 15:34:52 +00:00
self . log ( ' Waiting %s seconds for for changing account balance from %s ' % ( counter , initial_balance ) )
2018-05-25 17:29:07 +00:00
else :
2020-10-20 15:34:52 +00:00
self . log ( ' Balance is updated! ' )
2018-05-25 17:29:07 +00:00
return
2018-06-28 18:46:51 +00:00
def verify_balance_is ( self , expected_balance : int , recipient_address : str , errors : list ) :
balance = self . get_balance ( recipient_address )
if balance / 1000000000000000000 != expected_balance :
errors . append ( ' Recipients balance is not updated on etherscan ' )
2022-09-08 14:27:38 +00:00
# Do not use until web3 update
# def faucet(self, address):
# try:
# self.log("Trying to get funds from %s" % self.faucet_url)
# return requests.request('GET', '%s/0x%s' % (self.faucet_url, address)).json()
# except JSONDecodeError as e:
# self.log("No valid JSON response from Etherscan: %s " % str(e))
# pass
# def faucet_backup(self, address):
# self.log("Trying to get funds from %s" % self.faucet_backup_address)
# address = "0x" + address
# w3.donate_testnet_eth(address=address, amount=0.01, inscrease_default_gas_price=10)
# def get_donate(self, address, external_faucet=False, wait_time=300):
# initial_balance = self.get_balance(address)
# counter = 0
# if initial_balance < 1000000000000000000:
# if external_faucet:
# self.faucet_backup(address)
# else:
# self.faucet(address)
# while True:
# if counter >= wait_time:
# pytest.fail("Donation was not received during %s seconds!" % wait_time)
# elif self.get_balance(address) == initial_balance:
# counter += 10
# time.sleep(10)
# self.log('Waiting %s seconds for donation' % counter)
# else:
# self.log('Got %s Gwei for %s' % (self.get_balance(address), address))
# return
2018-05-25 17:29:07 +00:00
2018-03-31 20:05:11 +00:00
def start_chat_bot ( self , chat_name : str , messages_number : int , interval : int = 1 ) - > list :
2018-06-07 15:13:37 +00:00
url = ' %s /ping/ %s ?count= %s &interval= %s ' % ( self . chat_bot_url , chat_name , messages_number , interval )
2018-03-31 20:05:11 +00:00
text = requests . request ( ' GET ' , url ) . text
return [ i . split ( maxsplit = 5 ) [ - 1 ] . strip ( ' * ' ) for i in text . splitlines ( ) ]
2019-10-04 13:50:44 +00:00
def get_rounded_balance ( self , fetched_balance , actual_balance ) :
fetched_balance , actual_balance = str ( fetched_balance ) , str ( actual_balance )
# get actual number of decimals on account balance
decimals = abs ( Decimal ( fetched_balance ) . as_tuple ( ) . exponent )
rounded_balance = round ( float ( actual_balance ) , decimals )
2021-09-08 14:44:20 +00:00
return rounded_balance
2022-09-08 14:27:38 +00:00
def get_tx_param_by_hash ( self , hash : str , param : str ) :
method = self . network_url + ' module=proxy&action=eth_getTransactionByHash&txhash= %s &apikey= %s ' % (
hash , self . api_key )
res = self . send_etherscan_request ( method , ' result ' )
return int ( res [ param ] , 16 )
2021-09-08 14:44:20 +00:00
def get_custom_fee_tx_params ( self , hash : str ) :
return {
2022-09-08 14:27:38 +00:00
' fee_cap ' : str ( self . get_tx_param_by_hash ( hash , ' maxFeePerGas ' ) / 1000000000 ) ,
' tip_cap ' : str ( self . get_tx_param_by_hash ( hash , ' maxPriorityFeePerGas ' ) / 1000000000 ) ,
' gas_limit ' : str ( self . get_tx_param_by_hash ( hash , ' gas ' ) )
}