def transact(self, transaction, out_f): print("Sending transaction to trezor for signature...\n", file=out_f) signature = self.client.ethereum_sign_tx( n=[ 44 + bip32utils.BIP32_HARDEN, 60 + bip32utils.BIP32_HARDEN, bip32utils.BIP32_HARDEN, 0, self.index ], nonce=transaction["nonce"], gas_price=transaction["gasPrice"], gas_limit=transaction["gas"], to=bytearray.fromhex(transaction["to"][2:]), value=transaction["value"], data=bytearray.fromhex(transaction["data"][2:])) transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) raw_transaction = encode_transaction(unsigned_transaction, vrs=(signature[0], int(signature[1].hex(), 16), int(signature[2].hex(), 16))) print("Submitting transaction...\n", file=out_f) txn_hash = self.w3.eth.sendRawTransaction(raw_transaction) # Wait for transaction to be mined receipt = None while receipt is None: time.sleep(1) receipt = self.w3.eth.getTransactionReceipt(txn_hash) return receipt
def _transact(self, function_call=None, transaction=None): """Transaction utility: builds a transaction and signs it with private key, or uses native transactions with accounts """ # If we have no local means to sign transactions, raise error if not (self._ledger or self._key_file or self._private_key): raise ValueError( "No valid signing method found!\n" "Please specify one of: key_file, private_key, auth_type='ledger' or auth_type='trezor'" ) private_key = self._private_key if self._key_file: password = self._password or getpass( "Password to decrypt keystore file %s: " % self.account) private_key = self._get_private_key(self._key_file, password) # get the nonce for the current address nonce = self.w3.eth.getTransactionCount(self.address) # Build a transaction to sign gas_buffer = 100000 # Estimate gas cost if transaction is None: transaction = {} transaction.update({ 'nonce': nonce, 'gas': 4000000, 'gasPrice': self.w3.eth.generateGasPrice() }) if function_call: transaction = function_call.buildTransaction(transaction) gas_limit = self.w3.eth.estimateGas(transaction) + gas_buffer transaction.update({'gas': gas_limit}) if 'from' in transaction: del transaction['from'] if private_key: # Sign the transaction using the private key and send it as raw transaction signed_tx = self.w3.eth.account.signTransaction( transaction, '0x' + private_key) tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) else: unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) pos = self._ledger.get_account_index(self.address) (v, r, s) = self._ledger.sign(rlp.encode(unsigned_transaction), account_index=pos) encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) tx_hash = self.w3.eth.sendRawTransaction(encoded_transaction) self.logger.info( "Submitted transaction %s, waiting for transaction receipt..." % tx_hash.hex()) tx_receipt = self._wait_for_receipt(tx_hash) return hasattr(tx_receipt, "status") and tx_receipt["status"] == 1
def _sign_web3_transaction(tx: Dict[str, any], v: int, r: int, s: int) -> (bytes, HexBytes): """ Signed transaction can be send with w3.eth.sendRawTransaction """ unsigned_transaction = serializable_unsigned_transaction_from_dict(tx) rlp_encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) # To get the address signing, just do ecrecover_to_pub(unsigned_transaction.hash(), v, r, s) return rlp_encoded_transaction, unsigned_transaction.hash()
def transact(self, transaction, out_f): tx = UnsignedTransaction( nonce=transaction["nonce"], gasPrice=transaction["gasPrice"], gas=transaction["gas"], to=bytes(bytearray.fromhex(transaction["to"][2:])), value=transaction["value"], data=bytes(bytearray.fromhex(transaction["data"][2:]))) encoded_tx = rlp.encode(tx, UnsignedTransaction) overflow = len(self.dongle_path) + 1 + len(encoded_tx) - 255 if overflow > 0: encoded_tx, remaining_tx = encoded_tx[:-overflow], encoded_tx[ -overflow:] apdu = LedgerIdentityProvider.SIGN_TX_OP apdu += bytearray([ len(self.dongle_path) + 1 + len(encoded_tx), int(len(self.dongle_path) / 4) ]) apdu += self.dongle_path + encoded_tx try: print("Sending transaction to ledger for signature...\n", file=out_f) result = self.dongle.exchange(apdu) while overflow > 0: encoded_tx = remaining_tx overflow = len(encoded_tx) - 255 if overflow > 0: encoded_tx, remaining_tx = encoded_tx[: -overflow], encoded_tx[ -overflow:] apdu = LedgerIdentityProvider.SIGN_TX_OP_CONT apdu += bytearray([len(encoded_tx)]) apdu += encoded_tx result = self.dongle.exchange(apdu) except CommException: raise RuntimeError( "Received commException from ledger. Are you sure your device is unlocked and the " "Ethereum app is running?") transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) raw_transaction = encode_transaction( unsigned_transaction, vrs=(result[0], int.from_bytes(result[1:33], byteorder="big"), int.from_bytes(result[33:65], byteorder="big"))) return send_and_wait_for_transaction(raw_transaction, self.w3, out_f)
def signed_tx(cls, sutx, v, r, s): enctx = encode_transaction(sutx, (v, r, s)) transaction_hash = keccak(enctx) attr_dict = AttributeDict({ 'rawTransaction': HexBytes(enctx), 'hash': HexBytes(transaction_hash), 'r': r, 's': s, 'v': v, }) return attr_dict
def transact(self, transaction, out_f): tx = UnsignedTransaction( nonce=transaction["nonce"], gasPrice=transaction["gasPrice"], gas=transaction["gas"], to=bytes(bytearray.fromhex(transaction["to"][2:])), value=transaction["value"], data=bytes(bytearray.fromhex(transaction["data"][2:])) ) encoded_tx = rlp.encode(tx, UnsignedTransaction) overflow = len(self.dongle_path) + 1 + len(encoded_tx) - 255 if overflow > 0: encoded_tx, remaining_tx = encoded_tx[:- overflow], encoded_tx[-overflow:] apdu = LedgerIdentityProvider.SIGN_TX_OP apdu += bytearray([len(self.dongle_path) + 1 + len(encoded_tx), int(len(self.dongle_path) / 4)]) apdu += self.dongle_path + encoded_tx try: print("Sending transaction to ledger for signature...\n", file=out_f) result = self.dongle.exchange(apdu) while overflow > 0: encoded_tx = remaining_tx overflow = len(encoded_tx) - 255 if overflow > 0: encoded_tx, remaining_tx = encoded_tx[:- overflow], encoded_tx[-overflow:] apdu = LedgerIdentityProvider.SIGN_TX_OP_CONT apdu += bytearray([len(encoded_tx)]) apdu += encoded_tx result = self.dongle.exchange(apdu) except CommException: raise RuntimeError("Received commException from ledger. Are you sure your device is unlocked and the " "Ethereum app is running?") transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) raw_transaction = encode_transaction(unsigned_transaction, vrs=(result[0], int.from_bytes( result[1:33], byteorder="big"), int.from_bytes(result[33:65], byteorder="big"))) return send_and_wait_for_transaction(raw_transaction, self.w3, out_f)
def sign_keyvault(client, vault_url, key_name, key_version, tx, chain_id=0): unsigned_tx = serializable_unsigned_transaction_from_dict(tx) unsigned_tx_hash = unsigned_tx.hash() key_bundle = client.get_key(vault_url, key_name, key_version) json_key = key_bundle.key pubkey = convert_json_key_to_public_key_bytes(json_key) address_signer = public_key_to_address(pubkey[1:]) sig_resp = client.sign(vault_url, key_name, key_version, 'ECDSA256', unsigned_tx_hash) vrs = convert_azure_secp256k1_signature_to_vrs(pubkey, unsigned_tx_hash, sig_resp.result, chain_id) ret_signed_transaction = encode_transaction(unsigned_tx, vrs) return address_signer, ret_signed_transaction
def transact(self, transaction, out_f): print("Sending transaction to trezor for signature...\n", file=out_f) signature = self.client.ethereum_sign_tx(n=[44 + BIP32_HARDEN, 60 + BIP32_HARDEN, BIP32_HARDEN, 0, self.index], nonce=transaction["nonce"], gas_price=transaction["gasPrice"], gas_limit=transaction["gas"], to=bytearray.fromhex(transaction["to"][2:]), value=transaction["value"], data=bytearray.fromhex(transaction["data"][2:])) transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict(transaction) raw_transaction = encode_transaction(unsigned_transaction, vrs=(signature[0], int(signature[1].hex(), 16), int(signature[2].hex(), 16))) return send_and_wait_for_transaction(raw_transaction, self.w3, out_f)
def transact(self, transaction, out_f): tx = UnsignedTransaction( nonce=transaction["nonce"], gasPrice=transaction["gasPrice"], gas=transaction["gas"], to=bytes(bytearray.fromhex(transaction["to"][2:])), value=transaction["value"], data=bytes(bytearray.fromhex(transaction["data"][2:]))) encoded_tx = rlp.encode(tx, UnsignedTransaction) apdu = LedgerIdentityProvider.SIGN_TX_OP apdu += bytearray([ len(self.dongle_path) + 1 + len(encoded_tx), int(len(self.dongle_path) / 4) ]) apdu += self.dongle_path + encoded_tx try: print("Sending transaction to ledger for signature...\n", file=out_f) result = self.dongle.exchange(apdu) except CommException: raise RuntimeError( "Received commException from ledger. Are you sure your device is unlocked and the " "Ethereum app is running?") transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) raw_transaction = encode_transaction( unsigned_transaction, vrs=(result[0], int.from_bytes(result[1:33], byteorder="big"), int.from_bytes(result[33:65], byteorder="big"))) print("Submitting transaction...\n", file=out_f) txn_hash = self.w3.eth.sendRawTransaction(raw_transaction) # Wait for transaction to be mined receipt = None while receipt is None: time.sleep(1) receipt = self.w3.eth.getTransactionReceipt(txn_hash) return receipt
def sign_keyvault(addressSigner, signingClient, vault_url, key_name, key_version, tx, chain_id=0): unsigned_tx = serializable_unsigned_transaction_from_dict(tx) unsigned_tx_hash = unsigned_tx.hash() valid = False while not valid: sig_resp = signingClient.sign(vault_url, key_name, key_version, 'ES256K', unsigned_tx_hash) v, r, s, valid = util.convert_azure_secp256k1_signature_to_vrs( pubkey, unsigned_tx_hash, sig_resp.result, chain_id) vrs = (v, r, s) ret_signed_transaction = encode_transaction(unsigned_tx, vrs) return address_signer, ret_signed_transaction
def transact(self, transaction, out_f): print("Sending transaction to trezor for signature...\n", file=out_f) signature = self.client.ethereum_sign_tx(n=[44 + BIP32_HARDEN, 60 + BIP32_HARDEN, BIP32_HARDEN, 0, self.index], nonce=transaction["nonce"], gas_price=transaction["gasPrice"], gas_limit=transaction["gas"], to=bytearray.fromhex( transaction["to"][2:]), value=transaction["value"], data=bytearray.fromhex(transaction["data"][2:])) transaction.pop("from") unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) raw_transaction = encode_transaction(unsigned_transaction, vrs=(signature[0], int(signature[1].hex(), 16), int(signature[2].hex(), 16))) return send_and_wait_for_transaction(raw_transaction, self.w3, out_f)
def sign_transaction_dict(eth_key, transaction_dict): # generate RLP-serializable transaction, with defaults filled unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction_dict) transaction_hash = unsigned_transaction.hash() # detect chain if isinstance(unsigned_transaction, UnsignedTransaction): chain_id = None else: chain_id = unsigned_transaction.v # sign with private key (v, r, s) = sign_transaction_hash(eth_key, transaction_hash, chain_id) # serialize transaction with rlp encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) return (v, r, s, encoded_transaction)
def serialize(tx: SignedEthTx) -> str: ''' serialize a signed Ethereum transaction ''' temp_tx = cast(dict, tx.copy()) # NB: serializer wants bytes ¯\_(ツ)_/¯ # strip prefix and convert to bytes if 'x' in temp_tx['to']: temp_tx['to'] = bytes.fromhex(temp_tx['to'][2:]) else: temp_tx['to'] = bytes.fromhex(temp_tx['to']) temp_tx_obj = transactions.Transaction.from_dict(temp_tx) v = temp_tx.pop('v') r = temp_tx.pop('r') s = temp_tx.pop('s') # NB: the serializer wants the signature passed through # both inside AND outside the object ಠ_ಠ return transactions.encode_transaction(temp_tx_obj, (v, r, s)).hex()
def _transact(self, function_call=None, transaction=None): """Transaction utility: builds a transaction and signs it with private key, or uses native transactions with accounts """ # If we have no local means to sign transactions, raise error if not (self._ledger or self._key_file or self._private_key): raise ValueError( "No valid signing method found!\n" "Please specify one of: key_file, private_key, auth_type='ledger' or auth_type='trezor'" ) private_key = self._private_key if self._key_file: password = self._password or getpass( "Password to decrypt keystore file %s: " % self.account) private_key = self._get_private_key(self._key_file, password) # Build a transaction to sign gas_buffer = 100000 # Estimate gas cost if transaction is None: transaction = {} auto_gas_price = self.w3.eth.generateGasPrice() user_gas_price = transaction.get('gasPrice') transaction.update({ 'nonce': transaction.get("nonce", self.w3.eth.getTransactionCount(self.address)), 'gas': 4000000, 'gasPrice': auto_gas_price }) if function_call: transaction = function_call.buildTransaction(transaction) gas_limit = self.w3.eth.estimateGas(transaction) + gas_buffer transaction.update({ 'gas': gas_limit, 'gasPrice': user_gas_price if user_gas_price is not None else auto_gas_price }) if 'from' in transaction: del transaction['from'] if private_key: # Sign the transaction using the private key and send it as raw transaction signed_tx = self.w3.eth.account.signTransaction( transaction, '0x' + private_key) tx_hash = self.w3.eth.sendRawTransaction(signed_tx.rawTransaction) else: unsigned_transaction = serializable_unsigned_transaction_from_dict( transaction) pos = self._ledger.get_account_index(self.address) self.logger.info( "Signing transaction with your hardware wallet, please confirm on the hardware device when prompted..." ) (v, r, s) = self._ledger.sign(rlp.encode(unsigned_transaction), account_index=pos) encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) tx_hash = self.w3.eth.sendRawTransaction(encoded_transaction) self.logger.info( "Submitted transaction %s, waiting for transaction receipt..." % tx_hash.hex()) tx_receipt = None while not tx_receipt: try: tx_receipt = self._wait_for_receipt(tx_hash) except web3.utils.threads.Timeout: self.logger.warning( "Transaction still pending after 1 minute, waiting some more..." ) self.logger.info( "Gas used: %s at gas price of %.2f gwei (%.8f ether)" % (tx_receipt.get("gasUsed"), self.w3.fromWei(transaction.get("gasPrice"), 'gwei'), self.w3.fromWei( tx_receipt.get("gasUsed") * transaction.get("gasPrice"), 'ether'))) return hasattr(tx_receipt, "status") and tx_receipt["status"] == 1