def _invoke_contract_method( self, contract_factory, name, *args, tx_extra_params: Optional[ContractTxExtraParams] = None, signer: Optional[BaseAccount] = None, dry_run=False, estimate_gas=False, dry_run_block_id=None, node_index=None, expectation=TransactionExpectation()): tx_params = TxParams( **to_dict(tx_extra_params)) if tx_extra_params else None dry_run_block_id = 'latest' if dry_run_block_id is None else dry_run_block_id node = self._cluster.node(node_index) contract = contract_factory(node.eth) method = contract.constructor if not name else getattr( contract.functions, name) bound_method = method(*args) if dry_run: signer = signer or self.default_tx_signer if signer is not None: with_from = {'from': signer.address} tx_params = TxParams(**with_from, ** tx_params) if tx_params else TxParams( **with_from) if estimate_gas: return bound_method.estimateGas(tx_params, dry_run_block_id) return bound_method.call(tx_params, dry_run_block_id) return self._send_tx(bound_method.buildTransaction(tx_params), node_index=node_index, signer=signer, expectation=expectation)
def _send_tx(self, tx: TxParams, node_index=None, signer: Optional[BaseAccount] = None, expectation=TransactionExpectation()): signer = signer or self.default_tx_signer send_signed = signer is not None node = self._cluster.node(node_index) orig_params = tx tx = dict(**tx) if 'nonce' not in tx: if send_signed: tx['nonce'] = self._nonce_strategy(signer.address) else: if 'from' in tx: tx['nonce'] = self._nonce_strategy(getattr(tx, 'from')) else: tx['from'] = node.account.address tx['nonce'] = self._nonce_strategy(node.account.address) if send_signed: if 'gasPrice' not in tx: tx['gasPrice'] = node.eth.gas_price if 'gas' not in tx: tx['gas'] = node.eth.estimate_gas(TxParams(**tx)) tx_hash = node.eth.send_raw_transaction( signer.sign_transaction(TxParams(**tx)).rawTransaction) else: tx_hash = node.eth.send_transaction(TxParams(**tx)) assert tx_hash not in self._pending_trxs and tx_hash not in self._executed_trxs ret = TransactionResultFuture(tx_hash) self._pending_trxs[tx_hash] = self._PendingTransaction( ret, expectation, orig_params) return ret
def sign_transaction(self, raw_tx: TxParams) -> HexStr: raw_tx.pop('from', None) raw_tx['chainId'] = self._chain_id tx = serializable_unsigned_transaction_from_dict(raw_tx) tx_hash = tx.hash() self._logger.debug(f'Signing transaction hash {tx_hash.hex()}') sig = self._generate_signature(tx_hash) signed_tx = encode_transaction(tx, vrs=sig) return HexStr(signed_tx.hex())
def transact(self, path: str, request: Any) -> None: assert self.key is not None response = requests.post( base_url + path, headers={"Content-Type": "application/json"}, data=json.dumps(request), ) response.raise_for_status() for tx in response.json()["transactions"]: address = self.key.address._checksummed nonce = w3.eth.getTransactionCount(address, "pending") params = fill_transaction_defaults( w3, TxParams({ "data": HexStr(tx["data"]), "from": address, "nonce": nonce, "to": Web3.toChecksumAddress(tx["to"]), }), ) signed = Account.sign_transaction(params, bytes(self.key)) tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) assert tx_receipt["status"] == 1
async def test_async_send_transaction( self, async_w3: "Web3", unlockable_account_dual_type: ChecksumAddress, unlockable_account_pw: str) -> None: tx_params = TxParams() tx_params["to"] = unlockable_account_dual_type tx_params["from"] = unlockable_account_dual_type tx_params["value"] = Wei(123) response = await async_w3.geth.personal.send_transaction( # type: ignore tx_params, unlockable_account_pw) assert response is not None
def extract_valid_transaction_params(transaction_params: TxParams) -> TxParams: 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")
def deploy_contract( web3: Web3, contracts_manager: ContractManager, contract_name: str, deployer_key: CCPrivateKey, args: List[Any], ) -> Contract: deployer_address = private_key_to_address(deployer_key.to_hex()) json_contract = contracts_manager.get_contract(contract_name) contract = web3.eth.contract(abi=json_contract["abi"], bytecode=json_contract["bin"]) tx_hash = contract.constructor(*args).transact(TxParams({"from": deployer_address})) contract_address = web3.eth.get_transaction_receipt(tx_hash)["contractAddress"] return contract(contract_address)
def coin_transfer(self, to: Union[Address, ChecksumAddress, str], value: int, tx_extra_params: Optional[CoinTxExtraParams] = None, node_index=None, signer=None, expectation=TransactionExpectation()): assert to return self._send_tx(TxParams( to=to, value=value, **(to_dict(tx_extra_params) if tx_extra_params else dict())), node_index=node_index, signer=signer, expectation=expectation)
def get_transaction_params(network: str, web3_client: Web3) -> TxParams: network_config = NETWORKS[network] max_fee_per_gas = network_config["KEEPER_MAX_FEE_PER_GAS"] account_nonce = web3_client.eth.getTransactionCount( web3_client.eth.default_account) latest_block = web3_client.eth.get_block("latest") max_priority_fee = min(web3_client.eth.max_priority_fee, max_fee_per_gas) base_fee = latest_block["baseFeePerGas"] priority_fee = int(str(max_priority_fee), 16) max_fee_per_gas = priority_fee + 2 * base_fee return TxParams( nonce=account_nonce, maxPriorityFeePerGas=max_priority_fee, maxFeePerGas=hex(min(max_fee_per_gas, max_fee_per_gas)), )
def __init__( self, web3: Web3, private_key: PrivateKey, gas_limit: int, gas_price: int, wait: int = 10, contracts_version: Optional[str] = None, ): # pylint: disable=E1101 super(ContractDeployer, self).__init__(web3=web3, contracts_version=contracts_version) self.wait = wait self.owner = private_key_to_address(private_key) self.transaction = TxParams({ "from": self.owner, "gas": Wei(gas_limit), "gasPrice": Wei(gas_price * int(units["gwei"])), }) self.web3.middleware_onion.add( construct_sign_and_send_raw_middleware(private_key)) # Check that the precompiled data matches the source code # Only for current version, because this is the only one with source code if self.contracts_version in [None, CONTRACTS_VERSION]: contract_manager_source = ContractSourceManager( contracts_source_path(contracts_version=contracts_version)) contract_manager_source.verify_precompiled_checksums( self.precompiled_path) else: LOG.info( "Skipped checks against the source code because it is not available." )