def prepare_replacement_transaction(web3, current_transaction, new_transaction): if current_transaction['blockHash'] is not None: raise ValueError( 'Supplied transaction with hash {} has already been mined'.format( current_transaction['hash'])) if 'nonce' in new_transaction and new_transaction[ 'nonce'] != current_transaction['nonce']: raise ValueError( 'Supplied nonce in new_transaction must match the pending transaction' ) if 'nonce' not in new_transaction: new_transaction = assoc(new_transaction, 'nonce', current_transaction['nonce']) if 'gasPrice' in new_transaction: if new_transaction['gasPrice'] <= current_transaction['gasPrice']: raise ValueError( 'Supplied gas price must exceed existing transaction gas price' ) else: generated_gas_price = web3.eth.generateGasPrice(new_transaction) minimum_gas_price = int( math.ceil(current_transaction['gasPrice'] * 1.1)) if generated_gas_price and generated_gas_price > minimum_gas_price: new_transaction = assoc(new_transaction, 'gasPrice', generated_gas_price) else: new_transaction = assoc(new_transaction, 'gasPrice', minimum_gas_price) return new_transaction
def extract_valid_transaction_params(transaction_params): extracted_params = { key: transaction_params[key] for key in VALID_TRANSACTION_PARAMS if key in transaction_params } if extracted_params.get('data') is not None: if transaction_params.get('input') is not None: if extracted_params['data'] != transaction_params['input']: msg = 'failure to handle this transaction due to both "input: {}" and' msg += ' "data: {}" are populated. You need to resolve this conflict.' err_vals = (transaction_params['input'], extracted_params['data']) raise AttributeError(msg.format(*err_vals)) else: return extracted_params else: return extracted_params elif extracted_params.get('data') is None: if transaction_params.get('input') is not None: return assoc(extracted_params, 'data', transaction_params['input']) else: return extracted_params else: raise Exception( "Unreachable path: transaction's 'data' is either set or not set")
async def sendTransaction(self, transaction): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move gas estimation in middleware if 'gas' not in transaction: transaction = assoc( transaction, 'gas', get_buffered_gas_estimate(self.web3s, transaction), ) return await self.web3s.manager.request_blocking( "eth_sendTransaction", [transaction], )
def fill_nonce(web3, transaction): if 'from' in transaction and 'nonce' not in transaction: return assoc( transaction, 'nonce', web3.eth.getTransactionCount(transaction['from'], block_identifier='pending')) else: return transaction
async def estimateGas(self, transaction): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) return await self.web3s.manager.request_blocking( "eth_estimateGas", [transaction], )
def middleware(method, params): if method == 'eth_sendTransaction': transaction = params[0] if 'gasPrice' not in transaction: generated_gas_price = web3.eth.generateGasPrice(transaction) if generated_gas_price is not None: transaction = assoc(transaction, 'gasPrice', generated_gas_price) return make_request(method, [transaction]) return make_request(method, params)
async def middleware(method, params): response = await make_request(method, params) if 'result' in response: result = response['result'] if is_dict(result) and not isinstance(result, AttributeDict): return assoc(response, 'result', AttributeDict.recursive(result)) else: return response else: return response
async def call(self, transaction, block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address(self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move to middleware if block_identifier is None: block_identifier = self.defaultBlock result=await self.web3s.manager.request_blocking( "eth_call", [transaction, block_identifier], ) return result
async def traceCall(self, transaction, mode='stateDiff', block_identifier=None): # TODO: move to middleware if 'from' not in transaction and is_checksum_address( self.defaultAccount): transaction = assoc(transaction, 'from', self.defaultAccount) # TODO: move to middleware if block_identifier is None: block_identifier = self.defaultBlock return await self.web3s.manager.request_blocking( "trace_call", [transaction, [mode], block_identifier], )
async def middleware(method, params): result = await make_request(method, params) # As of v1.8, Geth returns errors when you request a # receipt for a transaction that is not in the chain. # It used to return a result of None, so we simulate the old behavior. if method == 'eth_getTransactionReceipt' and 'error' in result: is_geth = await web3.version.node.startswith('Geth') if is_geth and result['error']['code'] == -32000: return assoc( dissoc(result, 'error'), 'result', None, ) else: return result else: return result
def fill_default(field, guess_func, web3, transaction): if field in transaction and transaction[field] is not None: return transaction else: guess_val = guess_func(web3, transaction) return assoc(transaction, field, guess_val)