def add_fee(self): """Adding fee to the transaction by decreasing 'change' transaction.""" if not self.fee: self.calculate_fee() fee_in_satoshi = to_base_units(self.fee) if len(self.tx.vout) == 1 or self.tx.vout[1].nValue < fee_in_satoshi: raise RuntimeError( 'Cannot subtract fee from change transaction. You need to add more input transactions.' ) self.tx.vout[1].nValue -= fee_in_satoshi
def build_outputs(self): if not self.secret_hash: self.generate_hash() self.set_locktime(number_of_hours=self.init_hours) else: self.set_locktime(number_of_hours=self.participate_hours) self.build_atomic_swap_contract() contract_p2sh = self.contract.to_p2sh_scriptPubKey() self.tx_out_list = [ CMutableTxOut(to_base_units(self.value), contract_p2sh), ] if self.utxo_value > self.value: change = self.utxo_value - self.value self.tx_out_list.append( CMutableTxOut( to_base_units(change), CBitcoinAddress(self.sender_address).to_scriptPubKey()))
def get_first_vout_from_tx_json(cls, tx_json: dict) -> CTxOut: ''' Adapter method for returning first vout. Args: tx_json (dict): dictionary with transaction details Returns: CTxOut: transaction output ''' cscript = script.CScript.fromhex( tx_json['vout'][0]['scriptPubKey']['hex']) nValue = to_base_units(float(tx_json['vout'][0]['value'])) return CTxOut(nValue, cscript)
def test_transaction_fee(unsigned_transaction): assert type(unsigned_transaction.size) == int unsigned_transaction.fee_per_kb = 0.002 unsigned_transaction.add_fee() assert type(unsigned_transaction.fee) == float assert unsigned_transaction.fee < 1, 'Transaction fee should be in main units' change_without_fee = unsigned_transaction.tx.vout[1].nValue unsigned_transaction.add_fee() change_with_fee = unsigned_transaction.tx.vout[1].nValue assert change_without_fee - to_base_units(unsigned_transaction.fee) == change_with_fee assert unsigned_transaction.tx.serialize()
def build_outputs(self): self.tx_out_list = [ CMutableTxOut( to_base_units(self.value), CBitcoinAddress(self.recipient_address).to_scriptPubKey()) ]
def __init__( self, network, contract: str, raw_transaction: Optional[str]=None, transaction_address: Optional[str]=None ): if not raw_transaction and not transaction_address: raise ValueError('Provide raw_transaction or transaction_address argument.') self.network = network self.symbol = self.network.default_symbol self.contract = contract self.tx = None self.vout = None self.confirmations = None self.tx_address = transaction_address if raw_transaction: self.tx = self.network.deserialize_raw_transaction(raw_transaction) try: self.vout = self.tx.vout[0] except IndexError: raise ValueError('Given transaction has no outputs.') else: tx_json = get_transaction(network.default_symbol, transaction_address, network.is_test_network()) if not tx_json: raise ValueError('No transaction found under given address.') if 'hex' in tx_json: # transaction from blockcypher or raven explorer self.tx = self.network.deserialize_raw_transaction(tx_json['hex']) self.vout = self.tx.vout[0] else: # transaction from cryptoid incorrect_cscript = script.CScript.fromhex(tx_json['outputs'][0]['script']) correct_cscript = script.CScript([script.OP_HASH160, list(incorrect_cscript)[2], script.OP_EQUAL]) nValue = to_base_units(tx_json['outputs'][0]['amount']) self.vout = CTxOut(nValue, correct_cscript) if 'confirmations' in tx_json: self.confirmations = tx_json['confirmations'] elif 'block_height' in tx_json: self.confirmations = self.network.latest_block - tx_json['block_height'] elif 'block' in tx_json: self.confirmations = self.network.latest_block - tx_json['block'] if not self.vout: raise ValueError('Given transaction has no outputs.') contract_tx_out = self.vout contract_script = script.CScript.fromhex(self.contract) script_pub_key = contract_script.to_p2sh_scriptPubKey() valid_p2sh = script_pub_key == contract_tx_out.scriptPubKey self.address = str(CBitcoinAddress.from_scriptPubKey(script_pub_key)) self.balance = get_balance(self.network, self.address) script_ops = list(contract_script) if valid_p2sh and self.is_valid_contract_script(script_ops): self.recipient_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[6])) self.refund_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[13])) self.locktime_timestamp = int.from_bytes(script_ops[8], byteorder='little') self.locktime = datetime.utcfromtimestamp(self.locktime_timestamp) self.secret_hash = b2x(script_ops[2]) self.value = from_base_units(contract_tx_out.nValue) else: raise ValueError('Given transaction is not a valid contract.')
def test_to_base_units(btc_value): satoshi_value = to_base_units(btc_value) assert isinstance(satoshi_value, int) assert satoshi_value == round(btc_value * COIN)
def get_first_vout_from_tx_json(cls, tx_json: dict) -> CTxOut: incorrect_cscript = script.CScript.fromhex(tx_json['outputs'][0]['script']) correct_cscript = script.CScript([script.OP_HASH160, list(incorrect_cscript)[2], script.OP_EQUAL]) nValue = to_base_units(tx_json['outputs'][0]['amount']) return CTxOut(nValue, correct_cscript)
def get_first_vout_from_tx_json(cls, tx_json: dict) -> CTxOut: cscript = script.CScript.fromhex(tx_json['vout'][0]['scriptPubKey']['hex']) nValue = to_base_units(float(tx_json['vout'][0]['value'])) return CTxOut(nValue, cscript)