示例#1
0
def fee(request):
    """
    Definition of the /fee endpoint, in accordance with SEP-0006.
    See: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0006.md#fee
    """
    # Verify that the asset code exists in our database:
    asset_code = request.GET.get("asset_code")
    if not asset_code or not Asset.objects.filter(name=asset_code).exists():
        return render_error_response("invalid 'asset_code'")
    asset = Asset.objects.get(name=asset_code)

    # Verify that the requested operation is valid:
    operation = request.GET.get("operation")
    if operation not in (OPERATION_DEPOSIT, OPERATION_WITHDRAWAL):
        return render_error_response(
            f"'operation' should be either '{OPERATION_DEPOSIT}' or '{OPERATION_WITHDRAWAL}'"
        )
    # Verify that amount is provided, and that it is parseable into a float:
    amount_str = request.GET.get("amount")
    try:
        amount = float(amount_str)
    except (TypeError, ValueError):
        return render_error_response("invalid 'amount'")

    # Validate that the operation, and the specified type (if provided)
    # are applicable to the given asset:
    op_type = request.GET.get("type", "")
    if not _op_type_is_valid(asset_code, operation, op_type):
        return render_error_response(
            f"the specified operation is not available for '{asset_code}'")

    return Response({"fee": calc_fee(asset, operation, amount)})
示例#2
0
def interactive_deposit(request):
    """
    `GET /deposit/interactive_deposit` opens a form used to input information
    about the deposit. This creates a corresponding transaction in our
    database, pending processing by the external agent.
    """
    # Validate query parameters: account, asset_code, transaction_id.
    account = request.GET.get("account")
    if not account:
        return render_error_response("no 'account' provided")

    asset_code = request.GET.get("asset_code")
    if not asset_code or not Asset.objects.filter(name=asset_code).exists():
        return render_error_response("invalid 'asset_code'")

    transaction_id = request.GET.get("transaction_id")
    if not transaction_id:
        return render_error_response("no 'transaction_id' provided")

    # GET: The server needs to display the form for the user to input the deposit information.
    if request.method == "GET":
        form = DepositForm()
    # POST: The user submitted a form with the amount to deposit.
    else:
        if Transaction.objects.filter(id=transaction_id).exists():
            return render_error_response(
                "transaction with matching 'transaction_id' already exists"
            )
        form = DepositForm(request.POST)
        asset = Asset.objects.get(name=asset_code)
        form.asset = asset
        # If the form is valid, we create a transaction pending external action
        # and render the success page.
        if form.is_valid():
            amount_in = form.cleaned_data["amount"]
            amount_fee = calc_fee(asset, settings.OPERATION_DEPOSIT, amount_in)
            transaction = Transaction(
                id=transaction_id,
                stellar_account=account,
                asset=asset,
                kind=Transaction.KIND.deposit,
                status=Transaction.STATUS.pending_external,
                amount_in=amount_in,
                amount_fee=amount_fee,
                to_address=account,
            )
            transaction.save()

            serializer = TransactionSerializer(
                transaction,
                context={"more_info_url": _construct_more_info_url(request)},
            )
            tx_json = json.dumps({"transaction": serializer.data})
            return render(request, "deposit/success.html", context={"tx_json": tx_json})
    return render(request, "deposit/form.html", {"form": form})
def interactive_deposit(request):
    # Validate query parameters: account, asset_code, transaction_id.
    account = request.GET.get("account")
    if not account:
        return render_error_response("no 'account' provided")

    asset_code = request.GET.get("asset_code")
    if not asset_code or not Asset.objects.filter(name=asset_code).exists():
        return render_error_response("invalid 'asset_code'")

    transaction_id = request.GET.get("transaction_id")
    if not transaction_id:
        return render_error_response("no 'transaction_id' provided")

    # GET: The server needs to display the form for the user to input the deposit information.
    if request.method == "GET":
        form = DepositForm()
    # POST: The user submitted a form with the amount to deposit.
    else:
        if Transaction.objects.filter(id=transaction_id).exists():
            return render_error_response(
                "transaction with matching 'transaction_id' already exists"
            )
        form = DepositForm(request.POST)
        asset = Asset.objects.get(name=asset_code)
        form.asset = asset
        # If the form is valid, we create a transaction pending external action
        # and render the success page.
        if form.is_valid():
            amount_in = form.cleaned_data["amount"]
            amount_fee = calc_fee(asset, settings.OPERATION_DEPOSIT, amount_in)
            transaction = Transaction(
                id=transaction_id,
                stellar_account=account,
                asset=asset,
                kind=Transaction.KIND.deposit,
                status=Transaction.STATUS.pending_external,
                amount_in=amount_in,
                amount_fee=amount_fee,
            )
            transaction.save()
            create_stellar_deposit.delay(transaction.id)
            # TODO: Use the proposed callback approach.
            return render(request, "deposit/success.html")
    return render(request, "deposit/form.html", {"form": form})
def interactive_withdraw(request):
    """
    `GET /withdraw/interactive_withdraw` opens a form used to input information about
    the withdrawal. This creates a corresponding transaction in our database.
    """
    transaction_id = request.GET.get("transaction_id")
    if not transaction_id:
        return render_error_response("no 'transaction_id' provided")

    asset_code = request.GET.get("asset_code")
    if not asset_code or not Asset.objects.filter(name=asset_code).exists():
        return render_error_response("invalid 'asset_code'")

    # GET: The server needs to display the form for the user to input withdrawal information.
    if request.method == "GET":
        form = WithdrawForm()

    # POST: The user submitted a form with the withdrawal info.
    else:
        if Transaction.objects.filter(id=transaction_id).exists():
            return render_error_response(
                "transaction with matching 'transaction_id' already exists")
        form = WithdrawForm(request.POST)
        asset = Asset.objects.get(name=asset_code)
        form.asset = asset

        # If the form is valid, we create a transaction pending user action
        # and render the success page.
        if form.is_valid():
            amount_in = form.cleaned_data["amount"]
            amount_fee = calc_fee(asset, settings.OPERATION_WITHDRAWAL,
                                  amount_in)

            # We use the transaction ID as a memo on the Stellar transaction for the
            # payment in the withdrawal. This lets us identify that as uniquely
            # corresponding to this `Transaction` in the database. But a UUID4 is a 32
            # character hex string, while the Stellar HashMemo requires a 64 character
            # hex-encoded (32 byte) string. So, we zero-pad the ID to create an
            # appropriately sized string for the `HashMemo`.
            transaction_id_hex = uuid.UUID(transaction_id).hex
            withdraw_memo = "0" * (
                64 - len(transaction_id_hex)) + transaction_id_hex
            transaction = Transaction(
                id=transaction_id,
                stellar_account=settings.STELLAR_ACCOUNT_ADDRESS,
                asset=asset,
                kind=Transaction.KIND.withdrawal,
                status=Transaction.STATUS.pending_user_transfer_start,
                amount_in=amount_in,
                amount_fee=amount_fee,
                withdraw_anchor_account=settings.STELLAR_ACCOUNT_ADDRESS,
                withdraw_memo=withdraw_memo,
                withdraw_memo_type=Transaction.MEMO_TYPES.hash,
            )
            transaction.save()

            serializer = TransactionSerializer(transaction)
            tx_json = json.dumps({"transaction": serializer.data})
            return render(request,
                          "withdraw/success.html",
                          context={"tx_json": tx_json})
    return render(request, "withdraw/form.html", {"form": form})