Exemplo n.º 1
0
 def _sync_to_hardware_wallet_loop(self):
     bitcointx.select_chain_params(self.network)
     while True:
         try:
             self._sync_to_hardware_wallet()
         except SerialException:
             pass
Exemplo n.º 2
0
 async def async_mainnet() -> None:
     select_chain_params('bitcoin/mainnet')
     await wait_async('testnet')
     a = P2PKHCoinAddress.from_pubkey(pub)
     assert CBase58Data(str(a))[0] == 0
     check_core_modules()
     ready('mainnet')
     finish('mainnet')
     self.assertEqual(get_current_chain_params().NAME, 'bitcoin')
Exemplo n.º 3
0
 def _sync_to_blockchain_loop(self):
     bitcointx.select_chain_params(self.network)
     while True:
         try:
             if WalletFile.exists():
                 self._sync_to_blockchain()
                 sleep(5)
         except ConnectionError:
             pass
Exemplo n.º 4
0
def try_reclaim_btc(say, btc_rpc, txid, btc_contract, key, die):

    ensure_rpc_connected(say, btc_rpc)

    # we won't return from this function, so we can just
    # set the chain with select_chain_params
    select_chain_params(bitcoin_chain_name)

    def custom_die(msg):
        say(msg)
        die('Failed to reclaim my Bitcoin')

    from_addr = P2WSHCoinAddress.from_redeemScript(btc_contract)

    say('Will try to reclaim my bitcoin from {}'.format(from_addr))

    tx_json = btc_rpc.getrawtransaction(txid, 1)
    confirmations = int(tx_json['confirmations'])

    while confirmations < bitcoin_contract_timeout:
        tx_json = btc_rpc.getrawtransaction(txid, 1)
        confirmations = int(tx_json['confirmations'])

    for vout in tx_json['vout']:
        if 'scriptPubKey' in vout:
            if str(from_addr) in vout['scriptPubKey']['addresses']:
                vout_n = int(vout['n'])
                say('({} at UTXO {}:{})'.format(vout['value'], txid, vout_n))
                break
    else:
        custom_die(
            'Cannot find {} in outputs of tx {} - this must be a bug.'.format(
                from_addr, txid))

    # We should not use CBitcoinAddress directly here, because we might be
    # in regtest or testnet, and it is treated as different chain.
    # CBitcoinAddress will not recognize regtest address, you would need
    # to use CBitcoinTestnetAddress/CBitcoinRegtestAddress.
    # CCoinAddress is the correct abstraction to use.
    dst_addr = CCoinAddress(btc_rpc.getnewaddress())

    say('Will reclaim my Bitcoin to {}'.format(dst_addr))
    reclaim_tx = create_btc_spend_tx(dst_addr,
                                     txid,
                                     vout_n,
                                     btc_contract,
                                     spend_key=key,
                                     branch_condition=False)

    say('Sending my Bitcoin-reclaim transaction')
    new_txid = btc_rpc.sendrawtransaction(b2x(reclaim_tx.serialize()))

    wait_confirm(say, 'Bitcoin', new_txid, custom_die, btc_rpc, num_confirms=3)

    say('Reclaimed my Bitcoin. Swap failed.')
Exemplo n.º 5
0
def try_reclaim_elt(say, elt_rpc, txid, elt_contract, key, blinding_key, die):

    ensure_rpc_connected(say, elt_rpc)

    # we won't return from this function, so we can just
    # set the chain with select_chain_params
    select_chain_params(elements_chain_name)

    from_addr = P2SHCoinAddress.from_redeemScript(elt_contract)

    say('Will try to reclaim my Elements bitcoin asset from {}'.format(
        from_addr))

    tx_json = elt_rpc.getrawtransaction(txid, 1)
    confirmations = int(tx_json['confirmations'])

    while confirmations < elements_contract_timeout:
        tx_json = elt_rpc.getrawtransaction(txid, 1)
        confirmations = int(tx_json['confirmations'])

    commit_tx = CElementsTransaction.deserialize(x(tx_json['hex']))

    vout_n, unblind_result = find_and_unblind_vout(say, commit_tx, from_addr,
                                                   blinding_key, die)

    dst_addr = CElementsAddress(elt_rpc.getnewaddress())

    say('Will reclaim my Elements asset to {}'.format(dst_addr))
    reclaim_tx = create_elt_spend_tx(
        dst_addr,
        txid,
        vout_n,
        elt_contract,
        die,
        spend_key=key,
        blinding_factor=unblind_result.blinding_factor,
        asset_blinding_factor=unblind_result.asset_blinding_factor,
        branch_condition=False)

    say('Sending my Elements-reclaim transaction')
    new_txid = elt_rpc.sendrawtransaction(b2x(reclaim_tx.serialize()))

    def custom_die(msg):
        say(msg)
        die('Failed to reclaim by Elemets asset')

    wait_confirm(say,
                 'Elements',
                 new_txid,
                 custom_die,
                 elt_rpc,
                 num_confirms=3)

    say('Reclaimed my Elements asset. Swap failed.')
Exemplo n.º 6
0
 async def async_testnet() -> None:
     select_chain_params('bitcoin/testnet')
     await wait_async('regtest')
     a = P2SHCoinAddress.from_redeemScript(
         CScript(b'\xa9' + Hash160(pub) + b'\x87'))
     assert CBase58Data(str(a))[0] == 196
     check_core_modules()
     ready('testnet')
     await wait_async('mainnet')
     self.assertEqual(get_current_chain_params().NAME,
                      'bitcoin/testnet')
     finish('testnet')
Exemplo n.º 7
0
 async def async_regtest() -> None:
     select_chain_params('bitcoin/regtest')
     a = P2WPKHCoinAddress.from_pubkey(pub)
     witver, data = bitcointx.segwit_addr.decode(
         P2WPKHBitcoinRegtestAddress.bech32_hrp, str(a))
     assert witver == 0
     assert data == Hash160(pub)
     check_core_modules()
     ready('regtest')
     await wait_async('testnet')
     await wait_async('mainnet')
     self.assertEqual(get_current_chain_params().NAME,
                      'bitcoin/regtest')
     finish('regtest')
Exemplo n.º 8
0
    def __init__(self, watch_only_wallet: WatchOnlyWallet):
        super().__init__()
        self.network = Config.get_network()
        bitcointx.select_chain_params(self.network)

        self.watch_only_wallet = watch_only_wallet
        self.blockchain_client = BlockchainClient(self.network)
        self.fee_estimation_client = FeeEstimationClient()
        self.tx_broadcast_client = TxBroadcastClient(self.network)
        self.serial_client = SerialClient(self.network)

        # Wallet is already set up
        if WalletFile.exists():
            self.watch_only_wallet.load(*WalletFile.load())
        # Wallet already got HD keys from the hardware wallet, but haven't
        # properly recovered balances on this side
        elif HardwareWalletFile.exists():
            self.recover_wallet(HardwareWalletFile.load_candidate_wallets(),
                                HardwareWalletFile.load_master_fingerprint())
 def setUpClass(cls) -> None:
     cls._prev_chain_params = bitcointx.get_current_chain_params(
     )  # type: ignore
     bitcointx.select_chain_params('elements')
Exemplo n.º 10
0
 def tearDown(self) -> None:
     select_chain_params(self.current_params)
Exemplo n.º 11
0
 def test_select_chain_params(self) -> None:
     prev_params, cur_params = select_chain_params('bitcoin/regtest')
     assert isinstance(prev_params, BitcoinMainnetParams)
     assert isinstance(cur_params, BitcoinRegtestParams)
Exemplo n.º 12
0
def main():
    """The main function prepares everyting for two participant processes
    to operate and communicate with each other, and starts them"""

    global console_lock
    global fee_asset

    if len(sys.argv) != 4:
        sys.stderr.write(
            "usage: {} <alice-daemon-dir> <bob-daemon-dir> <fee_asset_hex>\n".
            format(sys.argv[0]))
        sys.exit(-1)

    elements_config_path1 = os.path.join(sys.argv[1], 'elements.conf')
    if not os.path.isfile(elements_config_path1):
        sys.stderr.write(
            'config file {} not found or is not a regular file\n'.format(
                elements_config_path1))
        sys.exit(-1)

    elements_config_path2 = os.path.join(sys.argv[2], 'elements.conf')
    if not os.path.isfile(elements_config_path2):
        sys.stderr.write(
            'config file {} not found or is not a regular file\n'.format(
                elements_config_path2))
        sys.exit(-1)

    try:
        fee_asset = CAsset(lx(sys.argv[3]))
    except ValueError as e:
        sys.stderr.write('specified fee asset is not valid: {}\n'.format(e))
        sys.exit(-1)

    # Initialize console lock
    console_lock = Lock()

    # Switch the chain parameters to Elements.
    # The setting should remain in place for child processes.
    select_chain_params('elements')

    # Create a pipe for processes to communicate
    pipe1, pipe2 = Pipe(duplex=True)

    # Create process to run 'alice' participant function
    # and pass it one end of a pipe, and path to config file for node1
    p1 = Process(target=participant,
                 name='alice',
                 args=(alice, 'Alice', pipe1, elements_config_path1))

    # Create process to run 'bob' participant function
    # and pass it one end of a pipe, and path to config file for node2
    p2 = Process(target=participant,
                 name='bob',
                 args=(bob, '  Bob', pipe2, elements_config_path2))

    # Start both processes
    p1.start()
    p2.start()

    # The childs are on their own now. We just wait for them to finish.
    try:
        p1.join()
        p2.join()
    except KeyboardInterrupt:
        print()
        print("=============================================================")
        print("Interrupted from keyboard, terminating participant processes.")
        print("-------------------------------------------------------------")
        for p in (p1, p2):
            if p.is_alive():
                print('terminating', p.name)
                p.terminate()
            else:
                print(p.name, 'is not alive')
            p.join()
        print('Exiting.')
        print("=============================================================")
Exemplo n.º 13
0
from bitcointx import select_chain_params
from bitcointx.core import x, satoshi_to_coins
from bitcointx.wallet import CCoinKey, CCoinAddress
from elementstx.core import CElementsTransaction
from elementstx.wallet import CCoinConfidentialAddress


if __name__ == '__main__':
    if len(sys.argv) != 3:
        print("usage: {} <raw-hex-tx-file> <blinding-key-file>"
              .format(sys.argv[0]))
        sys.exit(-1)

    # Switch the chain parameters to Elements
    select_chain_params('elements/liquidv1')

    # Read in and decode the blinded transaction.
    # expected to be hex-encoded as one line.
    
    f = sys.argv[1]
    #with open(sys.argv[1]) as f:
        # We could use CTransaction here, but if we want to
        # use mypy to do static checking, we need to use the elements-specific
        # classes. mypy does cannot know about dynamic class dispatch.
    #tx = CElementsTransaction.deserialize(x(f.readline().rstrip()))                                                                                                     [16/1870]
    tx = CElementsTransaction.deserialize(x(f))


    # Read in the blinding key, expected to be in WIF format.
    
Exemplo n.º 14
0
                        '--testnet',
                        action='store_true',
                        dest='testnet',
                        help='Use testnet')
    parser.add_argument('-r',
                        '--regtest',
                        action='store_true',
                        dest='regtest',
                        help='Use regtest')
    return parser


if __name__ == '__main__':
    args = parser().parse_args()
    if args.testnet:
        select_chain_params('bitcoin/testnet')
    elif args.regtest:
        select_chain_params('bitcoin/regtest')

    if args.input_file == '-':
        psbt_data = sys.stdin.read()
    else:
        with open(args.input_file, 'r') as f:
            psbt_data = f.read()

    path_template = None
    require_path_templates = True
    if args.path_template is not None:
        if args.without_path_template_checks:
            print('--without-path-template-checks conflicts with '
                  '--path-template argument')
Exemplo n.º 15
0
def alice(say, recv, send, die, btc_rpc, elt_rpc):
    """A function that implements the logic
    of the Elements-side participant
    of confidential cross-chain atomic swap"""

    global last_wish_func

    # Default chain for Alice will be Elements
    # To handle bitcoin-related objects, either
    # `with ChainParams(bitcoin_chain_name):` have to be used, or
    # concrete classes, like CBitcoinAddress, CBitcoinTransaction, etc.
    select_chain_params(elements_chain_name)

    # Let's create the shared blinding key
    blinding_key = CKey.from_secret_bytes(os.urandom(32))
    # And the key for btc spend
    alice_btc_key = CKey.from_secret_bytes(os.urandom(32))
    # And the key for the 'timeout' branch of the contract
    alice_elt_exit_key = CKey.from_secret_bytes(os.urandom(32))

    say('Sending pubkeys to Bob')
    send('pubkeys', (alice_btc_key.pub, alice_elt_exit_key.pub))

    say('Sending the blinding key to Bob')
    send('blinding_key', blinding_key.secret_bytes)

    (contract_pubkey_raw, bob_elt_pubkey_raw,
     bob_btc_exit_pub_raw) = recv('pubkeys')

    say("Pubkey of the key to be revealed: {}".format(
        b2x(contract_pubkey_raw)))
    say("Bob's Elements-side pubkey: {}".format(b2x(bob_elt_pubkey_raw)))

    contract_pubkey = CPubKey(contract_pubkey_raw)

    key_to_reveal_pub = CPubKey.add(contract_pubkey, blinding_key.pub)

    elt_contract = make_elt_cntract(key_to_reveal_pub, bob_elt_pubkey_raw,
                                    alice_elt_exit_key.pub)

    elt_contract_addr = P2SHCoinAddress.from_redeemScript(elt_contract)

    confidential_contract_addr = P2SHCoinConfidentialAddress.from_unconfidential(
        elt_contract_addr, blinding_key.pub)
    assert isinstance(confidential_contract_addr, CElementsConfidentialAddress)

    say("Created Elemets-side swap contract, size: {}".format(
        len(elt_contract)))
    say("Contract address:\n\tconfidential: {}\n\tunconfidential: {}".format(
        confidential_contract_addr, elt_contract_addr))

    btc_txid = recv('btc_txid')

    combined_btc_spend_pubkey = CPubKey.add(contract_pubkey, alice_btc_key.pub)
    btc_contract = make_btc_contract(combined_btc_spend_pubkey,
                                     bob_btc_exit_pub_raw)

    tx_json = btc_rpc.getrawtransaction(btc_txid, 1)

    if tx_json['confirmations'] < 6:
        die('Transaction does not have enough confirmations')

    # We use ChainParams, and not P2WSHBitcoinAddress here,
    # because bitcoin_chain_name might be 'bitcoin/regtest', for example,
    # and then the address would need to be P2WSHBitcoinRegtestAddress.
    # with ChainParams we leverage the 'frontend class' magic, P2WSHCoinAddress
    # will give us appropriate instance.
    with ChainParams(bitcoin_chain_name):
        btc_contract_addr = P2WSHCoinAddress.from_redeemScript(btc_contract)
        say('Looking for this address in transaction {} in Bitcoin'.format(
            btc_txid))

    # CTransaction subclasses do not change between mainnet/testnet/regtest,
    # so we can directly use CBitcoinTransaction.
    # That might not be true for other chains, though.
    # You might also want to use CTransaction within `with ChainParams(...):`
    btc_tx = CBitcoinTransaction.deserialize(x(tx_json['hex']))

    for n, vout in enumerate(btc_tx.vout):
        if vout.scriptPubKey == btc_contract_addr.to_scriptPubKey():
            say("Found the address at output {}".format(n))
            btc_vout_n = n
            break
    else:
        die('Did not find contract address in transaction')

    if vout.nValue != coins_to_satoshi(pre_agreed_amount):
        die('the amount {} found at the output in the offered transaction '
            'does not match the expected amount {}'.format(
                satoshi_to_coins(vout.nValue), pre_agreed_amount))

    say('Bitcoin amount match expected values')

    say('Sending {} to {}'.format(pre_agreed_amount,
                                  confidential_contract_addr))
    contract_txid = elt_rpc.sendtoaddress(str(confidential_contract_addr),
                                          pre_agreed_amount)

    def alice_last_wish_func():
        try_reclaim_elt(say, elt_rpc, contract_txid, elt_contract,
                        alice_elt_exit_key, blinding_key, die)

    last_wish_func = alice_last_wish_func

    wait_confirm(say, 'Elements', contract_txid, die, elt_rpc, num_confirms=2)

    send('elt_txid', contract_txid)

    sr_txid = wait_spend_reveal_transaction(say, contract_txid, die, elt_rpc)

    say('Got txid for spend-reveal transaction from Bob ({})'.format(sr_txid))

    tx_json = elt_rpc.getrawtransaction(sr_txid, 1)

    wait_confirm(say, 'Elements', sr_txid, die, elt_rpc, num_confirms=2)

    sr_tx = CTransaction.deserialize(x(tx_json['hex']))

    for n, vin in enumerate(sr_tx.vin):
        if vin.prevout.hash == lx(contract_txid)\
                and vin.scriptSig[-(len(elt_contract)):] == elt_contract:
            say('Transaction input {} seems to contain a script '
                'we can recover the key from'.format(n))
            reveal_script_iter = iter(vin.scriptSig)
            break
    else:
        die('Spend-reveal transaction does not have input that spends '
            'the contract output')

    next(reveal_script_iter)  # skip Bob's spend signature

    try:
        # 2 skipped bytes are tag and len
        sig_s = ecdsa.util.string_to_number(next(reveal_script_iter)[2:])
    except (ValueError, StopIteration):
        die('Reveal script is invalid')

    k, r = get_known_k_r()
    order = ecdsa.SECP256k1.order
    mhash = ecdsa.util.string_to_number(hashlib.sha256(b'\x01').digest())
    r_inverse = ecdsa.numbertheory.inverse_mod(r, order)

    for s in (-sig_s, sig_s):
        secret_exponent = (((s * k - mhash) % order) * r_inverse) % order

        recovered_key = CKey.from_secret_bytes(
            ecdsa.util.number_to_string(secret_exponent, order))

        if recovered_key.pub == key_to_reveal_pub:
            break
    else:
        die('Key recovery failed. Should not happen - the sig was already '
            'verified when transaction was accepted into mempool. '
            'Must be a bug.')

    say('recovered key pubkey: {}'.format(b2x(recovered_key.pub)))
    contract_key = CKey.sub(recovered_key, blinding_key)
    say('recovered unblined key pubkey: {}'.format(b2x(contract_key.pub)))
    combined_btc_spend_key = CKey.add(contract_key, alice_btc_key)

    say('Successfully recovered the key. Can now spend Bitcoin from {}'.format(
        btc_contract_addr))

    with ChainParams(bitcoin_chain_name):
        dst_addr = CCoinAddress(btc_rpc.getnewaddress())
        btc_claim_tx = create_btc_spend_tx(dst_addr,
                                           btc_txid,
                                           btc_vout_n,
                                           btc_contract,
                                           spend_key=combined_btc_spend_key)

    say('Sending my Bitcoin-claim transaction')
    btc_claim_txid = btc_rpc.sendrawtransaction(b2x(btc_claim_tx.serialize()))

    wait_confirm(say, 'Bitcoin', btc_claim_txid, die, btc_rpc, num_confirms=3)

    say('Got my Bitcoin. Swap successful!')
Exemplo n.º 16
0
 def tearDownClass(cls):
     bitcointx.select_chain_params(cls._prev_chain_params)
Exemplo n.º 17
0
 def setUpClass(cls):
     logging.basicConfig()
     cls._prev_chain_params = bitcointx.get_current_chain_params()
     bitcointx.select_chain_params('elements')
Exemplo n.º 18
0
import sys

PATH_TO_FUNCTIONAL = "~/bitcoin/test/functional"
PATH_TO_BITCOINTX = "~/python-bitcointx"
TEST_DATADIR = "tests/data"

sys.path.insert(0, PATH_TO_BITCOINTX)
sys.path.insert(0, PATH_TO_FUNCTIONAL)

from bitcointx import select_chain_params
from bitcointx.core import coins_to_satoshi

select_chain_params("bitcoin/regtest")

MIN_FEE = coins_to_satoshi(0.00000169)
TIMELOCK = 3
PORTION_TO_VAULT = 0.1
Exemplo n.º 19
0
from elementstx.core import (CConfidentialValue, CConfidentialAsset,
                             BlindingInputDescriptor, CElementsTransaction,
                             CElementsTxOut, CElementsMutableTxOut,
                             CElementsTxInWitness, BlindingSuccess)
from elementstx.core import CElementsScript
from elementstx.wallet import CCoinConfidentialAddress, CElementsAddress

if __name__ == '__main__':
    if len(sys.argv) not in (5, 6):
        sys.stderr.write(
            "usage: {} <raw-hex-tx-file> <spending-key-wif-file> <unblinding-key-hex-file> <destination-address> [chainparams]\n"
            .format(sys.argv[0]))
        sys.exit(-1)

    if len(sys.argv) == 6:
        select_chain_params(sys.argv[5])
        if not isinstance(get_current_chain_params(), ElementsParams):
            print('specified chainparams is not Elements-compatible')
            sys.exit(-1)
    else:
        # Switch the chain parameters to Elements
        select_chain_params('elements')

    # Read in and decode the blinded transaction.
    # expected to be hex-encoded as one line.
    with open(sys.argv[1]) as f:
        # We could use CTransaction here, but if we want to
        # use mypy to do static checking, we need to use the elements-specific
        # classes. mypy does cannot know about dynamic class dispatch.
        input_tx = CElementsTransaction.deserialize(x(f.readline().rstrip()))
 def setUpClass(cls) -> None:
     logging.basicConfig()
     cls._prev_chain_params = bitcointx.get_current_chain_params(
     )  # type: ignore
     bitcointx.select_chain_params('elements')
 def setUpClass(cls):
     cls._prev_chain_params = bitcointx.get_current_chain_params()
     bitcointx.select_chain_params('elements')
 def tearDownClass(cls) -> None:
     bitcointx.select_chain_params(cls._prev_chain_params)  # type: ignore
Exemplo n.º 23
0
                                   SIGHASH_ALL, SIGVERSION_WITNESS_V0, OP_DUP,
                                   OP_EQUALVERIFY, OP_HASH160, OP_CHECKSIG)
from elementstx.core import (CConfidentialValue, CConfidentialAsset,
                             BlindingInputDescriptor, CElementsTransaction,
                             CElementsTxOut, CElementsMutableTxOut)
from elementstx.wallet import CCoinConfidentialAddress, CElementsAddress

if __name__ == '__main__':
    if len(sys.argv) != 5:
        sys.stderr.write(
            "usage: {} <raw-hex-tx-file> <spending-key-wif-file> <unblinding-key-hex-file> <destination-address>\n"
            .format(sys.argv[0]))
        sys.exit(-1)

    # Switch the chain parameters to Elements
    select_chain_params('elements')

    # Read in and decode the blinded transaction.
    # expected to be hex-encoded as one line.
    with open(sys.argv[1]) as f:
        # We could use CTransaction here, but if we want to
        # use mypy to do static checking, we need to use the elements-specific
        # classes. mypy does cannot know about dynamic class dispatch.
        input_tx = CElementsTransaction.deserialize(x(f.readline().rstrip()))

    # Read in the key, expected to be in WIF format.
    with open(sys.argv[2]) as f:
        key = CCoinKey(f.readline().rstrip())

    # Read in the unblinding key, expected to be in HEX format.
    with open(sys.argv[3]) as f:
Exemplo n.º 24
0
# No part of python-bitcointx, including this file, may be copied, modified,
# propagated, or distributed except according to the terms contained in the
# LICENSE file.
"""Low-level example of how to spend a standard
pay-to-pubkey-hash (P2PKH) txout"""

import hashlib

from bitcointx import select_chain_params
from bitcointx.core import (b2x, lx, COutPoint, CMutableTxOut, CMutableTxIn,
                            CMutableTransaction, CoreCoinParams)
from bitcointx.core.script import CScript, SignatureHash, SIGHASH_ALL
from bitcointx.core.scripteval import VerifyScript
from bitcointx.wallet import CBitcoinAddress, P2PKHBitcoinAddress, CBitcoinKey

select_chain_params('bitcoin')

COIN = CoreCoinParams.COIN

# Create the (in)famous correct brainwallet secret key.
h = hashlib.sha256(b'correct horse battery staple').digest()
seckey = CBitcoinKey.from_secret_bytes(h)

# Same as the txid:vout the createrawtransaction RPC call requires
#
# lx() takes *little-endian* hex and converts it to bytes; in Bitcoin
# transaction hashes are shown little-endian rather than the usual big-endian.
# There's also a corresponding x() convenience function that takes big-endian
# hex and converts it to bytes.
txid = lx('7e195aa3de827814f172c362fcf838d92ba10e3f9fdd9c3ecaf79522b311b22d')
vout = 0
Exemplo n.º 25
0
def bob(say, recv, send, die, btc_rpc, elt_rpc):
    """A function that implements the logic
    of the Bitcoin-side participant
    of confidential cross-chain atomic swap"""

    global last_wish_func

    # Default chain for Bob will be Bitcoin
    # To handle bitcoin-related objects, either
    # `with ChainParams(elements_chain_name):` have to be used, or
    # concrete classes, like CElementsAddress, CElementsTransaction, etc.
    select_chain_params(bitcoin_chain_name)

    say('Waiting for blinding key from Alice')
    alice_btc_pub_raw, alice_elt_exit_pub_raw = recv('pubkeys')

    blinding_key = CKey.from_secret_bytes(recv('blinding_key'))
    say("Pubkey for blinding key: {}".format(b2x(blinding_key.pub)))

    # Let's create the key that would lock the coins on Bitcoin side
    contract_key = CKey.from_secret_bytes(os.urandom(32))
    # And the key for Elements side
    bob_elt_spend_key = CKey.from_secret_bytes(os.urandom(32))
    # And the key for 'timeout' case on btc side
    bob_btc_exit_key = CKey.from_secret_bytes(os.urandom(32))

    key_to_reveal_pub = CPubKey.add(contract_key.pub, blinding_key.pub)
    say("The pubkey of the combined key to be revealed: {}".format(
        b2x(key_to_reveal_pub)))

    say('Sending my pubkeys to Alice')
    send('pubkeys',
         (contract_key.pub, bob_elt_spend_key.pub, bob_btc_exit_key.pub))

    combined_btc_spend_pubkey = CPubKey.add(contract_key.pub,
                                            CPubKey(alice_btc_pub_raw))

    say('combined_btc_spend_pubkey: {}'.format(b2x(combined_btc_spend_pubkey)))
    btc_contract = make_btc_contract(combined_btc_spend_pubkey,
                                     bob_btc_exit_key.pub)

    btc_contract_addr = P2WSHCoinAddress.from_redeemScript(btc_contract)

    say("Created Bitcoin-side swap contract, size: {}".format(
        len(btc_contract)))
    say("Contract address: {}".format(btc_contract_addr))

    say('Sending {} to {}'.format(pre_agreed_amount, btc_contract_addr))
    btc_txid = btc_rpc.sendtoaddress(str(btc_contract_addr), pre_agreed_amount)

    def bob_last_wish_func():
        try_reclaim_btc(say, btc_rpc, btc_txid, btc_contract, bob_btc_exit_key,
                        die)

    last_wish_func = bob_last_wish_func

    wait_confirm(say, 'Bitcoin', btc_txid, die, btc_rpc, num_confirms=6)

    send('btc_txid', btc_txid)
    elt_txid = recv('elt_txid')

    elt_contract = make_elt_cntract(key_to_reveal_pub, bob_elt_spend_key.pub,
                                    alice_elt_exit_pub_raw)

    with ChainParams(elements_chain_name):
        elt_contract_addr = P2SHCoinAddress.from_redeemScript(elt_contract)

    say('Got Elements contract address from Alice: {}'.format(
        elt_contract_addr))
    say('Looking for this address in transaction {} in Elements'.format(
        elt_txid))

    tx_json = elt_rpc.getrawtransaction(elt_txid, 1)

    if tx_json['confirmations'] < 2:
        die('Transaction does not have enough confirmations')

    elt_commit_tx = CElementsTransaction.deserialize(x(tx_json['hex']))

    vout_n, unblind_result = find_and_unblind_vout(say, elt_commit_tx,
                                                   elt_contract_addr,
                                                   blinding_key, die)

    if unblind_result.amount != coins_to_satoshi(pre_agreed_amount):
        die('the amount {} found at the output in the offered transaction '
            'does not match the expected amount {}'.format(
                satoshi_to_coins(unblind_result.amount), pre_agreed_amount))

    say('The asset and amount match expected values. lets spend it.')

    with ChainParams(elements_chain_name):
        dst_addr = CCoinAddress(elt_rpc.getnewaddress())
        assert isinstance(dst_addr, CCoinConfidentialAddress)

        say('I will claim my Elements-BTC to {}'.format(dst_addr))

        elt_claim_tx = create_elt_spend_tx(
            dst_addr,
            elt_txid,
            vout_n,
            elt_contract,
            die,
            spend_key=bob_elt_spend_key,
            contract_key=contract_key,
            blinding_key=blinding_key,
            blinding_factor=unblind_result.blinding_factor,
            asset_blinding_factor=unblind_result.asset_blinding_factor)

        # Cannot use VerifyScript for now,
        # because it does not support CHECKSIGFROMSTACK yet
        #
        # VerifyScript(tx.vin[0].scriptSig,
        #              elt_contract_addr.to_scriptPubKey(),
        #              tx, 0, amount=amount)

    say('Sending my spend-reveal transaction')
    sr_txid = elt_rpc.sendrawtransaction(b2x(elt_claim_tx.serialize()))

    wait_confirm(say, 'Elements', sr_txid, die, elt_rpc, num_confirms=2)

    say('Got my Elements-BTC. Swap successful (at least for me :-)')