Пример #1
0
 def test_create_from_invalid_public_key_raise(self, invalid_public_key):
     with pytest.raises(
             Ed25519PublicKeyInvalidError,
             match="Invalid Ed25519 Public Key: {}".format(
                 invalid_public_key),
     ):
         Keypair.from_public_key(invalid_public_key)
Пример #2
0
def deposit(account: str, request: Request) -> Response:
    """
    POST /transactions/deposit/interactive

    Creates an `incomplete` deposit Transaction object in the database and
    returns the URL entry-point for the interactive flow.
    """
    asset_code = request.POST.get("asset_code")
    stellar_account = request.POST.get("account")
    lang = request.POST.get("lang")
    if lang:
        err_resp = validate_language(lang)
        if err_resp:
            return err_resp
        activate_lang_for_request(lang)

    # Verify that the request is valid.
    if not all([asset_code, stellar_account]):
        return render_error_response(
            _("`asset_code` and `account` are required parameters")
        )

    # Verify that the asset code exists in our database, with deposit enabled.
    asset = Asset.objects.filter(code=asset_code).first()
    if not asset:
        return render_error_response(_("unknown asset: %s") % asset_code)
    elif not asset.deposit_enabled:
        return render_error_response(_("invalid operation for asset %s") % asset_code)

    try:
        Keypair.from_public_key(stellar_account)
    except Ed25519PublicKeyInvalidError:
        return render_error_response(_("invalid 'account'"))

    # Construct interactive deposit pop-up URL.
    transaction_id = create_transaction_id()
    Transaction.objects.create(
        id=transaction_id,
        stellar_account=account,
        asset=asset,
        kind=Transaction.KIND.deposit,
        status=Transaction.STATUS.incomplete,
        to_address=account,
    )
    logger.info(f"Created deposit transaction {transaction_id}")

    url = interactive_url(
        request,
        str(transaction_id),
        stellar_account,
        asset_code,
        settings.OPERATION_DEPOSIT,
    )
    return Response(
        {"type": "interactive_customer_info_needed", "url": url, "id": transaction_id},
        status=status.HTTP_200_OK,
    )
Пример #3
0
def deposit(account: str, request: Request) -> Response:
    """
    `POST /transactions/deposit/interactive` initiates the deposit and returns an interactive
    deposit form to the user.
    """
    asset_code = request.POST.get("asset_code")
    stellar_account = request.POST.get("account")

    # Verify that the request is valid.
    if not all([asset_code, stellar_account]):
        return render_error_response(
            "`asset_code` and `account` are required parameters")

    # Verify that the asset code exists in our database, with deposit enabled.
    asset = Asset.objects.filter(code=asset_code).first()
    if not asset or not asset.deposit_enabled:
        return render_error_response(
            f"invalid operation for asset {asset_code}")

    try:
        Keypair.from_public_key(stellar_account)
    except Ed25519PublicKeyInvalidError:
        return render_error_response("invalid 'account'")

    # Verify the optional request arguments.
    verify_optional_args = _verify_optional_args(request)
    if verify_optional_args:
        return verify_optional_args

    # Construct interactive deposit pop-up URL.
    transaction_id = create_transaction_id()
    Transaction.objects.create(
        id=transaction_id,
        stellar_account=account,
        asset=asset,
        kind=Transaction.KIND.deposit,
        status=Transaction.STATUS.incomplete,
        to_address=account,
    )
    url = rdi.interactive_url(request, str(transaction_id), stellar_account,
                              asset_code)
    return Response(
        {
            "type": "interactive_customer_info_needed",
            "url": url,
            "id": transaction_id
        },
        status=status.HTTP_200_OK,
    )
Пример #4
0
def test_auth_get_account(client):
    """`GET <auth>` succeeds with a valid TransactionEnvelope XDR."""
    response = client.get(f"/auth?account={STELLAR_ACCOUNT_1}", follow=True)
    content = json.loads(response.content)
    assert content["network_passphrase"] == "Test SDF Network ; September 2015"
    assert content["transaction"]

    envelope_xdr = content["transaction"]
    envelope_object = TransactionEnvelope.from_xdr(
        envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE)
    transaction_object = envelope_object.transaction
    assert transaction_object.sequence == 0
    assert len(transaction_object.operations) == 1

    manage_data_op = transaction_object.operations[0]
    assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA
    assert manage_data_op.data_name == "SEP 24 Reference auth"
    assert len(manage_data_op.data_value) == 64

    signatures = envelope_object.signatures
    assert len(signatures) == 1
    server_signature = signatures[0]

    tx_hash = envelope_object.hash()
    server_public_key = Keypair.from_public_key(
        settings.STELLAR_DISTRIBUTION_ACCOUNT_ADDRESS)
    server_public_key.verify(tx_hash, server_signature.signature)
Пример #5
0
def test_auth_get_account(client):
    """`GET <auth>` succeeds with a valid TransactionEnvelope XDR."""
    response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}",
                          follow=True)
    content = json.loads(response.content)
    assert content["network_passphrase"] == "Test SDF Network ; September 2015"
    assert content["transaction"]

    envelope_xdr = content["transaction"]
    envelope_object = TransactionEnvelope.from_xdr(
        envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE)
    transaction_object = envelope_object.transaction
    assert transaction_object.sequence == 0
    assert len(transaction_object.operations) == 1

    manage_data_op = transaction_object.operations[0]
    assert manage_data_op.type_code() == Xdr.const.MANAGE_DATA
    assert manage_data_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth"
    assert len(manage_data_op.data_value) <= 64
    assert len(base64.b64decode(manage_data_op.data_value)) == 48

    signatures = envelope_object.signatures
    assert len(signatures) == 1
    server_signature = signatures[0]

    tx_hash = envelope_object.hash()
    server_public_key = Keypair.from_public_key(settings.SIGNING_KEY)
    server_public_key.verify(tx_hash, server_signature.signature)
Пример #6
0
def test_auth_get_success(client):
    """`GET <auth>` succeeds with a valid TransactionEnvelope XDR."""
    response = client.get(f"{endpoint}?account={STELLAR_ACCOUNT_1}",
                          follow=True)
    content = json.loads(response.content)
    assert content["network_passphrase"] == "Test SDF Network ; September 2015"
    assert content["transaction"]

    envelope_xdr = content["transaction"]
    envelope_object = TransactionEnvelope.from_xdr(
        envelope_xdr, network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE)
    transaction_object = envelope_object.transaction
    assert transaction_object.sequence == 0
    assert len(transaction_object.operations) == 2

    home_domain_op = transaction_object.operations[0]
    assert isinstance(home_domain_op, ManageData)
    assert home_domain_op.data_name == f"{urlparse(settings.HOST_URL).netloc} auth"
    assert len(home_domain_op.data_value) <= 64
    assert len(base64.b64decode(home_domain_op.data_value)) == 48

    web_auth_domain_op = transaction_object.operations[1]
    assert isinstance(web_auth_domain_op, ManageData)
    assert web_auth_domain_op.data_name == "web_auth_domain"
    assert (web_auth_domain_op.data_value ==
            f"{urlparse(settings.HOST_URL).netloc}".encode())

    signatures = envelope_object.signatures
    assert len(signatures) == 1

    tx_hash = envelope_object.hash()
    server_public_key = Keypair.from_public_key(settings.SIGNING_KEY)
    server_public_key.verify(tx_hash, signatures[0].signature)
Пример #7
0
 def test_can_sign(self):
     can_sign_kp = Keypair.from_secret(
         "SD7X7LEHBNMUIKQGKPARG5TDJNBHKC346OUARHGZL5ITC6IJPXHILY36")
     can_not_sign_kp = Keypair.from_public_key(
         "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH")
     assert can_sign_kp.can_sign() is True
     assert can_not_sign_kp.can_sign() is False
Пример #8
0
def create_stellar_deposit(transaction: Transaction) -> bool:
    """
    Performs final status and signature checks before calling submit_stellar_deposit().
    Returns true on successful submission, false otherwise. `transaction` will be placed
    in the error status if submission fails or if it is a multisig transaction and is not
    signed by the channel account.
    """
    if transaction.status not in [
            Transaction.STATUS.pending_anchor,
            Transaction.STATUS.pending_trust,
    ]:
        raise ValueError(
            f"unexpected transaction status {transaction.status} for "
            "create_stellar_deposit", )
    elif transaction.amount_in is None or transaction.amount_fee is None:
        transaction.status = Transaction.STATUS.error
        transaction.status_message = (
            "`amount_in` and `amount_fee` must be populated, skipping transaction"
        )
        transaction.save()
        raise ValueError(transaction.status_message)

    # if the distribution account's master signer's weight is great or equal to the its
    # medium threshold, verify the transaction is signed by it's channel account
    master_signer = None
    if transaction.asset.distribution_account_master_signer:
        master_signer = transaction.asset.distribution_account_master_signer
    thresholds = transaction.asset.distribution_account_thresholds
    if not master_signer or master_signer["weight"] < thresholds[
            "med_threshold"]:
        envelope = TransactionEnvelope.from_xdr(
            transaction.envelope_xdr, settings.STELLAR_NETWORK_PASSPHRASE)
        try:
            _verify_te_signed_by_account_id(envelope,
                                            transaction.channel_account)
        except InvalidSep10ChallengeError:
            transaction.status = Transaction.STATUS.error
            transaction.status_message = gettext(
                "Multisig transaction's envelope was not signed by channel account"
            )
            transaction.save()
            return False
    # otherwise, create the envelope and sign it with the distribution account's secret
    else:
        distribution_acc, _ = get_account_obj(
            Keypair.from_public_key(transaction.asset.distribution_account))
        envelope = create_transaction_envelope(transaction, distribution_acc)
        envelope.sign(transaction.asset.distribution_seed)

    try:
        submit_stellar_deposit(transaction, envelope)
    except (RuntimeError, BaseHorizonError) as e:
        transaction.status_message = f"{e.__class__.__name__}: {e.message}"
        transaction.status = Transaction.STATUS.error
        transaction.save()
        logger.error(transaction.status_message)
        return False
    else:
        return True
Пример #9
0
 def test_create_from_public_key(self):
     public_key = "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH"
     kp = Keypair.from_public_key(public_key)
     assert isinstance(kp, Keypair)
     assert (kp.public_key ==
             "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH")
     assert (
         kp.raw_public_key().hex() ==
         "2e3c35010749c1de3d9a5bdd6a31c12458768da5ce87cca6aad63ebbaaef7432")
Пример #10
0
def deposit(request):
    """
    `GET /deposit` initiates the deposit and returns an interactive
    deposit form to the user.
    """
    asset_code = request.GET.get("asset_code")
    stellar_account = request.GET.get("account")

    # Verify that the request is valid.
    if not all([asset_code, stellar_account]):
        return render_error_response(
            "`asset_code` and `account` are required parameters")

    # Verify that the asset code exists in our database, with deposit enabled.
    asset = Asset.objects.filter(code=asset_code).first()
    if not asset or not asset.deposit_enabled:
        return render_error_response(
            f"invalid operation for asset {asset_code}")

    try:
        Keypair.from_public_key(stellar_account)
    except Ed25519PublicKeyInvalidError:
        return render_error_response("invalid 'account'")

    # Verify the optional request arguments.
    verify_optional_args = _verify_optional_args(request)
    if verify_optional_args:
        return verify_optional_args

    # Construct interactive deposit pop-up URL.
    transaction_id = create_transaction_id()
    url = _construct_interactive_url(request, transaction_id)
    return Response(
        {
            "type": "interactive_customer_info_needed",
            "url": url,
            "id": transaction_id
        },
        status=status.HTTP_403_FORBIDDEN,
    )
Пример #11
0
    def test_from_xdr_object_alphanum12(self):
        code = "Banana"
        issuer = "GCNY5OXYSY4FKHOPT2SPOQZAOEIGXB5LBYW3HVU3OWSTQITS65M5RCNY"
        type = "credit_alphanum12"

        x = Xdr.nullclass()
        x.assetCode = bytearray(code, "ascii") + b"\x00" * 6
        x.issuer = Keypair.from_public_key(issuer).xdr_account_id()
        xdr_type = Xdr.const.ASSET_TYPE_CREDIT_ALPHANUM12
        xdr = Xdr.types.Asset(type=xdr_type, alphaNum12=x)

        asset = Asset.from_xdr_object(xdr)
        assert asset.code == code
        assert asset.issuer == issuer
        assert asset.type == type
Пример #12
0
 def test_from_xdr_object_alphanum12(self):
     code = "Banana"
     issuer = "GCNY5OXYSY4FKHOPT2SPOQZAOEIGXB5LBYW3HVU3OWSTQITS65M5RCNY"
     type = "credit_alphanum12"
     asset_code = stellar_xdr.AssetCode12(
         bytearray(code, "ascii") + b"\x00" * (12 - len(code)))
     asset = stellar_xdr.AssetAlphaNum12(
         asset_code=asset_code,
         issuer=Keypair.from_public_key(issuer).xdr_account_id(),
     )
     xdr = stellar_xdr.Asset(
         type=stellar_xdr.AssetType.ASSET_TYPE_CREDIT_ALPHANUM12,
         alpha_num12=asset)
     asset = Asset.from_xdr_object(xdr)
     assert asset.code == code
     assert asset.issuer == issuer
     assert asset.type == type
Пример #13
0
def create_transaction_envelope(transaction,
                                source_account) -> TransactionEnvelope:
    payment_amount = round(
        Decimal(transaction.amount_in) - Decimal(transaction.amount_fee),
        transaction.asset.significant_decimals,
    )
    memo = make_memo(transaction.memo, transaction.memo_type)
    builder = TransactionBuilder(
        source_account=source_account,
        network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE,
        # only one operation, so base_fee will be multipled by 1
        base_fee=settings.MAX_TRANSACTION_FEE_STROOPS
        or settings.HORIZON_SERVER.fetch_base_fee(),
    )
    _, json_resp = get_account_obj(
        Keypair.from_public_key(transaction.stellar_account))
    if transaction.claimable_balance_supported and is_pending_trust(
            transaction, json_resp):
        logger.debug(
            f"Crafting claimable balance operation for Transaction {transaction.id}"
        )
        claimant = Claimant(destination=transaction.stellar_account)
        asset = Asset(code=transaction.asset.code,
                      issuer=transaction.asset.issuer)
        builder.append_create_claimable_balance_op(
            claimants=[claimant],
            asset=asset,
            amount=str(payment_amount),
            source=transaction.asset.distribution_account,
        )
    else:
        builder.append_payment_op(
            destination=transaction.stellar_account,
            asset_code=transaction.asset.code,
            asset_issuer=transaction.asset.issuer,
            amount=str(payment_amount),
            source=transaction.asset.distribution_account,
        )
    if memo:
        builder.add_memo(memo)
    return builder.build()
Пример #14
0
def handle_bad_signatures_error(e, transaction, multisig=False):
    err_msg = (f"Horizon returned a {e.__class__.__name__} on transaction "
               f"{transaction.id} submission.")
    logger.error(err_msg)
    logger.error(
        f"Transaction {transaction.id} envelope XDR: {transaction.envelope_xdr}"
    )
    logger.error(f"Transaction {transaction.id} result XDR: {e.result_xdr}")
    if multisig:
        logger.error(
            f"Resetting the Transaction.envelope_xdr for {transaction.id}, "
            "updating Transaction.pending_signatures to True")
        channel_account, _ = get_account_obj(
            Keypair.from_public_key(transaction.channel_account))
        transaction.envelope_xdr = create_transaction_envelope(
            transaction, channel_account).to_xdr()
        transaction.pending_signatures = True
        transaction.status = Transaction.STATUS.pending_anchor = True
    else:
        transaction.status = Transaction.STATUS.error
        transaction.status_message = (
            f"Horizon returned a {e.__class__.__name__} on transaction "
            f"{transaction.id} submission")
    transaction.save()
Пример #15
0
def create_stellar_deposit(transaction: Transaction,
                           destination_exists: bool = False) -> bool:
    """
    Create and submit the Stellar transaction for the deposit.

    The Transaction can be either `pending_anchor` if the task is called
    from `poll_pending_deposits()` or `pending_trust` if called from the
    `check_trustlines()`.
    """
    if transaction.status not in [
            Transaction.STATUS.pending_anchor,
            Transaction.STATUS.pending_trust,
    ]:
        raise ValueError(
            f"unexpected transaction status {transaction.status} for "
            "create_stellar_deposit", )
    elif transaction.amount_in is None or transaction.amount_fee is None:
        transaction.status = Transaction.STATUS.error
        transaction.status_message = (
            "`amount_in` and `amount_fee` must be populated, skipping transaction"
        )
        transaction.save()
        raise ValueError(transaction.status_message)

    # if we don't know if the destination account exists
    if not destination_exists:
        try:
            _, created, pending_trust = get_or_create_transaction_destination_account(
                transaction)
        except RuntimeError as e:
            transaction.status = Transaction.STATUS.error
            transaction.status_message = str(e)
            transaction.save()
            logger.error(transaction.status_message)
            return False
        if created or pending_trust:
            # the account is pending_trust for the asset to be received
            if pending_trust and transaction.status != Transaction.STATUS.pending_trust:
                transaction.status = Transaction.STATUS.pending_trust
                transaction.save()
            return False

    # if the distribution account's master signer's weight is great or equal to the its
    # medium threshold, verify the transaction is signed by it's channel account
    master_signer = None
    if transaction.asset.distribution_account_master_signer:
        master_signer = transaction.asset.distribution_account_master_signer
    thresholds = transaction.asset.distribution_account_thresholds
    if not (master_signer
            and master_signer["weight"] >= thresholds["med_threshold"]):
        multisig = True
        envelope = TransactionEnvelope.from_xdr(
            transaction.envelope_xdr, settings.STELLAR_NETWORK_PASSPHRASE)
        try:
            _verify_te_signed_by_account_id(envelope,
                                            transaction.channel_account)
        except InvalidSep10ChallengeError:
            transaction.status = Transaction.STATUS.error
            transaction.status_message = gettext(
                "Multisig transaction's envelope was not signed by channel account"
            )
            transaction.save()
            return False
    # otherwise, create the envelope and sign it with the distribution account's secret
    else:
        multisig = False
        distribution_acc, _ = get_account_obj(
            Keypair.from_public_key(transaction.asset.distribution_account))
        envelope = create_transaction_envelope(transaction, distribution_acc)
        envelope.sign(transaction.asset.distribution_seed)
        transaction.envelope_xdr = envelope.to_xdr()

    try:
        return submit_stellar_deposit(transaction, multisig=multisig)
    except RuntimeError as e:
        transaction.status_message = str(e)
        transaction.status = Transaction.STATUS.error
        transaction.save()
        logger.error(transaction.status_message)
        return False
Пример #16
0
    "source": "GCUZ6YLL5RQBTYLTTQLPCM73C5XAIUGK2TIMWQH7HPSGWVS2KJ2F3CHS",
    "paging_token": "123456789",
}
mock_envelope = Mock(transaction=Mock(
    operations=[
        Mock(
            asset=Mock(
                issuer=USD_ISSUER_ACCOUNT,
                code="USD",
            ),
            amount=50,
            destination=Keypair.from_secret(USD_DISTRIBUTION_SEED).public_key,
            type_code=Mock(return_value=1),
        )
    ],
    source=Keypair.from_public_key(
        "GCUZ6YLL5RQBTYLTTQLPCM73C5XAIUGK2TIMWQH7HPSGWVS2KJ2F3CHS"),
))


@pytest.mark.django_db
@patch(f"{test_module}.TransactionEnvelope.from_xdr",
       return_value=mock_envelope)
def test_process_response_success(mock_xdr, client,
                                  acc1_usd_withdrawal_transaction_factory):
    del mock_xdr
    mock_source_account = mock_envelope.transaction.source.public_key
    transaction = acc1_usd_withdrawal_transaction_factory(mock_source_account)
    json = deepcopy(TRANSACTION_JSON)
    json["successful"] = True
    json["id"] = transaction.id
    json["memo"] = transaction.memo
Пример #17
0
def deposit(account: str, client_domain: Optional[str],
            request: Request) -> Response:
    """
    POST /transactions/deposit/interactive

    Creates an `incomplete` deposit Transaction object in the database and
    returns the URL entry-point for the interactive flow.
    """
    asset_code = request.data.get("asset_code")
    stellar_account = request.data.get("account")
    lang = request.data.get("lang")
    sep9_fields = extract_sep9_fields(request.data)
    claimable_balance_supported = request.data.get(
        "claimable_balance_supported")
    if not claimable_balance_supported:
        claimable_balance_supported = False
    elif isinstance(claimable_balance_supported, str):
        if claimable_balance_supported.lower() not in ["true", "false"]:
            return render_error_response(
                _("'claimable_balance_supported' value must be 'true' or 'false'"
                  ))
        claimable_balance_supported = claimable_balance_supported.lower(
        ) == "true"
    elif not isinstance(claimable_balance_supported, bool):
        return render_error_response(
            _("unexpected data type for 'claimable_balance_supprted'. Expected string or boolean."
              ))

    if lang:
        err_resp = validate_language(lang)
        if err_resp:
            return err_resp
        activate_lang_for_request(lang)

    # Verify that the request is valid.
    if not all([asset_code, stellar_account]):
        return render_error_response(
            _("`asset_code` and `account` are required parameters"))

    # Ensure memo won't cause stellar transaction to fail when submitted
    try:
        make_memo(request.data.get("memo"), request.data.get("memo_type"))
    except ValueError:
        return render_error_response(_("invalid 'memo' for 'memo_type'"))

    # Verify that the asset code exists in our database, with deposit enabled.
    asset = Asset.objects.filter(code=asset_code).first()
    if not asset:
        return render_error_response(_("unknown asset: %s") % asset_code)
    elif not (asset.deposit_enabled and asset.sep24_enabled):
        return render_error_response(
            _("invalid operation for asset %s") % asset_code)

    amount = None
    if request.data.get("amount"):
        try:
            amount = Decimal(request.data.get("amount"))
        except DecimalException:
            return render_error_response(_("invalid 'amount'"))
        if not (asset.deposit_min_amount <= amount <=
                asset.deposit_max_amount):
            return render_error_response(_("invalid 'amount'"))

    try:
        Keypair.from_public_key(stellar_account)
    except Ed25519PublicKeyInvalidError:
        return render_error_response(_("invalid 'account'"))

    try:
        rdi.save_sep9_fields(
            stellar_account,
            sep9_fields,
            lang,
        )
    except ValueError as e:
        # The anchor found a validation error in the sep-9 fields POSTed by
        # the wallet. The error string returned should be in the language
        # specified in the request.
        return render_error_response(str(e))

    # Construct interactive deposit pop-up URL.
    transaction_id = create_transaction_id()
    Transaction.objects.create(
        id=transaction_id,
        stellar_account=account,
        asset=asset,
        kind=Transaction.KIND.deposit,
        status=Transaction.STATUS.incomplete,
        to_address=account,
        protocol=Transaction.PROTOCOL.sep24,
        claimable_balance_supported=claimable_balance_supported,
        memo=request.data.get("memo"),
        memo_type=request.data.get("memo_type") or Transaction.MEMO_TYPES.hash,
        more_info_url=request.build_absolute_uri(
            f"{reverse('more_info')}?id={transaction_id}"),
        client_domain=client_domain,
    )
    logger.info(f"Created deposit transaction {transaction_id}")

    url = interactive_url(
        request,
        str(transaction_id),
        account,
        asset_code,
        settings.OPERATION_DEPOSIT,
        amount,
    )
    return Response(
        {
            "type": "interactive_customer_info_needed",
            "url": url,
            "id": transaction_id
        },
        status=status.HTTP_200_OK,
    )
Пример #18
0
def deposit(account: str, request: Request) -> Response:
    """
    POST /transactions/deposit/interactive

    Creates an `incomplete` deposit Transaction object in the database and
    returns the URL entry-point for the interactive flow.
    """
    asset_code = request.POST.get("asset_code")
    stellar_account = request.POST.get("account")
    lang = request.POST.get("lang")
    sep9_fields = extract_sep9_fields(request.POST)
    if lang:
        err_resp = validate_language(lang)
        if err_resp:
            return err_resp
        activate_lang_for_request(lang)

    # Verify that the request is valid.
    if not all([asset_code, stellar_account]):
        return render_error_response(
            _("`asset_code` and `account` are required parameters"))

    # Ensure memo won't cause stellar transaction to fail when submitted
    try:
        memo = memo_str(request.POST.get("memo"),
                        request.POST.get("memo_type"))
    except ValueError:
        return render_error_response(_("invalid 'memo' for 'memo_type'"))

    amount = None
    if request.POST.get("amount"):
        try:
            amount = Decimal(request.POST.get("amount"))
        except DecimalException as e:
            return render_error_response(_("Invalid 'amount'"))

    # Verify that the asset code exists in our database, with deposit enabled.
    asset = Asset.objects.filter(code=asset_code).first()
    if not asset:
        return render_error_response(_("unknown asset: %s") % asset_code)
    elif not (asset.deposit_enabled and asset.sep24_enabled):
        return render_error_response(
            _("invalid operation for asset %s") % asset_code)

    try:
        Keypair.from_public_key(stellar_account)
    except Ed25519PublicKeyInvalidError:
        return render_error_response(_("invalid 'account'"))

    try:
        rdi.save_sep9_fields(stellar_account, sep9_fields, lang)
    except ValueError as e:
        # The anchor found a validation error in the sep-9 fields POSTed by
        # the wallet. The error string returned should be in the language
        # specified in the request.
        return render_error_response(str(e))

    # Construct interactive deposit pop-up URL.
    transaction_id = create_transaction_id()
    Transaction.objects.create(
        id=transaction_id,
        stellar_account=account,
        asset=asset,
        kind=Transaction.KIND.deposit,
        status=Transaction.STATUS.incomplete,
        to_address=account,
        protocol=Transaction.PROTOCOL.sep24,
        memo=memo,
        memo_type=request.POST.get("memo_type") or Transaction.MEMO_TYPES.hash,
    )
    logger.info(f"Created deposit transaction {transaction_id}")

    url = interactive_url(
        request,
        str(transaction_id),
        account,
        asset_code,
        settings.OPERATION_DEPOSIT,
        amount,
    )
    return Response(
        {
            "type": "interactive_customer_info_needed",
            "url": url,
            "id": transaction_id
        },
        status=status.HTTP_200_OK,
    )
Пример #19
0
 def test_sign_without_secret_raise(self):
     data = b"Hello, Stellar!"
     can_not_sign_kp = Keypair.from_public_key(
         "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH")
     with pytest.raises(MissingEd25519SecretSeedError):
         can_not_sign_kp.sign(data)
Пример #20
0
 def test_read_secret_without_secret_raise(self):
     kp = Keypair.from_public_key(
         "GAXDYNIBA5E4DXR5TJN522RRYESFQ5UNUXHIPTFGVLLD5O5K552DF5ZH")
     with pytest.raises(MissingEd25519SecretSeedError):
         secret = kp.secret
Пример #21
0
def get_or_create_transaction_destination_account(
    transaction, ) -> Tuple[Optional[Account], bool, bool]:
    """
    Returns the stellar_sdk.account.Account for which this transaction's payment will be sent to as
    as well as whether or not the account was created as a result of calling this function.

    If the account exists, the function simply returns the account and False.

    If the account doesn't exist, Polaris must create the account using an account provided by the
    anchor. Polaris can use the distribution account of the anchored asset or a channel account if
    the asset's distribution account requires non-master signatures.

    If the transacted asset's distribution account does not require non-master signatures, Polaris
    can create the destination account using the distribution account. On successful creation,
    this function will return the account and True. On failure, a RuntimeError exception is raised.

    If the transacted asset's distribution account does require non-master signatures, the anchor
    should save a keypair of a pre-existing Stellar account to use as the channel account via
    DepositIntegration.create_channel_account().

    This channel account must only be used as the source account for transactions related to the
    ``Transaction`` object passed. It also must not be used to submit transactions by any service
    other than Polaris. If it is, the outstanding transactions will be invalidated due to bad
    sequence numbers. Finally, the channel accounts must have a master signer with a weight greater
    than or equal to the medium threshold for the account.

    After the transaction for creating the destination account has been submitted to the stellar network
    and the transaction has been created, this function will return the account and True. If the
    transaction was not submitted successfully, a RuntimeError exception will be raised.
    """
    try:
        account, json_resp = get_account_obj(
            Keypair.from_public_key(transaction.stellar_account))
        return account, False, has_trustline(transaction, json_resp)
    except RuntimeError:
        master_signer = None
        if transaction.asset.distribution_account_master_signer:
            master_signer = transaction.asset.distribution_account_master_signer
        thresholds = transaction.asset.distribution_account_thresholds
        if master_signer and master_signer["weight"] >= thresholds[
                "med_threshold"]:
            source_account_kp = Keypair.from_secret(
                transaction.asset.distribution_seed)
            source_account, _ = get_account_obj(source_account_kp)
        else:
            from polaris.integrations import registered_deposit_integration as rdi

            rdi.create_channel_account(transaction)
            source_account_kp = Keypair.from_secret(transaction.channel_seed)
            source_account, _ = get_account_obj(source_account_kp)

        base_fee = settings.HORIZON_SERVER.fetch_base_fee()
        builder = TransactionBuilder(
            source_account=source_account,
            network_passphrase=settings.STELLAR_NETWORK_PASSPHRASE,
            base_fee=base_fee,
        )
        transaction_envelope = builder.append_create_account_op(
            destination=transaction.stellar_account,
            starting_balance=settings.ACCOUNT_STARTING_BALANCE,
        ).build()
        transaction_envelope.sign(source_account_kp)

        try:
            settings.HORIZON_SERVER.submit_transaction(transaction_envelope)
        except BaseHorizonError as submit_exc:  # pragma: no cover
            raise RuntimeError(
                "Horizon error when submitting create account to horizon: "
                f"{submit_exc.message}")

        transaction.status = Transaction.STATUS.pending_trust
        transaction.save()
        logger.info(
            f"Transaction {transaction.id} is now pending_trust of destination account"
        )
        account, json_resp = get_account_obj(
            Keypair.from_public_key(transaction.stellar_account))
        return account, True, has_trustline(transaction, json_resp)
    except BaseHorizonError as e:
        raise RuntimeError(
            f"Horizon error when loading stellar account: {e.message}")
Пример #22
0
 def test_signature_hint(self, public_key, hint):
     assert Keypair.from_public_key(public_key).signature_hint() == hint
Пример #23
0
from stellar_sdk.keypair import Keypair

# create a random keypair
print("create a random keypair")
kp = Keypair.random()
print("Secret: {}".format(kp.secret))
print("Public Key: {}".format(kp.public_key))
print("")

# create a keypair from secret
print("create a keypair from secret")
secret = "SBRR6ZPBHHTDXYSFRZR2QZCGDZURNE5ON4M4F3HQA42G3Z62SFCR7EEJ"
kp = Keypair.from_secret(secret)
print("Secret: {}".format(kp.secret))
print("Public Key: {}".format(kp.public_key))
print("")

# create a keypair from public key
print("create a keypair from public key")
public_key = "GDCZ6JDZMWYORTIHEO2E4ZXKBQ2TLXNRQJPJH5RCFN7Q7I24G4RGLXP6"
kp = Keypair.from_public_key(public_key)
print("Public Key: {}".format(kp.public_key))
Пример #24
0
 def _is_valid_key(self, public_key):
     try:
         Keypair.from_public_key(public_key=public_key)
         return True
     except Ed25519PublicKeyInvalidError:
         raise InvalidStellarAddressException("Invalid stellar address")