def fill_transaction_defaults(web3: "Web3", transaction: TxParams) -> TxParams: """ if web3 is None, fill as much as possible while offline """ defaults = {} for key, default_getter in TRANSACTION_DEFAULTS.items(): if key not in transaction: if key == 'gasPrice' and any_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction): # if dynamic fee txn params present, do not set a default 'gasPrice' if missing continue if callable(default_getter): if web3 is not None: default_val = default_getter(web3, transaction) else: raise ValueError("You must specify %s in the transaction" % key) else: default_val = default_getter defaults[key] = default_val if 'type' not in transaction and any_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction): # default transaction type to '2' if dynamic fee txn params are present defaults['type'] = '0x2' return merge(defaults, transaction)
def fill_transaction_defaults(web3: "Web3", transaction: TxParams) -> TxParams: """ if web3 is None, fill as much as possible while offline """ strategy_based_gas_price = web3.eth.generate_gas_price(transaction) is_dynamic_fee_transaction = ( not strategy_based_gas_price and ('gasPrice' not in transaction # default to dynamic fee transaction or any_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction))) defaults = {} for key, default_getter in TRANSACTION_DEFAULTS.items(): if key not in transaction: if (is_dynamic_fee_transaction and key == 'gasPrice' or not is_dynamic_fee_transaction and key in DYNAMIC_FEE_TXN_PARAMS): # do not set default max fees if legacy txn or gas price if dynamic fee txn continue if callable(default_getter): if web3 is None: raise ValueError( "You must specify a '%s' value in the transaction" % key) default_val = default_getter(web3, transaction) else: default_val = default_getter defaults[key] = default_val return merge(defaults, transaction)
def validate_transaction_params(transaction: TxParams, latest_block: BlockData, strategy_based_gas_price: Wei) -> TxParams: # gas price strategy explicitly set: if (strategy_based_gas_price is not None and 'gasPrice' not in transaction and none_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction)): transaction = assoc(transaction, 'gasPrice', hex(strategy_based_gas_price)) # legacy and dynamic fee tx variables used: if "gasPrice" in transaction and any_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction): raise TransactionTypeMismatch() # dynamic fee transaction - canonical case: elif all_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction): if int(str(transaction["maxFeePerGas"]), 16) < int( str(transaction["maxPriorityFeePerGas"]), 16): raise InvalidTransaction( "maxFeePerGas must be >= maxPriorityFeePerGas") # dynamic fee txn - no max fee: elif 'maxFeePerGas' not in transaction and 'maxPriorityFeePerGas' in transaction: base_fee = latest_block['baseFeePerGas'] priority_fee = int(str(transaction['maxPriorityFeePerGas']), 16) max_fee_per_gas = priority_fee + 2 * base_fee transaction = assoc(transaction, 'maxFeePerGas', hex(max_fee_per_gas)) # dynamic fee transaction - no priority fee: elif 'maxFeePerGas' in transaction and 'maxPriorityFeePerGas' not in transaction: raise InvalidTransaction( "maxPriorityFeePerGas must be defined in a 1559 transaction.") # should be a fully formed (legacy or dynamic fee) tx or no fee values were specified return transaction
def prepare_replacement_transaction(web3: "Web3", original_transaction: TxData, replacement_transaction: TxParams, gas_multiplier: float = 1.125) -> TxParams: if original_transaction['blockHash'] is not None: raise ValueError( f'Supplied transaction with hash {original_transaction["hash"]!r} ' 'has already been mined') if 'nonce' in replacement_transaction and ( replacement_transaction['nonce'] != original_transaction['nonce']): raise ValueError( 'Supplied nonce in new_transaction must match the pending transaction' ) if 'nonce' not in replacement_transaction: replacement_transaction = assoc(replacement_transaction, 'nonce', original_transaction['nonce']) if any_in_dict(DYNAMIC_FEE_TXN_PARAMS, replacement_transaction): # for now, the client decides if a dynamic fee txn can replace the existing txn or not pass elif 'gasPrice' in replacement_transaction and original_transaction[ 'gasPrice'] is not None: if replacement_transaction['gasPrice'] <= original_transaction[ 'gasPrice']: raise ValueError( 'Supplied gas price must exceed existing transaction gas price' ) else: generated_gas_price = web3.eth.generate_gas_price( replacement_transaction) minimum_gas_price = int( math.ceil(original_transaction['gasPrice'] * gas_multiplier)) if generated_gas_price and generated_gas_price > minimum_gas_price: replacement_transaction = assoc(replacement_transaction, 'gasPrice', generated_gas_price) else: replacement_transaction = assoc(replacement_transaction, 'gasPrice', minimum_gas_price) return replacement_transaction