def _pay_key_fee(self, address, fee_lbc, name): log.info("Pay key fee %s --> %s", dewies_to_lbc(fee_lbc), address) reserved_points = self.wallet.reserve_points(address, fee_lbc) if reserved_points is None: raise InsufficientFundsError( 'Unable to pay the key fee of {} for {}'.format(dewies_to_lbc(fee_lbc), name) ) return f2d(self.wallet.send_points_to_address(reserved_points, fee_lbc))
def encode_transaction(self, tx): return { 'txid': tx.id, 'height': tx.height, 'inputs': [self.encode_input(txo) for txo in tx.inputs], 'outputs': [self.encode_output(txo) for txo in tx.outputs], 'total_input': dewies_to_lbc(tx.input_sum), 'total_output': dewies_to_lbc(tx.input_sum - tx.fee), 'total_fee': dewies_to_lbc(tx.fee), 'hex': hexlify(tx.raw).decode(), }
def format_amount_value(obj): if isinstance(obj, dict): for k, v in obj.items(): if k in ('amount', 'effective_amount'): if not isinstance(obj[k], float): obj[k] = dewies_to_lbc(obj[k]) elif k == 'supports' and isinstance(v, list): obj[k] = [{'txid': txid, 'nout': nout, 'amount': dewies_to_lbc(amount)} for (txid, nout, amount) in v] elif isinstance(v, (list, dict)): obj[k] = format_amount_value(v) elif isinstance(obj, list): obj = [format_amount_value(o) for o in obj] return obj
def encode_output(self, txo): tx_height = txo.tx_ref.height best_height = self.ledger.headers.height output = { 'txid': txo.tx_ref.id, 'nout': txo.position, 'amount': dewies_to_lbc(txo.amount), 'address': txo.get_address(self.ledger), 'height': tx_height, 'confirmations': (best_height + 1) - tx_height if tx_height > 0 else tx_height } if txo.is_change is not None: output['is_change'] = txo.is_change if txo.is_my_account is not None: output['is_mine'] = txo.is_my_account if txo.script.is_claim_involved: output.update({ 'name': txo.claim_name, 'claim_id': txo.claim_id, 'permanent_url': txo.permanent_url, }) if txo.script.is_claim_name or txo.script.is_update_claim: claim = txo.claim output['value'] = claim.claim_dict if claim.has_signature: output['valid_signature'] = None if txo.channel is not None: output['channel_name'] = txo.channel.claim_name try: output[ 'valid_signature'] = claim.validate_signature( txo.get_address(self.ledger), txo.channel.claim, name=txo.claim_name) except BadSignatureError: output['valid_signature'] = False except ValueError: log.exception( 'txo.id: %s, txo.channel.id:%s, output: %s', txo.id, txo.channel.id, output) output['valid_signature'] = False if txo.script.is_claim_name: output['type'] = 'claim' elif txo.script.is_update_claim: output['type'] = 'update' elif txo.script.is_support_claim: output['type'] = 'support' else: output['type'] = 'basic' return output
def _format_support(outpoint, supported_id, amount, address): return { "txid": outpoint.split(":")[0], "nout": int(outpoint.split(":")[1]), "claim_id": supported_id, "amount": dewies_to_lbc(amount), "address": address, }
async def _report_state(self): for account in self.accounts: total_receiving = len((await account.receiving.get_addresses())) total_change = len((await account.change.get_addresses())) channel_count = await account.get_channel_count() claim_count = await account.get_claim_count() balance = dewies_to_lbc(await account.get_balance()) log.info("Loaded account %s with %s LBC, %d receiving addresses (gap: %d), " "%d change addresses (gap: %d), %d channels, %d certificates and %d claims. ", account.id, balance, total_receiving, account.receiving.gap, total_change, account.change.gap, channel_count, len(account.certificates), claim_count)
async def claim_new_channel(self, channel_name, amount, account): address = await account.receiving.get_or_create_usable_address() cert, key = generate_certificate() tx = await Transaction.claim(channel_name, cert, amount, address, [account], account) await account.ledger.broadcast(tx) account.add_certificate_private_key(tx.outputs[0].ref, key.decode()) # TODO: release reserved tx outputs in case anything fails by this point await self.old_db.save_claims([ self._old_get_temp_claim_info(tx, tx.outputs[0], address, cert, channel_name, dewies_to_lbc(amount)) ]) return tx
def as_dict(self) -> typing.Dict: return { "name": self.claim_name, "claim_id": self.claim_id, "address": self.claim_address, "claim_sequence": self.claim_sequence, "value": self.claim, "height": self.height, "amount": dewies_to_lbc(self.amount), "nout": self.nout, "txid": self.txid, "channel_claim_id": self.channel_claim_id, "channel_name": self.channel_name }
async def tip_claim(self, amount, claim_id, account): claim_to_tip = await self.get_claim_by_claim_id(claim_id) tx = await Transaction.support(claim_to_tip['name'], claim_id, amount, claim_to_tip['address'], [account], account) await account.ledger.broadcast(tx) await self.old_db.save_supports(claim_id, [{ 'txid': tx.id, 'nout': tx.position, 'address': claim_to_tip['address'], 'claim_id': claim_id, 'amount': dewies_to_lbc(amount) }]) return tx
async def support_claim(self, claim_name, claim_id, amount, account): holding_address = await account.receiving.get_or_create_usable_address( ) tx = await Transaction.support(claim_name, claim_id, amount, holding_address, [account], account) await account.ledger.broadcast(tx) await self.old_db.save_supports(claim_id, [{ 'txid': tx.id, 'nout': tx.position, 'address': holding_address, 'claim_id': claim_id, 'amount': dewies_to_lbc(amount) }]) return tx
def _format_claim_response(outpoint, claim_id, name, amount, height, serialized, channel_id, address, claim_sequence): r = { "name": name, "claim_id": claim_id, "address": address, "claim_sequence": claim_sequence, "value": ClaimDict.deserialize(unhexlify(serialized)).claim_dict, "height": height, "amount": dewies_to_lbc(amount), "nout": int(outpoint.split(":")[1]), "txid": outpoint.split(":")[0], "channel_claim_id": channel_id, "channel_name": None } return r
async def claim_name(self, account, name, amount, claim_dict, certificate=None, claim_address=None): claim = ClaimDict.load_dict(claim_dict) if not claim_address: claim_address = await account.receiving.get_or_create_usable_address( ) if certificate: claim = claim.sign( certificate.private_key, claim_address, certificate.claim_id, curve=SECP256k1, name=name, force_detached= False # TODO: delete it and make True default everywhere when its out ) existing_claims = await account.get_claims( claim_name_type__any={ 'is_claim': 1, 'is_update': 1 }, # exclude is_supports claim_name=name) if len(existing_claims) == 0: tx = await Transaction.claim(name, claim, amount, claim_address, [account], account) elif len(existing_claims) == 1: tx = await Transaction.update(existing_claims[0], claim, amount, claim_address, [account], account) else: raise NameError( f"More than one other claim exists with the name '{name}'.") await account.ledger.broadcast(tx) await self.old_db.save_claims([ self._old_get_temp_claim_info(tx, tx.outputs[0], claim_address, claim_dict, name, dewies_to_lbc(amount)) ]) # TODO: release reserved tx outputs in case anything fails by this point return tx
async def get_history(account: BaseAccount, **constraints): headers = account.ledger.headers txs = await account.get_transactions(**constraints) history = [] for tx in txs: ts = headers[tx.height]['timestamp'] if tx.height > 0 else None item = { 'txid': tx.id, 'timestamp': ts, 'date': datetime.fromtimestamp(ts).isoformat(' ')[:-3] if tx.height > 0 else None, 'confirmations': (headers.height + 1) - tx.height if tx.height > 0 else 0, 'claim_info': [], 'update_info': [], 'support_info': [], 'abandon_info': [] } is_my_inputs = all([txi.is_my_account for txi in tx.inputs]) if is_my_inputs: # fees only matter if we are the ones paying them item['value'] = dewies_to_lbc(tx.net_account_balance + tx.fee) item['fee'] = dewies_to_lbc(-tx.fee) else: # someone else paid the fees item['value'] = dewies_to_lbc(tx.net_account_balance) item['fee'] = '0.0' for txo in tx.my_claim_outputs: item['claim_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) for txo in tx.my_update_outputs: if is_my_inputs: # updating my own claim previous = None for txi in tx.inputs: if txi.txo_ref.txo is not None: other_txo = txi.txo_ref.txo if (other_txo.is_claim or other_txo.script.is_support_claim) \ and other_txo.claim_id == txo.claim_id: previous = other_txo break if previous is not None: item['update_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(previous.amount - txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) else: # someone sent us their claim item['update_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(0), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) for txo in tx.my_support_outputs: item['support_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc( txo.amount if not is_my_inputs else -txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'is_tip': not is_my_inputs, 'nout': txo.position }) for txo in tx.other_support_outputs: item['support_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'is_tip': is_my_inputs, 'nout': txo.position }) for txo in tx.my_abandon_outputs: item['abandon_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) history.append(item) return history
def calculate_effective_amount( amount: str, supports: typing.Optional[typing.List[typing.Dict]] = None) -> str: return dewies_to_lbc( lbc_to_dewies(amount) + sum([lbc_to_dewies(support['amount']) for support in supports]))
async def get_history(account: BaseAccount, **constraints): headers = account.ledger.headers txs = await account.get_transactions(**constraints) history = [] for tx in txs: ts = headers[tx.height]['timestamp'] if tx.height > 0 else None item = { 'txid': tx.id, 'timestamp': ts, 'value': dewies_to_lbc(tx.net_account_balance), 'fee': dewies_to_lbc(tx.fee), 'date': datetime.fromtimestamp(ts).isoformat(' ')[:-3] if tx.height > 0 else None, 'confirmations': headers.height - tx.height if tx.height > 0 else 0, 'claim_info': [], 'update_info': [], 'support_info': [], 'abandon_info': [] } for txo in tx.my_claim_outputs: item['claim_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) for txo in tx.my_update_outputs: item['update_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) for txo in tx.my_support_outputs: is_tip = next(tx.my_inputs, None) is None item['support_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(txo.amount if is_tip else -txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'is_tip': is_tip, 'nout': txo.position }) for txo in tx.other_support_outputs: is_tip = next(tx.my_inputs, None) is not None item['support_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'is_tip': is_tip, 'nout': txo.position }) for txo in tx.my_abandon_outputs: item['abandon_info'].append({ 'address': txo.get_address(account.ledger), 'balance_delta': dewies_to_lbc(-txo.amount), 'amount': dewies_to_lbc(txo.amount), 'claim_id': txo.claim_id, 'claim_name': txo.claim_name, 'nout': txo.position }) if all([txi.txo_ref.txo is not None for txi in tx.inputs]): item['fee'] = dewies_to_lbc(tx.fee) else: item['fee'] = '0' # can't calculate fee without all input txos history.append(item) return history