def _sync_to_hardware_wallet_loop(self): bitcointx.select_chain_params(self.network) while True: try: self._sync_to_hardware_wallet() except SerialException: pass
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')
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
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.')
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.')
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')
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')
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')
def tearDown(self) -> None: select_chain_params(self.current_params)
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)
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("=============================================================")
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.
'--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')
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!')
def tearDownClass(cls): bitcointx.select_chain_params(cls._prev_chain_params)
def setUpClass(cls): logging.basicConfig() cls._prev_chain_params = bitcointx.get_current_chain_params() bitcointx.select_chain_params('elements')
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
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
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:
# 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
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 :-)')