def solve(self, digest): from .transaction import Witness pubkey = self.privk.pub() sig = self.privk.sign(digest) return (ScriptSig.from_stack_data([ StackData.from_bytes(sig + self.sighash.as_byte()), StackData.from_bytes(pubkey.compressed) ]), Witness([]))
def inputs(utxos, previous_transaction_indexes=None): inputs, amount = list(), int() for index, utxo in enumerate(utxos): if previous_transaction_indexes is None or index in previous_transaction_indexes: amount += utxo["amount"] inputs.append( TxIn(txid=utxo["hash"], txout=utxo["output_index"], script_sig=ScriptSig.empty(), sequence=Sequence.max())) return inputs, amount
def _get_unsigned_txn(self): # outputs_amounts is copied so any instance can be modified with change_fee, # and will still function correctly, i.e the change address won't already # be in the self._outputs_amounts dict self._modified_outputs_amounts = self.outputs_amounts.copy() # adding change address to outputs, if there is leftover balance that isn't dust if self._change_amount > 0: self._modified_outputs_amounts[self.change_address] = self._change_amount outputs = [] for i, (addr, amount) in enumerate(self._modified_outputs_amounts.items()): outputs.append(TxOut( value=amount, n=i, script_pubkey=self.get_script_pubkey(addr) )) inputs = [] for t in self._specific_utxo_data: # build inputs using the UTXO data in self._specific_utxo_data, # script_sig is empty as the transaction will be signed later inputs.append( TxIn(txid=t[0], txout=t[1], script_sig=ScriptSig.empty(), sequence=Sequence.max(), witness=Witness([StackData.zero()])) if self.is_segwit else None, ) if self.is_segwit: transaction = MutableSegWitTransaction( version=TX_VERSION, ins=inputs, outs=outputs, locktime=Locktime(self.locktime), ) else: transaction = MutableTransaction( version=TX_VERSION, ins=inputs, outs=outputs, locktime=Locktime(self.locktime) ) return transaction
def createContractInput(fundingTx): to_spend = fundingTx #TODO Failing here #Signer=fundingTxn() #Todo LATEST Failing here .Change to spend input Transaction Signer = ScriptSig.empty() #TOdo create SignFundingTx(FundingTx, Solver) SigScript = [ MutableTxIn( txid=to_spend, # Input need not be a segwit transaction. txout=0, script_sig=Signer, sequence=Sequence.max()) ] return SigScript
def solve(self, *digests): from .transaction import Witness if len(digests) != len(self.privkeys): raise ValueError('{} privkeys provided and {} digests'.format( len(self.privkeys), len(digests))) script_sig_data = [StackData.zero()] for priv, digest, sighash in zip(self.privkeys, digests, self.sighashes): sig = priv.sign(digest) script_sig_data.append( StackData.from_bytes(sig + sighash.as_byte())) return ScriptSig.from_stack_data(script_sig_data), Witness([])
def _build_inputs( utxos: list, previous_transaction_indexes: Optional[list] = None) -> tuple: inputs, amount = [], 0 for index, utxo in enumerate(utxos): if previous_transaction_indexes is None or index in previous_transaction_indexes: amount += utxo["value"] inputs.append( TxIn(txid=utxo["tx_hash"], txout=utxo["tx_output_n"], script_sig=ScriptSig.empty(), sequence=Sequence.max())) return inputs, amount
def fundingTxn(): Signer = ScriptSig.empty() outvalue = fundingInput_value(fundingTxIn, 0) - 400 MultiSigTx = MutableSegWitTransaction( version=1, #Publish to the Blockchain ins=[ TxIn(txid=fundingTxIn_id, txout=0, script_sig=Signer, sequence=Sequence.max()) ], outs=[TxOut(value=outvalue, n=0, script_pubkey=FundingScript) ], # todo must change this to access the contract script locktime=Locktime(0)) MultiSigTxSigned = MultiSigTx.spend( [fundingTxIn.outs[0]], [funding_sig]) # ToDo Failing here - spend attribute not found print("funding tx signed ", MultiSigTxSigned.hexlify()) # return MultiSigTx,p2sh_solver,MultiSigTxSigned.outs[0]; # TODo when to Return Signed MultiSigTransaction return MultiSigTxSigned.txid, MultiSigTxSigned.outs[0]
def sweepTx(MultiSigTx, MultiSigTxOutput, MultiSigTxSolver, to_pubkey, to_index, to_value): to_spend = MultiSigTx unsigned = MutableSegWitTransaction( version=1, ins=[ TxIn( txid=to_spend, #.txid, txout=to_index, script_sig=ScriptSig.empty(), sequence=Sequence.max()) ], outs=[ TxOut(value=to_value - txFee, n=0, script_pubkey=P2pkhScript(to_pubkey)) ], # todo make funding_pubkey a parameter. This must sweep back tp A & B locktime=Locktime(0)) solver = MultiSigTxSolver signed = unsigned.spend( [MultiSigTxOutput], [solver]) #print ("Return tx signed ",signed.hexlify()) return signed.hexlify()
def build_transaction(self, transaction_id, wallet, amount, locktime=0): """ Build Bitcoin refund transaction. :param transaction_id: Bitcoin fund transaction id to redeem. :type transaction_id: str :param wallet: Bitcoin sender wallet. :type wallet: bitcoin.wallet.Wallet :param amount: Bitcoin amount to withdraw. :type amount: int :param locktime: Bitcoin transaction lock time, defaults to 0. :type locktime: int :returns: RefundTransaction -- Bitcoin refund transaction instance. >>> from shuttle.providers.bitcoin.transaction import RefundTransaction >>> from shuttle.providers.bitcoin.wallet import Wallet >>> sender_wallet = Wallet(network="testnet").from_passphrase("meherett") >>> refund_transaction = RefundTransaction(network="testnet") >>> refund_transaction.build_transaction(transaction_id="1006a6f537fcc4888c65f6ff4f91818a1c6e19bdd3130f59391c00212c552fbd", wallet=sender_wallet, amount=10000) <shuttle.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0> """ # Checking parameter instances if not isinstance(transaction_id, str): raise TypeError("invalid amount instance, only takes string type") if not isinstance(wallet, Wallet): raise TypeError( "invalid wallet instance, only takes Bitcoin Wallet class") # Setting transaction_id and wallet self.transaction_id, self.wallet = transaction_id, wallet # Getting transaction detail by id self.transaction_detail = get_transaction_detail(self.transaction_id) # Getting Hash time lock contract output detail self.htlc_detail = self.transaction_detail["outputs"][0] # Getting HTLC funded amount balance htlc_amount = self.htlc_detail["value"] # Calculating fee self._fee = fee_calculator(1, 1) if amount < self._fee: raise BalanceError("insufficient spend utxos") elif not htlc_amount >= (amount - self._fee): raise BalanceError("insufficient spend utxos", f"maximum you can withdraw {htlc_amount}") # Building mutable Bitcoin transaction self.transaction = MutableTransaction( version=self.version, ins=[ TxIn(txid=self.transaction_id, txout=0, script_sig=ScriptSig.empty(), sequence=Sequence.max()) ], outs=[ TxOut(value=(amount - self._fee), n=0, script_pubkey=P2pkhScript.unhexlify( hex_string=self.wallet.p2pkh())) ], locktime=Locktime(locktime)) self._type = "bitcoin_refund_unsigned" return self
def build_transaction( self, address: str, transaction_hash: str, locktime: int = config["locktime"]) -> "RefundTransaction": """ Build Bitcoin refund transaction. :param address: Bitcoin sender address. :type address: str :param transaction_hash: Bitcoin funded transaction hash/id. :type transaction_hash: str :param locktime: Bitcoin transaction lock time, defaults to ``0``. :type locktime: int :returns: RefundTransaction -- Bitcoin refund transaction instance. >>> from swap.providers.bitcoin.transaction import RefundTransaction >>> refund_transaction: RefundTransaction = RefundTransaction("testnet") >>> refund_transaction.build_transaction(address="n1wgm6kkzMcNfAtJmes8YhpvtDzdNhDY5a", transaction_hash="a211d21110756b266925fee2fbf2dc81529beef5e410311b38578dc3a076fb31") <swap.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0> """ # Check parameter instances if not is_address(address, self._network): raise AddressError( f"Invalid Bitcoin sender '{address}' {self._network} address.") # Set address and transaction_hash self._address, self._transaction_hash, = address, transaction_hash # Get transaction self._transaction_detail = get_transaction( transaction_hash=self._transaction_hash, network=self._network) # Find HTLC UTXO self._htlc_utxo = find_p2sh_utxo(transaction=self._transaction_detail) if self._htlc_utxo is None: raise ValueError( "Invalid transaction id, there is no pay to script hash (P2SH) address." ) self._amount = self._htlc_utxo["value"] # Calculate the fee self._fee = fee_calculator(1, 1) outputs: list = [ TxOut(value=(self._amount - self._fee), n=0, script_pubkey=get_address_hash(address=self._address, script=True)) ] # Build mutable transaction self._transaction = MutableTransaction( version=self._version, ins=[ TxIn(txid=self._transaction_hash, txout=self._htlc_utxo["position"], script_sig=ScriptSig.empty(), sequence=Sequence.max()) ], outs=outputs, locktime=Locktime(locktime)) # Set transaction type self._type = "bitcoin_refund_unsigned" return self
def solve(self, *digests): script_sig, witness = self.inner_solver.solve(*digests) script_sig_data = script_sig.get_data() script_sig_data.append(StackData.from_bytes(self.preimage)) return ScriptSig.from_stack_data(script_sig_data), witness
def solve(self, *digests): script_sig, witness = self.inner_solver.solve(*digests) script_sig_data = script_sig.get_data() script_sig_data.append(StackData.from_int(self.branch.value)) return ScriptSig.from_stack_data(script_sig_data), witness
def solve(self, *digests): from .transaction import Witness script_sig, witness = self.witness_script_solver.solve(*digests) return (ScriptSig.empty(), (script_sig.to_witness() + witness + Witness([self.get_prev_script().to_stack_data()])))
def solve(self, *digests): script_sig, witness = self.redeem_script_solver.solve(*digests) script_sig_data = script_sig.get_data() script_sig_data.append(self.redeem_script.to_stack_data()) return ScriptSig.from_stack_data(script_sig_data), witness
def build_transaction(self, transaction_id, wallet, amount, secret=None, locktime=0): """ Build bitcoin refund transaction. :param transaction_id: bitcoin fund transaction id to redeem. :type transaction_id: str :param wallet: bitcoin sender wallet. :type wallet: bitcoin.wallet.Wallet :param amount: bitcoin amount to withdraw. :type amount: int :param secret: secret passphrase. :type secret: str :param locktime: bitcoin transaction lock time, defaults to 0. :type locktime: int :returns: RefundTransaction -- bitcoin refund transaction instance. >>> from shuttle.providers.bitcoin.transaction import RefundTransaction >>> refund_transaction = RefundTransaction(network="testnet") >>> refund_transaction.build_transaction(fund_transaction_id, sender_wallet, 10000) <shuttle.providers.bitcoin.transaction.RefundTransaction object at 0x0409DAF0> """ # Checking build transaction arguments instance if not isinstance(transaction_id, str): raise TypeError("invalid amount instance, only takes string type") if not isinstance(wallet, Wallet): raise TypeError( "invalid wallet instance, only takes bitcoin Wallet class") if secret is not None and not isinstance(secret, str): raise TypeError("invalid secret instance, only takes string type") # Setting transaction_id and wallet self.transaction_id, self.wallet, self.secret = transaction_id, wallet, secret # Getting transaction detail by id self.transaction_detail = get_transaction_detail(self.transaction_id) # Checking transaction outputs if "outputs" not in self.transaction_detail: raise NotFoundError("not found htlc in this %s hash" % self.transaction_id) # Hash time lock contract output self.htlc = self.transaction_detail["outputs"][0] # Sender account output sender_address = P2pkhScript.unhexlify( self.transaction_detail["outputs"][1]["script"]).address( mainnet=self.mainnet) self.sender_account = Wallet(network=self.network).from_address( str(sender_address)) # HTLC info's htlc_amount = self.htlc["value"] htlc_script = P2shScript.unhexlify(self.htlc["script"]) # Calculating fee self.fee = fee_calculator(1, 1) if amount < self.fee: raise BalanceError("insufficient spend utxos") elif not htlc_amount >= (amount - self.fee): raise BalanceError("insufficient spend utxos", "maximum withdraw %d" % htlc_amount) # Building mutable bitcoin transaction self.transaction = MutableTransaction( version=self.version, ins=[ TxIn(txid=self.transaction_id, txout=0, script_sig=ScriptSig.empty(), sequence=Sequence.max()) ], outs=[ TxOut(value=(amount - self.fee), n=0, script_pubkey=P2pkhScript.unhexlify( self.sender_account.p2pkh())) ], locktime=Locktime(locktime)) return self
penalty = int(float(to_spend.to_json()['vout'][0]['value']) * (10**8)) # 估算挖矿费用 print('estimating mining fee...') mining_fee_per_kb = get_mining_fee_per_kb(coin_symbol, api_key, condidence='high') estimated_tx_size = cal_tx_size_in_byte(inputs_num=1, outputs_num=1) mining_fee = int(mining_fee_per_kb * (estimated_tx_size / 1000)) * 2 # 创建交易 unsigned = MutableTransaction(version=2, ins=[ TxIn(txid=to_spend.txid, txout=0, script_sig=ScriptSig.empty(), sequence=Sequence.max()) ], outs=[ TxOut(value=penalty - mining_fee, n=0, script_pubkey=script), ], locktime=Locktime(0)) # 修改交易 signed = unsigned.spend([to_spend.outs[0]], [if_solver]) # 广播交易 print('open_tx_hex: ', signed.hexlify())