def _netname(name: str) -> dict: '''resolute network name, required because some providers use shortnames and other use longnames.''' try: long = net_query(name).network_name short = net_query(name).network_shortname except AttributeError: raise UnsupportedNetwork( '''This blockchain network is not supported by the pypeerassets, check networks.py for list of supported networks.''' ) return {'long': long, 'short': short}
def test_net_query(): "Check that we can find NetworkParams for networks by name." # Use a network's long name net_params = net_query("peercoin") assert net_params.shortname == "ppc" # Use a network's short name net_params = net_query("tppc") assert net_params.name == "peercoin-testnet" # Try to find a network we don't know about. with pytest.raises(UnsupportedNetwork): net_query("not a network name we know of.")
def opreturn(self, string: hex, locktime: int = 0) -> str: '''send op_return transaction''' network_params = net_query(Settings.network) inputs = provider.select_inputs(Settings.key.address, 0.01) outs = [ tx_output(network=provider.network, value=Decimal(0), n=1, script=nulldata_script(bytes.fromhex(string))) ] # first round of txn making is done by presuming minimal fee change_sum = Decimal(inputs['total'] - network_params.min_tx_fee) outs.append( tx_output(network=provider.network, value=change_sum, n=len(outs) + 1, script=p2pkh_script(address=Settings.key.address, network=provider.network))) unsigned_tx = make_raw_transaction(network=provider.network, inputs=inputs['utxos'], outputs=outs, locktime=Locktime(locktime)) signedtx = sign_transaction(provider, unsigned_tx, Settings.key) return sendtx(signedtx)
def test_sign_transaction(): network_params = net_query('tppc') provider = Explorer(network='tppc') key = Kutil(network='tppc', privkey=bytearray.fromhex('9e321f5379c2d1c4327c12227e1226a7c2e08342d88431dcbb0063e1e715a36c') ) dest_address = 'mwn75Gavp6Y1tJxca53HeCj5zzERqWagr6' unspent = provider.select_inputs(key.address, 0.63) # 0.69 output = tx_output(network='tppc', value=Decimal(0.1), n=0, script=p2pkh_script(network='tppc', address=dest_address) ) unsigned = MutableTransaction( version=1, ins=unspent['utxos'], outs=[output], locktime=Locktime(0), network=network_params, timestamp=int(time.time()), ) parent_outputs = [find_parent_outputs(provider, i) for i in unsigned.ins] solver = P2pkhSolver(key._private_key) signed = unsigned.spend(parent_outputs, [solver for i in parent_outputs]) assert isinstance(signed, Transaction)
def vote_init(vote: Vote, inputs: dict, change_address: str) -> bytes: '''initialize vote transaction, must be signed by the deck_issuer privkey''' network_params = net_query(vote.deck.network) deck_vote_tag_address = deck_vote_tag(vote.deck) tx_fee = network_params.min_tx_fee # settle for min tx fee for now for utxo in inputs['utxos']: utxo['txid'] = unhexlify(utxo['txid']) utxo['scriptSig'] = unhexlify(utxo['scriptSig']) outputs = [{ "redeem": 0.01, "outputScript": transactions.monosig_script(deck_vote_tag_address) }, { "redeem": 0, "outputScript": transactions.op_return_script(vote.to_protobuf) }, { "redeem": float(inputs['total']) - float(tx_fee) - float(0.01), "outputScript": transactions.monosig_script(change_address) }] return transactions.make_raw_transaction(inputs['utxos'], outputs)
def __init__(self, network: str, privkey: bytearray=None, from_string: str=None, from_wif: str=None) -> None: ''' High level helper class for handling public key cryptography. : privkey - privatekey bytes : from_wif - <WIF> import private key from your wallet in WIF format : from_bytes - import private key in binary format : network - specify network [ppc, tppc, btc] : from_string - specify seed (string) to make the privkey from ''' self.network = network self.btcpy_constants = net_query(self.network).btcpy_constants if privkey is not None: self._private_key = PrivateKey(privkey) if from_string is not None: self._private_key = PrivateKey(sha256( from_string.encode()).digest()) if from_wif is not None: self._private_key = PrivateKey.from_wif(wif=from_wif, network=self.btcpy_constants, ) if not privkey: if from_string == from_wif is None: # generate a new privkey self._private_key = PrivateKey(bytearray(urandom(32))) self.privkey = str(self._private_key) self._public_key = PublicKey.from_priv(self._private_key) self.pubkey = str(self._public_key)
def make_raw_transaction( network: str, inputs: list, outputs: list, locktime: Locktime, timestamp: int=int(time()), version: int=1, ) -> MutableTransaction: '''create raw transaction''' network_params = net_query(network) if network_params.name.startswith("peercoin"): return MutableTransaction( version=version, ins=inputs, outs=outputs, locktime=locktime, network=network_params, timestamp=timestamp, ) return MutableTransaction( version=version, ins=inputs, outs=outputs, locktime=locktime, network=network_params, )
def test_sign_transaction(): network_params = net_query('tppc') provider = Cryptoid(network='tppc') key = pa.Kutil( network='tppc', privkey=bytearray.fromhex( '9e321f5379c2d1c4327c12227e1226a7c2e08342d88431dcbb0063e1e715a36c') ) dest_address = pa.Kutil(network='tppc').address unspent = provider.select_inputs(key.address, 1) output = tx_output(network='tppc', value=Decimal(0.1), n=0, script=p2pkh_script(network='tppc', address=dest_address)) unsigned = MutableTransaction( version=1, ins=unspent['utxos'], outs=[output], locktime=Locktime(0), network=network_params, timestamp=int(time.time()), ) assert isinstance(sign_transaction(provider, unsigned, key), Transaction)
def find_parent_outputs(provider: Provider, utxo: TxIn) -> TxOut: '''due to design of the btcpy library, TxIn object must be converted to TxOut object before signing''' network_params = net_query(provider.network) index = utxo.txout # utxo index return TxOut.from_json(provider.getrawtransaction(utxo.txid, 1)['vout'][index], network=network_params)
def p2pkh_script(network: str, address: str) -> P2pkhScript: '''create pay-to-key-hash (P2PKH) script''' network_params = net_query(network) addr = Address.from_string(network=network_params, string=address) return P2pkhScript(addr)
def tx_output(network: str, value: Decimal, n: int, script: ScriptSig) -> TxOut: '''create TxOut object''' network_params = net_query(network) return TxOut(network=network_params, value=int(value * network_params.to_unit), n=n, script_pubkey=script)
def card_transfer(provider: Provider, card: CardTransfer, inputs: dict, change_address: str, locktime: int = 0) -> Transaction: '''Prepare the CardTransfer Transaction object : card - CardTransfer object : inputs - utxos (has to be owned by deck issuer) : change_address - address to send the change to : locktime - tx locked until block n=int ''' network_params = net_query(provider.network) pa_params = param_query(provider.network) if card.deck_p2th is None: raise Exception("card.deck_p2th required for tx_output") outs = [ tx_output(network=provider.network, value=pa_params.P2TH_fee, n=0, script=p2pkh_script(address=card.deck_p2th, network=provider.network)), # deck p2th tx_output(network=provider.network, value=Decimal(0), n=1, script=nulldata_script( card.metainfo_to_protobuf)) # op_return ] for addr, index in zip(card.receiver, range(len(card.receiver))): outs.append( # TxOut for each receiver, index + 2 because we have two outs already tx_output(network=provider.network, value=Decimal(0), n=index + 2, script=p2pkh_script(address=addr, network=provider.network))) # first round of txn making is done by presuming minimal fee change_sum = Decimal(inputs['total'] - network_params.min_tx_fee - pa_params.P2TH_fee) outs.append( tx_output(network=provider.network, value=change_sum, n=len(outs) + 1, script=p2pkh_script(address=change_address, network=provider.network))) unsigned_tx = make_raw_transaction(network=provider.network, inputs=inputs['utxos'], outputs=outs, locktime=Locktime(locktime)) return unsigned_tx
def metainfo_to_protobuf(self) -> bytes: '''encode card_transfer info to protobuf''' card = cardtransferproto() card.version = self.version card.amount.extend(self.amount) card.number_of_decimals = self.number_of_decimals if self.asset_specific_data: if not isinstance(self.asset_specific_data, bytes): card.asset_specific_data = self.asset_specific_data.encode() else: card.asset_specific_data = self.asset_specific_data if card.ByteSize() > net_query(self.network).op_return_max_bytes: raise OverSizeOPReturn( ''' Metainfo size exceeds maximum of {max} bytes supported by this network.''' .format(max=net_query(self.network).op_return_max_bytes)) return card.SerializeToString()
def p2sh_p2pkh_script(network: str, address: str) -> P2shScript: '''p2sh embedding p2pkh''' network_params = net_query(network) addr = Address.from_string(network=network_params, string=address) p2pkh = P2pkhScript(addr) return P2shScript(p2pkh)
def metainfo_to_protobuf(self) -> bytes: '''encode deck into protobuf''' deck = deckspawnproto() deck.version = self.version deck.name = self.name deck.number_of_decimals = self.number_of_decimals deck.issue_mode = self.issue_mode if self.asset_specific_data: if not isinstance(self.asset_specific_data, bytes): deck.asset_specific_data = self.asset_specific_data.encode() else: deck.asset_specific_data = self.asset_specific_data if deck.ByteSize() > net_query(self.network).op_return_max_bytes: raise OverSizeOPReturn( ''' Metainfo size exceeds maximum of {max} bytes supported by this network.''' .format(max=net_query(self.network).op_return_max_bytes)) return deck.SerializeToString()
def deck_spawn(provider: Provider, deck: Deck, inputs: dict, change_address: str, locktime: int = 0) -> Transaction: '''Creates Deck spawn raw transaction. : key - Kutil object which we'll use to sign the tx : deck - Deck object : card - CardTransfer object : inputs - utxos (has to be owned by deck issuer) : change_address - address to send the change to : locktime - tx locked until block n=int ''' network_params = net_query(deck.network) pa_params = param_query(deck.network) if deck.production: p2th_addr = pa_params.P2TH_addr else: p2th_addr = pa_params.test_P2TH_addr # first round of txn making is done by presuming minimal fee change_sum = Decimal(inputs['total'] - network_params.min_tx_fee - pa_params.P2TH_fee) txouts = [ tx_output(network=deck.network, value=pa_params.P2TH_fee, n=0, script=p2pkh_script(address=p2th_addr, network=deck.network)), # p2th tx_output(network=deck.network, value=Decimal(0), n=1, script=nulldata_script( deck.metainfo_to_protobuf)), # op_return tx_output(network=deck.network, value=change_sum, n=2, script=p2pkh_script(address=change_address, network=deck.network)) # change ] unsigned_tx = make_raw_transaction(network=deck.network, inputs=inputs['utxos'], outputs=txouts, locktime=Locktime(locktime)) return unsigned_tx
def sendto(self, address: Union[str], amount: Union[float], locktime: int = 0) -> str: '''send coins to address''' if not len(address) == amount: raise RecieverAmountMismatch network_params = net_query(Settings.network) inputs = provider.select_inputs(Settings.key.address, sum(amount)) outs = [] for addr, index, amount in zip(address, range(len(address)), amount): outs.append( tx_output(network=Settings.network, value=Decimal(amount), n=index, script=p2pkh_script(address=addr, network=Settings.network))) # first round of txn making is done by presuming minimal fee change_sum = Decimal(inputs['total'] - network_params.min_tx_fee) outs.append( tx_output(network=provider.network, value=change_sum, n=len(outs) + 1, script=p2pkh_script(address=Settings.key.address, network=provider.network))) unsigned_tx = make_raw_transaction(network=provider.network, inputs=inputs['utxos'], outputs=outs, locktime=Locktime(locktime)) signedtx = sign_transaction(provider, unsigned_tx, Settings.key) return sendtx(signedtx)
def vote_cast(vote: Vote, choice_index: int, inputs: dict, change_address: str) -> bytes: '''vote cast transaction''' network_params = net_query(vote.deck.network) vote_cast_addr = vote.vote_choice_address[choice_index] tx_fee = network_params.min_tx_fee # settle for min tx fee for now for utxo in inputs['utxos']: utxo['txid'] = unhexlify(utxo['txid']) utxo['scriptSig'] = unhexlify(utxo['scriptSig']) outputs = [{ "redeem": 0.01, "outputScript": transactions.monosig_script(vote_cast_addr) }, { "redeem": float(inputs['total']) - float(tx_fee) - float(0.01), "outputScript": transactions.monosig_script(change_address) }] return transactions.make_raw_transaction(inputs['utxos'], outputs)
def address(self) -> str: '''generate an address from pubkey''' return str(self._public_key.to_address(net_query(self.network)))
def address(self) -> str: '''generate an address from pubkey''' btcpy_constants = net_query(self.network).btcpy_constants return str(self._public_key.to_address(btcpy_constants))
def network_properties(self) -> NetworkParams: '''network parameters [min_fee, denomination, ...]''' return net_query(self.network)