Beispiel #1
0
class TestSignTx(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(
            self.rpc_userpass))
        if '{}_test'.format(self.type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.type), True)
        self.wrpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/{}_test'.format(
                self.rpc_userpass, self.type))
        self.wpk_rpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')

    def _test_signtx(self, input_type, multisig):
        # Import some keys to the watch only wallet and send coins to them
        keypool_desc = process_commands(
            self.dev_args +
            ['getkeypool', '--keypool', '--sh_wpkh', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = process_commands(
            self.dev_args +
            ['getkeypool', '--keypool', '--sh_wpkh', '--internal', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        # Get origin info/key pair so wallet doesn't forget how to
        # sign with keys post-import
        pubkeys = [sh_wpkh_info['desc'][8:-2],\
                wpkh_info['desc'][5:-1],\
                pkh_info['desc'][4:-1]]

        sh_multi_desc = {
            'desc':
            'sh(multi(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' + pubkeys[2] +
            '))',
            "timestamp":
            "now",
            "label":
            "shmulti"
        }
        sh_wsh_multi_desc = {
            'desc':
            'sh(wsh(multi(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' +
            pubkeys[2] + ')))',
            "timestamp":
            "now",
            "label":
            "shwshmulti"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_desc = {
            'desc':
            'wsh(multi(2,' + pubkeys[2] + ',' + pubkeys[1] + ',' + pubkeys[0] +
            '))',
            "timestamp":
            "now",
            "label":
            "wshmulti"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_desc, sh_wsh_multi_desc, wsh_multi_desc])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel("shmulti").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel("wshmulti").popitem()[0]

        send_amount = 2
        number_inputs = 0
        # Single-sig
        if input_type == 'segwit' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(sh_wpkh_addr, send_amount)
            self.wpk_rpc.sendtoaddress(wpkh_addr, send_amount)
            number_inputs += 2
        if input_type == 'legacy' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(pkh_addr, send_amount)
            number_inputs += 1
        # Now do segwit/legacy multisig
        if multisig:
            if input_type == 'legacy' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(sh_multi_addr, send_amount)
                number_inputs += 1
            if input_type == 'segwit' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(wsh_multi_addr, send_amount)
                self.wpk_rpc.sendtoaddress(sh_wsh_multi_addr, send_amount)
                number_inputs += 2

        self.wpk_rpc.generatetoaddress(6, self.wpk_rpc.getnewaddress())

        # Spend different amounts, requiring 1 to 3 inputs
        for i in range(number_inputs):
            # Create a psbt spending the above
            psbt = self.wrpc.walletcreatefundedpsbt(
                [], [{
                    self.wpk_rpc.getnewaddress(): (i + 1) * send_amount
                }], 0, {
                    'includeWatching': True,
                    'subtractFeeFromOutputs': [0]
                }, True)
            sign_res = process_commands(self.dev_args +
                                        ['signtx', psbt['psbt']])
            finalize_res = self.wrpc.finalizepsbt(sign_res['psbt'])
            self.assertTrue(finalize_res['complete'])
        self.wrpc.sendrawtransaction(finalize_res['hex'])

    # Test wrapper to avoid mixed-inputs signing for Ledger
    def test_signtx(self):
        supports_mixed = {'coldcard', 'trezor'}
        supports_multisig = {'ledger', 'trezor'}
        if self.type not in supports_mixed:
            self._test_signtx("legacy", self.type in supports_multisig)
            self._test_signtx("segwit", self.type in supports_multisig)
        else:
            self._test_signtx("all", self.type in supports_multisig)
Beispiel #2
0
class TestSignTx(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(
            self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/{}_test'.format(
                self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def tearDown(self):
        self.emulator.stop()

    def _generate_and_finalize(self, unknown_inputs, psbt):
        if not unknown_inputs:
            # Just do the normal signing process to test "all inputs" case
            sign_res = self.do_command(self.dev_args +
                                       ['signtx', psbt['psbt']])
            finalize_res = self.wrpc.finalizepsbt(sign_res['psbt'])
        else:
            # Sign only input one on first pass
            # then rest on second pass to test ability to successfully
            # ignore inputs that are not its own. Then combine both
            # signing passes to ensure they are actually properly being
            # partially signed at each step.
            first_psbt = PSBT()
            first_psbt.deserialize(psbt['psbt'])
            second_psbt = PSBT()
            second_psbt.deserialize(psbt['psbt'])

            # Blank master fingerprint to make hww fail to sign
            # Single input PSBTs will be fully signed by first signer
            for psbt_input in first_psbt.inputs[1:]:
                for pubkey, path in psbt_input.hd_keypaths.items():
                    psbt_input.hd_keypaths[pubkey] = (0, ) + path[1:]
            for pubkey, path in second_psbt.inputs[0].hd_keypaths.items():
                second_psbt.inputs[0].hd_keypaths[pubkey] = (0, ) + path[1:]

            single_input = len(first_psbt.inputs) == 1

            # Process the psbts
            first_psbt = first_psbt.serialize()
            second_psbt = second_psbt.serialize()

            # First will always have something to sign
            first_sign_res = self.do_command(self.dev_args +
                                             ['signtx', first_psbt])
            self.assertTrue(single_input == self.wrpc.finalizepsbt(
                first_sign_res['psbt'])['complete'])
            # Second may have nothing to sign (1 input case)
            # and also may throw an error(e.g., ColdCard)
            second_sign_res = self.do_command(self.dev_args +
                                              ['signtx', second_psbt])
            if 'psbt' in second_sign_res:
                self.assertTrue(not self.wrpc.finalizepsbt(
                    second_sign_res['psbt'])['complete'])
                combined_psbt = self.wrpc.combinepsbt(
                    [first_sign_res['psbt'], second_sign_res['psbt']])

            else:
                self.assertTrue('error' in second_sign_res)
                combined_psbt = first_sign_res['psbt']

            finalize_res = self.wrpc.finalizepsbt(combined_psbt)
            self.assertTrue(finalize_res['complete'])
            self.assertTrue(
                self.wrpc.testmempoolaccept([finalize_res['hex']
                                             ])[0]["allowed"])
        return finalize_res['hex']

    def _test_signtx(self, input_type, multisig):
        # Import some keys to the watch only wallet and send coins to them
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--keypool', '--sh_wpkh', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--keypool', '--sh_wpkh', '--internal', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        # Get origin info/key pair so wallet doesn't forget how to
        # sign with keys post-import
        pubkeys = [sh_wpkh_info['desc'][8:-11],\
                wpkh_info['desc'][5:-10],\
                pkh_info['desc'][4:-10]]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(multi(2,' +
                                                    pubkeys[0] + ',' +
                                                    pubkeys[1] + ',' +
                                                    pubkeys[2] +
                                                    '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo('sh(wsh(multi(2,' +
                                                        pubkeys[0] + ',' +
                                                        pubkeys[1] + ',' +
                                                        pubkeys[2] +
                                                        ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(multi(2,' +
                                                     pubkeys[2] + ',' +
                                                     pubkeys[1] + ',' +
                                                     pubkeys[0] +
                                                     '))')['descriptor']

        sh_multi_import = {
            'desc': sh_multi_desc,
            "timestamp": "now",
            "label": "shmulti"
        }
        sh_wsh_multi_import = {
            'desc': sh_wsh_multi_desc,
            "timestamp": "now",
            "label": "shwshmulti"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {
            'desc': wsh_multi_desc,
            "timestamp": "now",
            "label": "wshmulti"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel("shmulti").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel("wshmulti").popitem()[0]

        in_amt = 3
        out_amt = in_amt // 3
        number_inputs = 0
        # Single-sig
        if input_type == 'segwit' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(sh_wpkh_addr, in_amt)
            self.wpk_rpc.sendtoaddress(wpkh_addr, in_amt)
            number_inputs += 2
        if input_type == 'legacy' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(pkh_addr, in_amt)
            number_inputs += 1
        # Now do segwit/legacy multisig
        if multisig:
            if input_type == 'legacy' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(sh_multi_addr, in_amt)
                number_inputs += 1
            if input_type == 'segwit' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(wsh_multi_addr, in_amt)
                self.wpk_rpc.sendtoaddress(sh_wsh_multi_addr, in_amt)
                number_inputs += 2

        self.wpk_rpc.generatetoaddress(6, self.wpk_rpc.getnewaddress())

        # Spend different amounts, requiring 1 to 3 inputs
        for i in range(number_inputs):
            # Create a psbt spending the above
            if i == number_inputs - 1:
                self.assertTrue((i + 1) *
                                in_amt == self.wrpc.getbalance("*", 0, True))
            psbt = self.wrpc.walletcreatefundedpsbt(
                [], [{
                    self.wpk_rpc.getnewaddress('', 'legacy'): (i + 1) * out_amt
                }, {
                    self.wpk_rpc.getnewaddress('', 'p2sh-segwit'):
                    (i + 1) * out_amt
                }, {
                    self.wpk_rpc.getnewaddress('', 'bech32'): (i + 1) * out_amt
                }], 0, {
                    'includeWatching': True,
                    'subtractFeeFromOutputs': [0, 1, 2]
                }, True)

            # Sign with unknown inputs in two steps
            self._generate_and_finalize(True, psbt)
            # Sign all inputs all at once
            final_tx = self._generate_and_finalize(False, psbt)

        # Send off final tx to sweep the wallet
        self.wrpc.sendrawtransaction(final_tx)

    # Test wrapper to avoid mixed-inputs signing for Ledger
    def test_signtx(self):
        supports_mixed = {'coldcard', 'trezor_1', 'digitalbitbox', 'keepkey'}
        supports_multisig = {'ledger', 'trezor_1', 'digitalbitbox', 'keepkey'}
        if self.full_type not in supports_mixed:
            self._test_signtx("legacy", self.full_type in supports_multisig)
            self._test_signtx("segwit", self.full_type in supports_multisig)
        else:
            self._test_signtx("all", self.full_type in supports_multisig)

    # Make a huge transaction which might cause some problems with different interfaces
    def test_big_tx(self):
        # make a huge transaction that is unrelated to the hardware wallet
        outputs = []
        num_inputs = 60
        for i in range(0, num_inputs):
            outputs.append({self.wpk_rpc.getnewaddress('', 'legacy'): 0.001})
        psbt = self.wpk_rpc.walletcreatefundedpsbt([], outputs, 0, {},
                                                   True)['psbt']
        psbt = self.wpk_rpc.walletprocesspsbt(psbt)['psbt']
        tx = self.wpk_rpc.finalizepsbt(psbt)['hex']
        txid = self.wpk_rpc.sendrawtransaction(tx)
        inputs = []
        for i in range(0, num_inputs):
            inputs.append({'txid': txid, 'vout': i})
        psbt = self.wpk_rpc.walletcreatefundedpsbt(
            inputs,
            [{
                self.wpk_rpc.getnewaddress('', 'legacy'): 0.001 * num_inputs
            }], 0, {'subtractFeeFromOutputs': [0]}, True)['psbt']
        # For cli, this should throw an exception
        try:
            result = self.do_command(self.dev_args + ['signtx', psbt])
            if self.interface == 'cli':
                self.fail('Big tx did not cause CLI to error')
            if self.type == 'coldcard':
                self.assertEqual(result['code'], -7)
            else:
                self.assertNotIn('code', result)
                self.assertNotIn('error', result)
        except OSError as e:
            if self.interface == 'cli':
                pass
Beispiel #3
0
class Wallet:
    def __init__(self, network: str, datadir: str):
        global network_port_map_g, ltc_network_port_map_g, transfer_info_map_g

        self.rpc_user = input('RPC Username: '******'RPC Password: '******'Username: '******'Select Crypto(0 => Bitcoin or 1 => Litecoin): '))]
        self.rpc_port = network_port_map_g[self.crypto][network]
        self.rpc_connection = AuthServiceProxy(
            "http://%s:%[email protected]:%d" %
            (self.rpc_user, self.rpc_password, self.rpc_port),
            timeout=10000)
        self.network = network
        self.transfer_info_filepath = os.path.join(
            datadir, '%s.%s.%s.json' %
            (transfer_info_map_g[network], self.crypto, user))
        self.user = user

    def isAddressUnused(self, address: str):
        if self.crypto == 'bitcoin':
            res = requests.get('https://blockchain.info/rawaddr/' + address)
            jsonobj = json.loads(res.text)
            return (jsonobj['total_received'] == 0)

        if self.crypto == 'litecoin':
            res = requests.get('https://chain.so/api/v2/address/LTC/' +
                               address)
            jsonobj = json.loads(res.text)
            return (jsonobj['data']['total_txs'] == 0)

    def setUnusedAddresses(self):
        self.unused_list = [
            address for address in self.jsonobj['Addresses']
            if self.isAddressUnused(address) == True
        ]

    def setUnusedAddressesTest(self):
        unspent_list = self.rpc_connection.listunspent()
        if len(unspent_list) > 0:
            inuse_addresses = [unspent['address'] for unspent in unspent_list]
            index = 0
            for inuse_address in inuse_addresses:
                if inuse_address in self.jsonobj['Addresses']:
                    new_index = self.jsonobj['Addresses'].index(inuse_address)
                    index = new_index if new_index > index else index
            self.unused_list = copy(self.jsonobj['Addresses'][index + 1:])
        else:
            self.unused_list = copy(self.jsonobj['Addresses'])

#                print('unused list = %s' % self.unused_list)

    def getNextAddresses(self):
        if network == 'regtest':
            self.setUnusedAddressesTest()
        else:
            self.setUnusedAddresses()

        count = int(input('Enter Number of Unused Addresses: '))
        addresses = self.unused_list[0:count]

        return addresses

#        def getTargetAddresses(self):
#                if network == 'regtest':
#                        self.setUnusedAddressesTest()
#                else:
#                        self.setUnusedAddresses()
#
#                out_count = int(input('Enter Number of Target Addresses: '))
#
#                tx_out = []
#
#                unused_addresses = copy(self.unused_list)
#
#                for i in range(out_count):
#                        address_value = {}
#                        choice = (input('Scan QR code [Y/n]: ') or 'Y').lower()
#                        if choice == 'y':
#                                qrcode = qrutils.scanQRCode()
#                                if ':' in qrcode and qrcode.split(':')[0] != self.crypto:
#                                        print('Address belong to different cryptocurrency i.e. %s' % qrcode.split(':')[0])
#                                        exit()
#                                address = qrcode.split(':')[1].split('?')[0] if ':' in qrcode else qrcode.split('?')[0]
#                                value = float(qrcode.split('?')[1].split('=')[1]) if '?' in qrcode else float(input('Enter Btc/Ltc: '))
#                        elif choice == 'n':
#                                address = input('Enter Target Address: ')
#                                value = float(input('Enter Bitcoins: '))
#                        else:
#                                print('Invalid entry')
#                                exit()
#                        address_value[address] = value
#
#                        if address in unused_addresses:
#                                unused_addresses.remove(address)
#
#                        tx_out.append(address_value)
#
#                if len(set(tx_out)) != out_count:
#                        print('Address repetition is not allowed in target')
#                        exit()
#
#                change_address = unused_addresses[0]
#                print('change address: %s' % change_address)
#                return tx_out, change_address

    def getTargetAddresses(self):
        if network == 'regtest':
            self.setUnusedAddressesTest()
        else:
            self.setUnusedAddresses()

        out_count = int(input('Enter Number of Target Addresses: '))

        tx_out = []

        unused_addresses = copy(self.unused_list)

        tx_out = {}
        for i in range(out_count):
            choice = (input('Scan QR code [Y/n]: ') or 'Y').lower()
            if choice == 'y':
                qrcode = qrutils.scanQRCode()
                if ':' in qrcode and qrcode.split(':')[0] != self.crypto:
                    print(
                        'Address belong to different cryptocurrency i.e. %s' %
                        qrcode.split(':')[0])
                    exit()
                address = qrcode.split(':')[1].split(
                    '?')[0] if ':' in qrcode else qrcode.split('?')[0]
                value = float(qrcode.split('?')[1].split('=')
                              [1]) if '?' in qrcode else float(
                                  input('Enter Btc/Ltc: '))
            elif choice == 'n':
                address = input('Enter Target Address: ')
                value = float(input('Enter Bitcoins: '))
            else:
                print('Invalid entry')
                exit()
            tx_out[address] = value

            if address in unused_addresses:
                unused_addresses.remove(address)

        if len(tx_out) != out_count:
            print('Address repetition is not allowed in target')
            exit()

        change_address = unused_addresses[0]
        print('change address: %s' % change_address)
        return tx_out, change_address

    def getSourceTargetAddresses(self):
        if network == 'regtest':
            self.setUnusedAddressesTest()
        else:
            self.setUnusedAddresses()

        out_count = int(input('Enter Number of Input Addresses: '))

        input_addresses = []

        for i in range(out_count):
            address = input('Enter Input Address: ')

            input_addresses.append(address)

        out_count = int(input('Enter Number of Target Addresses: '))

        out_addresses = []

        for i in range(out_count):
            choice = (input('Scan QR code [Y/n]: ') or 'Y').lower()
            if choice == 'y':
                qrcode = qrutils.scanQRCode()
                if ':' in qrcode and qrcode.split(':')[0] != self.crypto:
                    print(
                        'Address belong to different cryptocurrency i.e. %s' %
                        qrcode.split(':')[0])
                    exit()
                if '?' in qrcode:
                    print(
                        'QR code should not contain amount. Use option "Create Raw Transaction" instead.'
                    )
                    exit()
                address = qrcode.split(':')[1] if ':' in qrcode else qrcode
            elif choice == 'n':
                address = input('Enter Target Address: ')
            else:
                print('Invalid entry')
                exit()

            out_addresses.append(address)

        if len(set(out_addresses)) != out_count:
            print('Address repetition is not allowed in target')
            exit()


#                print('out_addresses = %s' % out_addresses)

        return input_addresses, out_addresses

    def validateAddresses(self):
        address_valid_map = {}
        for address in self.jsonobj['Addresses']:
            address_valid_map[address] = self.rpc_connection.validateaddress(
                address)['isvalid']
        return address_valid_map

    def setNewAddresses(self, addresses: list):
        label = self.user
        label_list = self.rpc_connection.listlabels()
        existing_addresses = []

        if label in label_list:
            existing_addresses = self.rpc_connection.getaddressesbylabel(label)
        new_addresses = set(addresses) - set(existing_addresses)
        #                print('new_addresses = %s' % new_addresses)

        return new_addresses

    def registerAddresses(self, addresses: list):
        new_addresses = self.setNewAddresses(addresses)

        s = []
        for address in new_addresses:
            i = {
                'scriptPubKey': {
                    'address': address
                },
                'timestamp': 0,
                'label': self.user,
                'watchonly': True
            }
            s.append(i)

        options = {'rescan': False}
        if len(s) > 0:
            self.rpc_connection.importmulti(s, options)

        return new_addresses

    def createRawTxn(self, fee_rate):
        #                print('transfer_info_filepath = %s' % self.transfer_info_filepath)
        sys.stdout.flush()

        self.registerAddresses(self.jsonobj['Addresses'])

        raw_txn = create_raw_txn.RawTxn(self.rpc_user, self.rpc_password,
                                        self.rpc_port,
                                        self.transfer_info_filepath, self.user)
        txout, change_address = self.getTargetAddresses()
        self.jsonobj = raw_txn.getRawTxnFromOuts(txout, change_address,
                                                 fee_rate, self.jsonobj)

    def createRawTxnToDivideFunds(self, fee_rate):
        #                print('transfer_info_filepath = %s' % self.transfer_info_filepath)
        sys.stdout.flush()

        self.registerAddresses(self.jsonobj['Addresses'])

        raw_txn = create_raw_txn.RawTxn(self.rpc_user, self.rpc_password,
                                        self.rpc_port,
                                        self.transfer_info_filepath, self.user)
        input_addresses, out_addresses = self.getSourceTargetAddresses()
        self.jsonobj = raw_txn.getRawTxnToDivideFunds(input_addresses,
                                                      out_addresses, fee_rate,
                                                      self.jsonobj)

    def publishSignedTxn(self):
        return self.rpc_connection.sendrawtransaction(
            self.jsonobj['Signed Txn'])

    def getFeeRate(self, conf_target_block: float):
        return self.rpc_connection.estimatesmartfee(
            conf_target_block)['feerate']

    def decodeSignedTransaction(self):
        return self.rpc_connection.decoderawtransaction(
            self.jsonobj['Signed Txn'])