def bitcoind_export(self): descriptor = self.descriptor() export_range = (self.address_index, self.address_index + self.export_size) rpc = WalletRPC('bitboy') rpc.export(descriptor, export_range, False) # FIXME: change=False # FIXME: hackily update address index based on unspent descriptors ... # this could miss spent transactions ... # FIXME: skips exports between old and new index unspent = rpc.rpc().listunspent(0, 9999999, [], True) for u in unspent: desc = u['desc'] ai = int(desc[desc.find('/') + 1:desc.find(']')]) self.address_index = max(self.address_index, ai + 1) self.save()
def open(cls): with open(cls.filename, 'r') as f: raw_json = f.read() wallet = cls.deserialize(raw_json) # load associated Bitcoin Core watch-only wallet WalletRPC('').load_wallet('bitboy') return wallet
def create(cls, xpub=None): if isfile(cls.filename): raise OSError("wallet file already exists") xpub = HDPublicKey.parse(BytesIO(xpub.encode())) WalletRPC('').create_watchonly_wallet('bitboy') wallet = cls(xpub) wallet.bitcoind_export() wallet.save() return wallet
def balance(self): unconfirmed_balance = 0 confirmed_balance = 0 unspent = WalletRPC('bitboy').listunspent(0, 9999999, [], True) for u in unspent: if u['confirmations'] > 0: confirmed_balance += u['amount'] else: unconfirmed_balance += u['amount'] return unconfirmed_balance, confirmed_balance
def add_signature(): if request.method == 'GET': return render_template('add-signature.html') else: wallet = Wallet.open() script_sig = Script.parse( BytesIO(bytes.fromhex(request.json['signature']))) tx = Tx.parse(BytesIO(bytes.fromhex(wallet.tx_data['tx']))) for i, tx_in in enumerate(tx.tx_ins): if tx_in.script_sig.cmds == []: tx.tx_ins[i].script_sig = script_sig print('filled in script sig') break # FIXME: for some reason script_sig is None ... if all([tx_in.script_sig.cmds != [] for tx_in in tx.tx_ins]): rpc = WalletRPC('bitboy') print(tx.serialize().hex()) rpc.broadcast(tx.serialize().hex()) print('broadcasted') # wallet.tx_data = None # FIXME return tx.id() wallet.save() return 'ok'
def prepare_tx(self, address, amount, fee): # FIXME: amount -> satoshis rpc = WalletRPC('bitboy') # create unfunded transaction tx_ins = [] tx_outs = [ { address: sat_to_btc(amount) }, ] rawtx = rpc.create_raw_transaction(tx_ins, tx_outs) # fund it change_address = self.consume_address() fundedtx = rpc.fund_raw_transaction(rawtx, change_address) # input metadata input_meta = [] decoded = rpc.rpc().decoderawtransaction(fundedtx) for tx_in in decoded['vin']: print('iterate input') tx_id = tx_in['txid'] tx_index = tx_in['vout'] prev_tx = rpc.rpc().getrawtransaction(tx_id, True) script_pubkey = encode_varstr( bytes.fromhex( prev_tx['vout'][tx_index]['scriptPubKey']['hex'])).hex() input_address = prev_tx['vout'][tx_index]['scriptPubKey'][ 'addresses'][0] pubkey, path = self.lookup_pubkey(input_address) derivation_path = f"m/69'/{path[2:]}" print('PATH', derivation_path) input_meta = [{ 'script_pubkey': script_pubkey, 'derivation_path': derivation_path }] # output metadata output_meta = [] for tx_out in decoded['vout']: print('iterate output') address = tx_out['scriptPubKey']['addresses'][0] pubkey, path = self.lookup_pubkey(address) if path is None: output_meta.append({'change': False}) else: derivation_path = f"m/69'/{path[2:]}" output_meta.append({ 'change': True, 'derivation_path': derivation_path }) return fundedtx, input_meta, output_meta
def transactions(self): return WalletRPC('bitboy').get_transactions()
def unspent(self): return WalletRPC('bitboy').get_unspent()
def balance(self): return WalletRPC('bitboy').get_balance()