Exemplo n.º 1
0
    async def payment_pre_processing(self, other_address, seq, command,
                                     payment):
        """An async method to let VASP perform custom business logic to a
        successsful (sequenced & ACKed) command prior to normal processing.
        For example it can be used to check whether the payment is in terminal
        status. The command could have originated either from the other VASP
        or this VASP (see `command.origin` to determine this).
        Args:
            other_address (str): the encoded Diem Blockchain address of the other VASP.
            seq (int): the sequence number into the shared command sequence.
            command (ProtocolCommand): the command that lead to the new or
                updated payment.
            payment (PaymentObject): the payment resulting from this command.
        Returns None or a context objext that will be passed on the
        other business context functions.
        """

        if (payment.sender.status.as_status() == Status.ready_for_settlement
                and payment.receiver.status.as_status()
                == Status.ready_for_settlement):
            if self.is_sender(payment):
                ref_id = payment.reference_id
                transaction_id = get_transaction_id_from_reference_id(ref_id)
                transaction = get_single_transaction(transaction_id)
                add_metadata_signature(ref_id, payment.recipient_signature)

                if transaction.status == TransactionStatus.COMPLETED:
                    return None
                if transaction.status == TransactionStatus.READY_FOR_ON_CHAIN:
                    start_settle_offchain(transaction_id=transaction.id)

                # TODO: What should happen in this case?
                if transaction.status == TransactionStatus.CANCELED:
                    raise ValueError("what should happen in this case?")

            else:
                receiver_subaddress = LibraAddress.from_encoded_str(
                    payment.receiver.address).get_subaddress_hex()
                txn_id = add_transaction(
                    amount=payment.action.amount,
                    currency=DiemCurrency(payment.action.currency),
                    payment_type=TransactionType.OFFCHAIN,
                    status=TransactionStatus.READY_FOR_ON_CHAIN,
                    source_id=None,
                    source_address=LibraAddress.from_encoded_str(
                        payment.sender.address).get_onchain_address_hex(),
                    source_subaddress=LibraAddress.from_encoded_str(
                        payment.sender.address).get_subaddress_hex(),
                    destination_id=get_account_id_from_subaddr(
                        receiver_subaddress),
                    destination_address=LibraAddress.from_encoded_str(
                        payment.receiver.address).get_onchain_address_hex(),
                    destination_subaddress=receiver_subaddress,
                    sequence=None,
                    blockchain_version=None,
                    reference_id=payment.reference_id,
                    metadata_signature=payment.recipient_signature,
                )
Exemplo n.º 2
0
    def get_peer_base_url(self, other_addr: LibraAddress) -> str:
        """Get the base URL that manages off-chain communications of the other
        VASP.
        Returns:
            str: The base url of the other VASP.
        """

        return self.context.get_vasp_base_url(
            other_addr.get_onchain_address_hex())
Exemplo n.º 3
0
def make_payment(
    sender: LibraAddress,
    receiver: LibraAddress,
    amount: int,
    currency=testnet.TEST_CURRENCY_CODE,
    action="charge",
) -> PaymentObject:
    action = PaymentAction(amount, currency, action, int(time.time()))
    status = StatusObject(Status.none)
    sender_actor = PaymentActor(sender.as_str(), status, [])
    receiver_actor = PaymentActor(receiver.as_str(), status, [])
    return PaymentObject(
        sender_actor,
        receiver_actor,
        f"{sender.get_onchain().as_str()}_abc",
        None,
        "payment description",
        action,
    )
Exemplo n.º 4
0
 def get_account_id(self, payment) -> int:
     my_actor = payment.sender if self.is_sender(
         payment) else payment.receiver
     address = LibraAddress.from_encoded_str(my_actor.address)
     subaddress = address.get_subaddress_hex()
     account_id = get_account_id_from_subaddr(subaddress)
     if account_id is None:
         role = self.get_my_role(payment)
         raise BusinessForceAbort(
             OffChainErrorCode.payment_invalid_libra_subaddress,
             f"Subaccount {subaddress} does not exist in {role}.",
         )
     return account_id
Exemplo n.º 5
0
def get_new_offchain_reference_id(sender_address_hex: str) -> str:
    address = LibraAddress.from_hex(context.get().config.diem_address_hrp(),
                                    sender_address_hex, None)
    id = uuid.uuid1().hex
    return f"{address.as_str()}_{id}"
Exemplo n.º 6
0
 def vasp_diem_address(self) -> LibraAddress:
     return LibraAddress.from_hex(self.diem_address_hrp(),
                                  self.vasp_address, None)
Exemplo n.º 7
0
def external_offchain_transaction(
    sender_id: int,
    receiver_address: str,
    receiver_subaddress: str,
    amount: int,
    currency: DiemCurrency,
    payment_type: TransactionType,
    original_payment_reference_id: Optional[str] = None,
    description: Optional[str] = None,
) -> Transaction:

    sender_onchain_address = context.get().config.vasp_address
    logger.info(
        f"=================Start external_offchain_transaction "
        f"{sender_onchain_address}, {sender_id}, {receiver_address}, {receiver_subaddress}, "
        f"{amount}, {currency}, {payment_type}")
    if not validate_balance(sender_id, amount, currency):
        raise BalanceError(
            f"Balance {account_service.get_account_balance_by_id(account_id=sender_id).total[currency]} "
            f"is less than amount needed {amount}")

    sender_subaddress = account_service.generate_new_subaddress(
        account_id=sender_id)
    logger.info(f"======sender_subaddress: {sender_subaddress}")
    ref_id = get_new_offchain_reference_id(sender_onchain_address)
    transaction = add_transaction(
        amount=amount,
        currency=currency,
        payment_type=payment_type,
        status=TransactionStatus.PENDING,
        source_id=sender_id,
        source_address=sender_onchain_address,
        source_subaddress=sender_subaddress,
        destination_id=None,
        destination_address=receiver_address,
        destination_subaddress=receiver_subaddress,
        reference_id=ref_id,
    )

    # off-chain logic
    sender_address = LibraAddress.from_bytes(
        context.get().config.diem_address_hrp(),
        bytes.fromhex(sender_onchain_address),
        bytes.fromhex(sender_subaddress),
    )
    logger.info(
        f"sender address: {sender_onchain_address}, {sender_address.as_str()}, {sender_address.get_onchain().as_str()}"
    )
    receiver_address = LibraAddress.from_bytes(
        context.get().config.diem_address_hrp(),
        bytes.fromhex(receiver_address),
        bytes.fromhex(receiver_subaddress),
    )
    logger.info(
        f"receiver address: {receiver_address.as_str()}, {receiver_address.get_onchain().as_str()}",
    )
    sender = PaymentActor(
        sender_address.as_str(),
        StatusObject(Status.needs_kyc_data),
        [],
    )
    receiver = PaymentActor(receiver_address.as_str(),
                            StatusObject(Status.none), [])
    action = PaymentAction(amount, currency, "charge", int(time()))
    reference_id = get_reference_id_from_transaction_id(transaction.id)
    payment = PaymentObject(
        sender=sender,
        receiver=receiver,
        reference_id=reference_id,
        original_payment_reference_id=original_payment_reference_id,
        description=description,
        action=action,
    )
    cmd = PaymentCommand(payment)

    if not get_transaction_status(transaction.id) == TransactionStatus.PENDING:
        logger.info(
            "In external_offchain_transaction, payment status is not PENDING, abort"
        )
        return

    update_transaction(transaction.id, TransactionStatus.OFF_CHAIN_STARTED)
    logger.info(
        "In external_offchain_transaction: Updated status to OFF_CHAIN_STARTED"
    )

    result = (offchain_client.get().new_command(receiver_address.get_onchain(),
                                                cmd).result(timeout=300))
    logger.info(f"Offchain Result: {result}")

    return transaction
Exemplo n.º 8
0
 def get_peer_compliance_verification_key(self,
                                          other_addr: str) -> ComplianceKey:
     address = LibraAddress.from_encoded_str(
         other_addr).get_onchain_address_hex()
     return self.context.get_vasp_public_compliance_key(address)
Exemplo n.º 9
0
 def user_address(self, user_subaddress_hex: str) -> LibraAddress:
     return LibraAddress.from_hex(
         self.context.config.diem_address_hrp(),
         self.vasp_address.get_onchain_address_hex(),
         user_subaddress_hex,
     )
Exemplo n.º 10
0
def actor_to_libra_address(actor: PaymentActor) -> LibraAddress:
    return LibraAddress.from_encoded_str(actor.address)