Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do you spend from multisig address in Python? #28

Closed
gustavklopp opened this issue Jan 13, 2016 · 24 comments
Closed

How do you spend from multisig address in Python? #28

gustavklopp opened this issue Jan 13, 2016 · 24 comments

Comments

@gustavklopp
Copy link

I've generated a multisig address thanks to generate_multisig_address().

Now I don't get it how to spend it using create_unsigned_tx, make_tx_signatures then broadcast_signed_transaction.

from blockcypher import create_unsigned_tx, make_tx_signatures, broadcast_signed_transaction
inputs = [{'address':multisig_addr},] 
outputs = [{'address': dest_addr, 'value': btc_to_satoshis(2.00000000)}]

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet')
pprint(unsigned_tx)

# then sign it with one of the 3 private keys: here `priv1` :
privkey_list = [priv1]
pubkey_list = [pub1]
tx_signatures = make_tx_signatures(txs_to_sign=unsigned_tx['tosign'], privkey_list=privkey_list, pubkey_list=pubkey_list)
pprint(tx_signatures)

# and broadcast it:
r = broadcast_signed_transaction(unsigned_tx, tx_signatures, pubkey_list, coin_symbol='btc-testnet')
pprint(r)

But it's not working:

{'errors': [{'error': 'Error building input: Error generating scriptsig when '
                      'building transaction: Non-standard script type: .'},
            {'error': 'Not enough funds in 1 inputs to pay for 2 outputs, '
                      'missing -200000000.'},
            {'error': 'Not enough funds in 1 inputs to pay for 2 outputs, '
                      'missing -1519959000.'},
            {'error': 'Not enough funds after fees in 0 inputs to pay for 2 '
                      'outputs, missing -1519979400.'},
            {'error': 'Error validating generated transaction: Transaction '
                      'missing input or output.'}],
          ...
@mflaxman
Copy link

Hey @gustavklopp thanks for opening the issue and sorry for the problem.

I've never tried to redeem funds send to a multisig address with the python library, but this library should support it.

I'm not 100% sure, but I think that the error you're running into here is in building the transaction, which would happen on the call to create_unsinged_tx. You can confirm this by making the following CURL call without even needing to use the python library at all:

$ curl -d '{"inputs":[{"addresses": ["multisig_addr_goes_here"]}],"outputs":[{"addresses": ["dest_addr_goes_here"], "value": 200000000}]}' https://api.blockcypher.com/v1/btc/test3/txs/new?includeToSign=true

Does that make sense?

Unfortunately, in order for us to help you debug this will require you sharing your addresses (not the private keys of course!). If you'd rather not do this over github, you can email support@blockcypher.com and reference this github issue.

@gustavklopp
Copy link
Author

Thanks a lot for your help
curl gives me exactly the same result in fact: http://pastebin.com/VeH8EQdX
Here's the script. (one of the private key is included... but since it's multisig...)

dest_addr = "mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a"

priv1 = "9c46389dde9e820294b68defd44e01da12cfe1374324cf27c198e4822e7d9d1e"
pub1 = "0471b0e83960b9a8ad980400fc7ee85e9739009f0ee08ef033784bdcefe7f38c64e9ba2b9d842089486735556e0b1940304db510ad521865bb5b028dee229c1dbd"
addr1 = "mySFV5esqFZqz8maEVjEodxwc9xyhXMmmY"

priv2 = XXX
pub2 = '04a3cc3225df2ef6ca72e960c5cab0059731301d5efe61e7ffa1c4cac3a8e4994adcb27f01a282b7747d96ffdad324e774087c4a35197e99016bca62541af26eab'
addr2 = 'mouKAz9iAgMJzZjiiw4bZ4rxkJapkTXVDZ'

priv3 = XXX
pub3 = '04db43666cf4206e7848aaaf551e2ea6af2488b23046c155f1456d0dd175c782eef61acc42ededcd45a37012c7e096125e356c839e9c0a5f9c75d48aeddcad6712'
addr3 = 'mkmCeTJCLuhQw37xGCW7gFSSh3z4wXxGQ1'

pubkey_list = [pub1, pub2, pub3]
multisig = generate_multisig_address(pubkey_list, coin_symbol='btc-testnet')
# so we got:
multisig_addr = '2NEMZM6bLwdT18sKSrnfXcdcdGfqgccc9Qj'

from blockcypher import create_unsigned_tx, make_tx_signatures, broadcast_signed_transaction

inputs = [{'address':multisig_addr}]
outputs = [{'address': dest_addr, 'value':200000 }]

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet')
# pprint(unsigned_tx)

privkey_list = [priv1]
pubkey_list = [pub1]

tx_signatures = make_tx_signatures(txs_to_sign=unsigned_tx['tosign'], privkey_list=privkey_list, pubkey_list=pubkey_list)

r = broadcast_signed_transaction(unsigned_tx, tx_signatures, pubkey_list, coin_symbol='btc-testnet')
print(r)

@acityinohio
Copy link
Contributor

Sorry for the trouble @gustavklopp. I think you actually need to send the pubkey array as the inputs' addresses when spending money from a multisig address...otherwise we won't be able to send the proper data to sign to unlock P2SH funds: http://dev.blockcypher.com/#multisig-transactions

So in the code snippet above, I'd change

inputs = [{'address':multisig_addr}]

into:

inputs = [{'address':pubkey_list}]

After that, you might run into some trouble signing multiple signatures with different priv-pub-key pairs; just have to make sure the pubkeys and addrs you supply are in the right order for make_tx_signatures.

@gustavklopp
Copy link
Author

Thanks.
I've tried to use
inputs = [{'address':pubkey_list}] or inputs = [{'address':adress_list}]
but I've got now:

Traceback (most recent call last):
  File "/home/gus/workspace/btcc_project/test_of_blockcypher_multisig.py", line 53, in <module>
    unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet')
  File "/home/gus/.Envs/bitcoin/lib/python3.5/site-packages/blockcypher/api.py", line 1494, in create_unsigned_tx
    ), address
AssertionError: ['mySFV5esqFZqz8maEVjEodxwc9xyhXMmmY', 'mouKAz9iAgMJzZjiiw4bZ4rxkJapkTXVDZ', 'mkmCeTJCLuhQw37xGCW7gFSSh3z4wXxGQ1']

So apparently, the assertion check doesn't recognize a list, only address:
I've tried to modify utils.py :

def is_valid_address_for_coinsymbol(b58_address, coin_symbol):
    '''
    Is an address both valid *and* start with the correct character
    for its coin symbol (chain/network)
    '''
    assert is_valid_coin_symbol(coin_symbol)

    if b58_address[0] in COIN_SYMBOL_MAPPINGS[coin_symbol]['address_first_char_list']:
        if is_valid_address(b58_address):
            return True
    return False

modified to :

def is_valid_address_for_coinsymbol(b58_address, coin_symbol):
    '''
    Is an address both valid *and* start with the correct character
    for its coin symbol (chain/network)
    '''
    assert is_valid_coin_symbol(coin_symbol)

    if isinstance(b58_address, list):
        for addr in b58_address:
            if b58_address[0] in COIN_SYMBOL_MAPPINGS[coin_symbol]['address_first_char_list']:
                if not is_valid_address(b58_address):
                    return False
        return True
    else:
        if b58_address[0] in COIN_SYMBOL_MAPPINGS[coin_symbol]['address_first_char_list']:
            if is_valid_address(b58_address):
                return True
    return False

Now when I use:

inputs = [{'address':pubkey_list}]
outputs = [{'address': addr1, 'value':200000 }]
unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet')
pprint(unsigned_tx)

this results in:

{'error': "Couldn't deserialize request: json: cannot unmarshal array into Go "
          'value of type string'}

@mflaxman
Copy link

Hi @gustavklopp, thanks for the info and sorry for all the trouble. We'll get this working!

@acityinohio, why does this curl call work?

$ curl -d '{"inputs":[{"addresses": ["2NEMZM6bLwdT18sKSrnfXcdcdGfqgccc9Qj"]}],"outputs":[{"addresses": ["mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a"], "value": 200000000}]}' https://api.blockcypher.com/v1/btc/test3/txs/new?includeToSignTx=true

The docs seem to suggest that you have to pass an array of pubkeys as inputs and not the address. Since the API should know that this input is a p2sh address (which requires an array of pubkeys) it should be throwing an error here, no?

If that's the case, this should be the curl call:

curl -d '{ "inputs" : [ {"addresses": ["0471b0e83960b9a8ad980400fc7ee85e9739009f0ee08ef033784bdcefe7f38c64e9ba2b9d842089486735556e0b1940304db510ad521865bb5b028dee229c1dbd", "04a3cc3225df2f6ca72e960c5cab0059731301d5efe61e7ffa1c4cac3a8e4994adcb27f01a282b7747d96ffdad324e774087c4a35197e99016bca62541af26eab", "04db43666cf4206e7848aaaf551e2ea6af2488b23046c155f1456d0dd175c782eef61acc42ededcd45a37012c7e096125e356c839e9c0a5f9c75d48aeddcad6712"], "script_type" : "multisig-2-of-3" }],"outputs":[{"addresses": ["mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a"], "value": 200000000}]}' https://api.blockcypher.com/v1/btc/test3/txs/new?includeToSignTx=true

I've update the python SDK to accept this, if you pull the latest version (1.0.56) the following should work:

from blockcypher import create_unsigned_tx

dest_addr = "mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a"

priv1 = "9c46389dde9e820294b68defd44e01da12cfe1374324cf27c198e4822e7d9d1e"
pub1 = "0471b0e83960b9a8ad980400fc7ee85e9739009f0ee08ef033784bdcefe7f38c64e9ba2b9d842089486735556e0b1940304db510ad521865bb5b028dee229c1dbd"
addr1 = "mySFV5esqFZqz8maEVjEodxwc9xyhXMmmY"

pub2 = '04a3cc3225df2ef6ca72e960c5cab0059731301d5efe61e7ffa1c4cac3a8e4994adcb27f01a282b7747d96ffdad324e774087c4a35197e99016bca62541af26eab'
addr2 = 'mouKAz9iAgMJzZjiiw4bZ4rxkJapkTXVDZ'

pub3 = '04db43666cf4206e7848aaaf551e2ea6af2488b23046c155f1456d0dd175c782eef61acc42ededcd45a37012c7e096125e356c839e9c0a5f9c75d48aeddcad6712'
addr3 = 'mkmCeTJCLuhQw37xGCW7gFSSh3z4wXxGQ1'

pubkey_list = [pub1, pub2, pub3]
#multisig = generate_multisig_address(pubkey_list, coin_symbol='btc-testnet')
# so we got:
multisig_addr = '2NEMZM6bLwdT18sKSrnfXcdcdGfqgccc9Qj'

inputs = [{'pubkeys':pubkey_list, 'script_type': 'multisig-2-of-3'}]
outputs = [{'address': dest_addr, 'value':200000 }]

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet', include_tosigntx=True)

import pprint; pprint.pprint(unsigned_tx, width=1)

## -- End pasted text --
{'tosign': ['35fc0f055ec9145631c6216c6cbba3d2e6f75b061b4bfb828a530c4788393608'],
 'tosign_tx': ['01000000017b99e6ed1b439965cae0c2be942eb1622fbc7cb1c12e139795d38eaa9f333be400000000c952410471b0e83960b9a8ad980400fc7ee85e9739009f0ee08ef033784bdcefe7f38c64e9ba2b9d842089486735556e0b1940304db510ad521865bb5b028dee229c1dbd4104a3cc3225df2ef6ca72e960c5cab0059731301d5efe61e7ffa1c4cac3a8e4994adcb27f01a282b7747d96ffdad324e774087c4a35197e99016bca62541af26eab4104db43666cf4206e7848aaaf551e2ea6af2488b23046c155f1456d0dd175c782eef61acc42ededcd45a37012c7e096125e356c839e9c0a5f9c75d48aeddcad671253aeffffffff02400d0300000000001976a9140930f90fe591bf98350dbf21a9e52a25cd2bfbd588ac98ae955a0000000017a914e78d4c143f67da579214af60bd4a94fad4e086d5870000000001000000'],
 'tx': {'addresses': ['mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a',
                      '2NEMZM6bLwdT18sKSrnfXcdcdGfqgccc9Qj'],
        'block_height': -1,
        'block_index': -1,
        'confidence': 0,
        'confirmations': 0,
        'double_spend': False,
        'fees': 20400,
        'hash': 'be8dd537919a337e171b47408fbf0f9d15bd33faa59fd3f5827d7cc0d14ef3ce',
        'inputs': [{'addresses': ['0471b0e83960b9a8ad980400fc7ee85e9739009f0ee08ef033784bdcefe7f38c64e9ba2b9d842089486735556e0b1940304db510ad521865bb5b028dee229c1dbd',
                                  '04a3cc3225df2ef6ca72e960c5cab0059731301d5efe61e7ffa1c4cac3a8e4994adcb27f01a282b7747d96ffdad324e774087c4a35197e99016bca62541af26eab',
                                  '04db43666cf4206e7848aaaf551e2ea6af2488b23046c155f1456d0dd175c782eef61acc42ededcd45a37012c7e096125e356c839e9c0a5f9c75d48aeddcad6712'],
                    'age': 365,
                    'output_index': 0,
                    'output_value': 1519979400,
                    'prev_hash': 'e43b339faa8ed39597132ec1b17cbc2f62b12e94bec2e0ca6599431bede6997b',
                    'script': '',
                    'script_type': 'multisig-2-of-3',
                    'sequence': 4294967295}],
        'lock_time': 0,
        'outputs': [{'addresses': ['mgMZ3UdQsEmJ1ebjRV9ibTn1DFCxgmMo7a'],
                     'script': '76a9140930f90fe591bf98350dbf21a9e52a25cd2bfbd588ac',
                     'script_type': 'pay-to-pubkey-hash',
                     'value': 200000},
                    {'addresses': ['2NEMZM6bLwdT18sKSrnfXcdcdGfqgccc9Qj'],
                     'script': 'a914e78d4c143f67da579214af60bd4a94fad4e086d587',
                     'script_type': 'pay-to-script-hash',
                     'value': 1519759000}],
        'preference': 'high',
        'received': '2016-01-14T17:17:12.766551971Z',
        'relayed_by': '207.38.134.25, '
                      '127.0.0.1',
        'size': 117,
        'total': 1519959000,
        'ver': 1,
        'vin_sz': 1,
        'vout_sz': 2}}

Next up we have to deal with signing. @gustavklopp , can you figure out how to do that from here? Relevant part of the docs here.

Basically, you want to feed into make_tx_signatures the following (notice the repeating because we want to sign it twice):

make_tx_signatures(
    txs_to_sign['35fc0f055ec9145631c6216c6cbba3d2e6f75b061b4bfb828a530c4788393608', '35fc0f055ec9145631c6216c6cbba3d2e6f75b061b4bfb828a530c4788393608']
    privkey_list=[privkey1, privkey2],
    pubkey_list=[pubkey1, pubkey2],
)

Does that make sense?

@gustavklopp
Copy link
Author

Yes, it's working! Proof: https://live.blockcypher.com/btc-testnet/tx/4e98c0c54b6ae13f934fbe59342b362fd97c604cdbd6d04623f8cb512dfcda75/ :)

I've used as you noted (example with one of the private key):

""" Siging with one of the privkey """
tx_signatures = make_tx_signatures(txs_to_sign=unsigned_tx['tosign'], privkey_list=[priv1], pubkey_list=[pub1])
print(tx_signatures)
r = broadcast_signed_transaction(unsigned_tx, tx_signatures, [pub1], coin_symbol='btc-testnet')
pprint(r)

That's very great! Thanks again a lot

@acityinohio
Copy link
Contributor

Awesome! 👍 Glad to hear it @gustavklopp and @mflaxman .

Re: the error on cURL, you're right @mflaxman; any time a P2SH address is used as an input we should throw an error. I'll take a look at the transaction builder code and see if I can patch it soon. (cc @matthieu )

@mflaxman
Copy link

Glad to hear it @gustavklopp! I'm a little surprised/confused though, that code seems to show you only signing with one private key. Don't you need to sign with 2 of the 3?

Thanks @acityinohio for looking into the tx builder code.

@gustavklopp
Copy link
Author

I've signed with two of the 3, one after another. I've put only one portion of the code for the example. Sorry for the confusion

@mflaxman
Copy link

On second thought, @acityinohio , why is this a requirement? The end-user will later need those pubkeys for broadcast (and the private keys of course for signing), but at the time of generating the transaction there's no reason to require the pubkeys.

Perhaps since they'll be needed at the next step it's best to just ensure they have them at the beginning? cc @matthieu

@acityinohio
Copy link
Contributor

Unfortunately because of the nature of P2SH addresses it is required for us to have pubkeys as inputs prior to generating data for the user to sign. Remember that when you use a prior P2SH address as an input, what you are actually pushing onto the Script stack is the full multisig script as an input in the transaction, and by its nature that includes the pubkeys. Correct me if I'm wrong but I'm pretty sure we won't be able to generate the right tosign data without having the pubkeys as inputs (instead of a P2SH address). Wish it wasn't so, because it really does make things more complicated. :-/

@mflaxman
Copy link

Gotcha, thanks!

So is having the API throw an error on submitting a p2sh address (not pubkeys) still on your list?

@acityinohio
Copy link
Contributor

No prob, and yup! I was just discussing with @hbcheng the right place to put it in the code and will have a PR forthcoming; will definitely let you know when it's merged.

@mflaxman
Copy link

Thanks!

No rush, the python code isn't dependent on it. Just wanted to make it didn't fall through the cracks.

@acityinohio
Copy link
Contributor

So, I think I was slightly mistaken; apologies for the misinformation! We can't accept P2SH addresses without the corresponding script_type "multisig-n-of-m" field in the input (turns out we can in fact add the pubkeys later, prior to the /txs/send step). That said, without that "multisig-n-of-m," we wouldn't know how to properly hash the scriptSig (which is what errored in this case), so we still need slightly more info than just the script. I just submitted a patch here (not merged/deployed yet). Once deployed, it should return an error when a P2SH address is used without a corresponding script_type.

@mflaxman
Copy link

Thanks for the update @acityinohio. Hmm, based on your earlier comments I wrote the simple_spend_p2sh method to require all pubkeys:
https://github.com/blockcypher/blockcypher-python/pull/40/files#diff-c1077949a462f79efc62028519405cbaR1913

If I'm understanding you correctly, you are saying:

  1. All pubkeys are not strictly required on /txs/new, provided you include script_type : "multisig-n-of-m" in your input?
  2. All pubkeys (not just those used in tx signing) are required when you get to /txs/send?

Can you please confirm? I don't know the p2sh protocol that well, but this doesn't sound correct. In practical terms, imagine the scenario where people A, B, and C provide their own keys to create a 2 of 3 p2sh address. Person A loses their keys, so when they want to spend funds controlled by that p2sh address, person B & C go to sign a transaction. If and 2 are correct, you are saying that unless someone kept a copy of person A's pubkey the funds would not be recoverable. In a 2-of-3 multisig, that's quite confusing.

@acityinohio
Copy link
Contributor

Best practice is definitely to use all pubkeys as address inputs for /txs/new. But as long as the user correctly specifies "script_type": "multisig-n-of-m" (and uses the correct n and m, e.g. multisig-2-of-3) with the P2SH address as an input, they should be able to get the right data to sign. In the subsequent /txs/send they will have to include every public key for every P2SH UTXO they are spending

On your scenario, that's (sadly) actually correct; if you lose A's pubkey, the funds are, in fact, undependable. :( That's because the ScriptSig (aka the unlocking script on a transaction input) contains the full Redeem Script, which includes all three pubkeys, in this form:

OP_2 [A's pubkey] [B's pubkey] [C's pubkey] OP_3 OP_CHECKMULTISIG

P2SH redeem script described here: https://bitcoin.org/en/developer-guide#term-redeem-script

My original confusion was that I believed that you needed the Redeem Script to generate the data to sign, but I forgot that you actually remove all ScriptSigs before signing (which includes the Redeem Script). Sorry for the mix-up, but I actually think your simple_spend_p2sh follows the right course of action; you'll need all the pubkeys anyway when you broadcast.

@mflaxman
Copy link

Thanks @acityinohio , that was a perfect answer!

@kumrzz
Copy link

kumrzz commented Jun 10, 2016

hey @acityinohio , it seems I am having to supply an API token to be able to use create_unsigned_tx() :

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet', include_tosigntx=True, api_key='blah')

(or else it fails complaining'No API token supplied')
... given this is not actually hitting the blockchain, don't you think its a bit OTT to require a token ?

@mflaxman
Copy link

It requires an API token because Blockcypher is fetching all the UTXOs
and selecting which ones to include in the transaction. Then Blockcypher
builds an unsigned TX to verify client side.

Does that make sense?

On Friday, June 10, 2016, Kumar Ghosh notifications@github.com wrote:

hey @acityinohio https://github.com/acityinohio , it seems I am having
to supply an API token to be able to use create_unsigned_tx() :

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs,
coin_symbol='btc-testnet', include_tosigntx=True, api_key='blah')

(or else it fails complaining'No API token supplied')
... given this is not actually hitting the blockchain, don't you think its
a bit OTT to require a token ?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#28 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAbYhPjwyyN6tkLd_S48kRFggGsbPNNFks5qKSkJgaJpZM4HEFtt
.

Sent from my iPhone

@kumrzz
Copy link

kumrzz commented Jun 11, 2016

yes absolutely mate, sorry that was a bit of a dumb question :s

@acityinohio
Copy link
Contributor

'sallgood @kumrzz! no such thing, always good to have opportunities for clarification. 👍

@RamiJaloudi
Copy link

I'm getting an assertion error:
C:\Users\RJalo\Desktop>python 2of3aaa2.py
Traceback (most recent call last):
File "2of3aaa2.py", line 48, in
tx_signatures = make_tx_signatures(txs_to_sign=unsigned_tx['tosign'], privkey_list=privkey_list, pubkey_list=pubkey_list)
File "C:\Users\RJalo\AppData\Local\Programs\Python\Python37-32\lib\site-packages\blockcypher\api.py", line 1843, in make_tx_signatures
assert len(privkey_list) == len(pubkey_list) == len(txs_to_sign)
AssertionError
#############################################################

import blockcypher

#personalWallet = {
 #   'address': 'mtiM4kphi8w9NweV8PRfJ6TBrs2cL5EscR',
 #   'private': '93S742e5hYWib7K8RC2o7pkK8xBwmAenrWwHxSRc6ZP27cDUbnU'
#}

#multisigKeys = [{
 #   'address': 'n2GFJcivbiuLy3gwa4RwUZknWrWNaKosF8',
 #   'private': '91eo9h9J5h2mgHpW4PjH4cE5UATTRkcWaynw2CvQp7q8F6shnE7', #n2GFJcivbiuLy3gwa4RwUZknWrWNaKosF8
#	#0326de79e072071956c07e39802bf4e692e1cbc570cbd3e9814e5e9b
#},{
#    'address': 'mxXpdrr1DFVNPpdXH1yzeLje9JF8TuFbvB',
#    'private': '92QmukWsv3TCNDgRccQ88vqfyEFN5zQMSYRnwC2rDxUn8eet4ay', #mxXpdrr1DFVNPpdXH1yzeLje9JF8TuFbvB
	##bc4dc326544eefc43c7cecad68c06b4ea7faa953bb944b4854134556
#},{
 #   'address': 'ms3K4ANfmBS3neNKbfSehMhX2dHWXkZgu6',
 #   'private': '91yoRoGbSBcRJVCYxWEwLtDuMj3SzvMg4cm9q7KqgzuhGiwSS6G', #ms3K4ANfmBS3neNKbfSehMhX2dHWXkZgu6
#	#e679aa2cf91fa54728d2d82cad72ec5223e1ba2851f3d0c6c49fbaea
#}]


finalDestinationAddress = 'mxdNW2wKGafADgYpxWo2LBp6t3VfnCqt9J'

apiKey = 'eaacdbb026814590acb6ce47918209f0'

# Get Details for personal wallet
#getWalletDetails = lambda x : blockcypher.get_address_overview(x, coin_symbol='btc-testnet')
#getWalletDetails(personalWallet['address'])

#[ getWalletDetails(x['address']) for x in multisigKeys ]
#apiKey = 'eaacdbb026814590acb6ce47918209f0'


dest_addr = "mxdNW2wKGafADgYpxWo2LBp6t3VfnCqt9J"

priv1 = "93S742e5hYWib7K8RC2o7pkK8xBwmAenrWwHxSRc6ZP27cDUbnU"
pub1 = "044D88423A9AAECC0019854E0241A3625342AA924E2A026248BC5E823407B31A579B156A8A5FD691B50A3F705E56848494E1BE896B90A6617F380AC99808982606"
addr1 = "mtiM4kphi8w9NweV8PRfJ6TBrs2cL5EscR"

priv2 = "91eo9h9J5h2mgHpW4PjH4cE5UATTRkcWaynw2CvQp7q8F6shnE7"
pub2 = '047E3B25401017ED57934CA40AA74B99CDA432BF33FBBD2BD03D3366BE2233BEEE5C13C3BA4BC4987403F504B45E2B15942B3FB59ECF485AB1D45C0E5B98675626'
addr2 = 'n2GFJcivbiuLy3gwa4RwUZknWrWNaKosF8'

priv3 = "91yoRoGbSBcRJVCYxWEwLtDuMj3SzvMg4cm9q7KqgzuhGiwSS6G"
pub3 = '0424094D9B0D12220F7CA1794ECB999F6A3B369DC8C09CEB25BEFF01CCED0E1C1F1FF3C2761EF32CF1025ADC427FD0A1175241E94A5D78F2EEDB51AAA258DC3ED8'
addr3 = 'ms3K4ANfmBS3neNKbfSehMhX2dHWXkZgu6'

#pubkey_list = [pub1, pub2, pub3]
#multisig = generate_multisig_address(pubkey_list, coin_symbol='btc-testnet')
# so we got:
multisig_addr = 'mxdNW2wKGafADgYpxWo2LBp6t3VfnCqt9J'

from blockcypher import create_unsigned_tx, make_tx_signatures, broadcast_signed_transaction

inputs = [{'address':multisig_addr}]
outputs = [{'address': dest_addr, 'value':200000 }]

unsigned_tx = create_unsigned_tx(inputs=inputs, outputs=outputs, coin_symbol='btc-testnet', api_key=apiKey)
# pprint(unsigned_tx)

privkey_list = [priv1]
pubkey_list = [pub1]

tx_signatures = make_tx_signatures(txs_to_sign=unsigned_tx['tosign'], privkey_list=privkey_list, pubkey_list=pubkey_list)

r = broadcast_signed_transaction(unsigned_tx, tx_signatures, pubkey_list, coin_symbol='btc-testnet', api_key=apiKey)
print(r)

@agrawalnandini
Copy link

How to spend a particular UTXOs for a Multisig address? If I give the previous hash and output index as input it doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants