Integrating Stellar Payments into a Django Web Application

ki3ani

Kenneth Kimani

Posted on August 19, 2024

Integrating Stellar Payments into a Django Web Application

This is a submission for the Build Better on Stellar: Smart Contract Challenge : Create a Tutorial

Introduction

In this tutorial, we're excited to guide you through the process of integrating Stellar payments into your Django web application. If you've ever wanted to add Stellar’s powerful payment capabilities to your app, you're in the right place!

We'll start with the basics, walking you through the setup required to connect your Django application to the Stellar network. You’ll learn how to create Stellar accounts directly from your app, check balances to keep track of funds, send payments effortlessly, and handle other operations.

Whether you're looking to implement a simple payment system or build a more complex financial feature, this guide will provide you with the tools and knowledge you need. Along the way, we'll cover key concepts, show you how to use the Stellar SDK in Python, and offer practical examples to make the integration process smooth and straightforward.

What I Created

In this tutorial, I developed a Django web application with seamless Stellar payment integration. This application serves as a practical example for developers looking to incorporate Stellar’s powerful payment capabilities into their own Django projects.

Key Features of the Application:

  • User Registration and Profile Management with JWT authentication: Users can easily register and manage their profiles within the application. This includes updating profile details and managing account settings.
  • Stellar Account Management: Users can create new Stellar accounts directly from the application, making it easy to get started with Stellar payments.
  • Account Funding: The application allows users to fund their Stellar accounts, providing a straightforward way to add assets to their accounts.
  • Sending Payments: Users can send payments to other Stellar accounts, facilitating smooth and efficient transactions.
  • Transaction History: Users can view their transaction history, keeping track of all payment activities and account changes.

Supporting the Stellar Developer Experience

This tutorial is designed to simplify the integration of Stellar payments into Django applications. By following the guide, developers will gain hands-on experience with the Stellar SDK and learn how to:

  • Set Up Stellar Payments: Understand the setup process for integrating Stellar into a Django app, including configuring Stellar accounts and transactions.
  • Use Stellar’s Features: Explore how to leverage Stellar’s capabilities for creating and managing accounts, sending payments, and more.
  • Implement Best Practices: Learn best practices for integrating Stellar payments, ensuring that the application is secure, efficient, and user-friendly.

How This Tutorial Helps Other Developers

This tutorial provides a clear, step-by-step guide to integrating Stellar payments with Django, making it an invaluable resource for developers interested in blockchain and financial technology. It offers:

  • Simplified Integration: A straightforward approach to adding Stellar functionality, reducing the complexity of working with blockchain technologies.
  • Comprehensive Coverage: A detailed walkthrough that covers all essential aspects of Stellar integration, from account creation to transaction management.

By following this tutorial, developers will not only learn how to integrate Stellar payments but also gain a deeper understanding of how to work with Stellar’s API and SDK in a Django environment. This knowledge can be applied to various applications, from financial services to e-commerce platforms, expanding their capabilities and enhancing their projects.

Journey

Creating this tutorial was a fascinating journey filled with learning and exploration. Here’s a glimpse into the process, motivations, and experiences that shaped this project:

Research and Content Creation

My journey began with a deep dive into the Stellar ecosystem and the Python Stellar SDK. I explored Stellar’s documentation, tutorials, and various resources to understand how to effectively integrate Stellar payments into a Django web application. The goal was to bridge the gap between Stellar’s blockchain technology and Django’s robust web framework, providing a seamless and practical solution for developers.

During the research phase, I focused on:

  • Understanding Stellar’s API: Learning how Stellar’s API works, including account creation, funding, and transaction management.
  • Exploring Django Integration: Figuring out the best ways to incorporate Stellar functionality into Django, ensuring smooth interactions between the web application and the Stellar network.
  • Identifying Best Practices: Gathering best practices for implementing blockchain technology in web applications to ensure security, efficiency, and a great user experience.

Motivation Behind the Submission

The motivation for this project stemmed from a desire to make blockchain technology more accessible to developers who are familiar with Django but may be new to Stellar. By creating a practical, easy-to-follow tutorial, I aimed to help others integrate Stellar payments into their projects without the steep learning curve.

What I Learned

Throughout this process, I gained a deeper understanding of:

  • Stellar’s Capabilities: How Stellar’s network supports various financial operations and how to leverage its features in a web application.
  • Django Integration: Best practices for integrating external services into Django applications, ensuring smooth interactions and data handling.
  • Developer Experience: The challenges and solutions involved in creating a user-friendly tutorial that balances technical depth with practical guidance.

Experience with the Ecosystem

Working with Stellar and Django was an enriching experience. The Stellar ecosystem is vibrant and developer-friendly, offering a wealth of resources and support. Django, on the other hand, provided a robust framework for building web applications with ease. Combining these technologies highlighted the strengths of both platforms and demonstrated how they can work together effectively.

Looking ahead, I hope to:

  • Expand the Tutorial: Add more advanced features and examples to cover additional use cases and scenarios.
  • Contribute to the Community: Share insights and improvements with the Stellar and Django communities, fostering collaboration and innovation.
  • Explore Further Integration: Investigate additional ways to leverage blockchain technology in web applications, exploring new possibilities and applications.

Prerequisites

Before diving into the integration of Stellar payments with Django, ensure you have the following prerequisites in place:

  • Basic Knowledge of Django: Familiarity with Django's core concepts, including models, views, templates, and URL routing. If you're new to Django, consider reviewing the official Django documentation or completing a basic Django tutorial.

  • Stellar Network Understanding: A basic understanding of how the Stellar network operates, including key concepts like Stellar accounts, transactions, and assets. You can start with the Stellar documentation.

  • Python Programming Skills: Proficiency in Python, as the integration will involve writing Python code to interact with the Stellar network.

  • Stellar SDK for Python: Knowledge of the Stellar SDK for Python, which will be used to interact with the Stellar network. Familiarize yourself with the Stellar SDK documentation.

  • Development Environment: Ensure you have a working development environment for Django applications. This includes a code editor (like VSCode or PyCharm), Python, and Django installed on your machine.

  • API Keys and Stellar Network Setup: If you're planning to interact with the Stellar testnet or mainnet, you'll need to set up API keys and have a Stellar account ready. This guide will focus on using the testnet for development purposes.

Installation

To get started with integrating Stellar payments into your Django application, follow these steps to set up your development environment and install the necessary dependencies.

1. Create a Virtual Environment

Using a virtual environment is a best practice in Python development to manage project-specific dependencies and avoid conflicts. To create and activate a virtual environment, run the following commands:

# Create a virtual environment
python -m venv env

# Activate the virtual environment
# On Windows
env\Scripts\activate
# On macOS/Linux
source env/bin/activate
Enter fullscreen mode Exit fullscreen mode

2. Install Dependencies

With your virtual environment activated, you'll need to install the required dependencies for the project. This includes the Stellar SDK for Python, which is essential for interacting with the Stellar network.

Stellar SDK for Python

The Stellar SDK for Python provides a convenient way to interact with the Stellar blockchain from your Python application. It includes features for account creation, transaction handling, and more. To install the SDK, run:

pip install stellar-sdk
Enter fullscreen mode Exit fullscreen mode

Besides the Stellar SDK, you'll need to install Django,DRF and simplejwt for authentication:

pip install django djangorestframework djangorestframework-simplejwt
Enter fullscreen mode Exit fullscreen mode

Now that we have installed the dependencies we can now start

Building the Application

In this section, we’ll discuss the core components of the Django application and how they work together to provide Stellar payment functionalities. We’ll explore views, utilities, models, serializers, and URLs, and show how they integrate with the Stellar network.

1. Views

Views in Django handle the request/response cycle. They process incoming requests, interact with the data models, and return responses to the client. Here's a breakdown of the views used in our application:

StellarAccountViewSet

This viewset manages Stellar accounts, allowing users to perform actions such as creating an account, funding an account, checking balance, sending payments, and viewing transaction history.

Key Methods:

  • create_account: Creates a new Stellar account using the create_stellar_account utility function and saves it to the database.
  • fund_account: Funds an existing Stellar account using the fund_account utility function.
  • check_balance: Checks the balance of the user’s Stellar account using the check_account_balance utility function.
  • send_payment: Sends payments to other Stellar accounts using the send_payment utility function.
  • transaction_history: Retrieves the transaction history for the user’s Stellar account using the get_transaction_history utility function.

Code Snippet:

class StellarAccountViewSet(viewsets.ModelViewSet):
    queryset = StellarAccount.objects.all()
    serializer_class = StellarAccountSerializer
    permission_classes = [IsAuthenticated]

    @action(detail=False, methods=['post'])
    def create_account(self, request):
        public_key, secret_seed = create_stellar_account()
        if public_key and secret_seed:
            account = StellarAccount(user=request.user, account_id=public_key)
            account.set_secret_seed(secret_seed)
            account.save()
            return Response({'public_key': public_key, 'secret_seed': secret_seed})
        return Response({'error': 'Failed to create the account'}, status=400)

    @action(detail=False, methods=['post'])
    def fund_account(self, request):
        public_key = request.data.get('public_key')

        if not public_key:
            return Response({'error': 'Public key is required'}, status=400)

        try:
            response = fund_account(public_key)
            return Response({'status': 'success', 'response': response})
        except Exception as e:
            return Response({'error': str(e)}, status=400)

    @action(detail=False, methods=['get'])
    def check_balance(self, request):
        account = StellarAccount.objects.get(user=request.user)
        balances = check_account_balance(account.account_id)
        return Response({'balances': balances})

    @action(detail=False, methods=['post'])
    def send_payment(self, request):
        serializer = SendPaymentSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data

        from_account = StellarAccount.objects.get(user=request.user)

        balance = check_account_balance(from_account.account_id)
        if any(b['asset_type'] == 'native' and float(b['balance']) < data['amount'] for b in balance):
            return Response({'error': 'Insufficient balance'}, status=400)

        secret_seed = from_account.get_secret_seed()  # Decrypt the secret seed
        response = send_payment(from_account, data['to_account'], data['amount'], secret_seed=secret_seed)
        return Response({'response': response})

    @action(detail=False, methods=['get'])
    def transaction_history(self, request):
        account = StellarAccount.objects.get(user=request.user)
        transactions = get_transaction_history(account.account_id)
        return Response({'transactions': transactions})
Enter fullscreen mode Exit fullscreen mode

2. Utilities

Utility functions perform the actual operations with the Stellar network, such as account creation, funding, and payment transactions.

Key Functions:

  • create_stellar_account: Creates a new Stellar account and returns the public key and secret seed.
  • check_account_balance: Checks the balance of a Stellar account.
  • send_payment: Sends a payment to another Stellar account.
  • get_transaction_history: Retrieves the transaction history for a Stellar account.
  • fund_account: Funds a Stellar account.

Code Snippet:

def get_fernet():
    return Fernet(settings.SECRET_KEY.encode())

def encrypt_data(data):
    fernet = get_fernet()
    encrypted = fernet.encrypt(data.encode())
    return encrypted.decode()

def decrypt_data(data):
    fernet = get_fernet()
    decrypted = fernet.decrypt(data.encode())
    return decrypted.decode()

def create_stellar_account():
    keypair = Keypair.random()
    public_key = keypair.public_key
    secret_seed = keypair.secret

    try:
        fund_account(public_key)
        return public_key, secret_seed
    except Exception as e:
        print(f"Error funding account: {e}")
        return None, None

def fund_account(public_key):
    friendbot_url = "https://friendbot.stellar.org"
    response = requests.get(friendbot_url, params={"addr": public_key}) 

    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Failed to fund account: {response.text}")

def check_account_balance(account_id):
    server = Server(horizon_url="https://horizon-testnet.stellar.org")
    account = server.accounts().account_id(account_id).call()
    return account['balances']

def send_payment(from_account, to_account, amount, asset_code="XLM", asset_issuer=None):
    server = Server(horizon_url="https://horizon-testnet.stellar.org")
    source_keypair = Keypair.from_secret(from_account.get_secret_seed())  # Decrypt secret seed
    source_account = server.load_account(account_id=from_account.account_id)
    base_fee = server.fetch_base_fee()

    if asset_code == "XLM":
        asset = Asset.native()
    else:
        asset = Asset(asset_code, asset_issuer)

    transaction = TransactionBuilder(
        source_account=source_account,
        network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE,
        base_fee=base_fee
    ).add_text_memo("Test Transaction").append_payment_op(
        destination=to_account,
        amount=str(amount),
        asset=asset
    ).build()

    transaction.sign(source_keypair)
    response = server.submit_transaction(transaction)
    return response

def get_transaction_history(account_id):
    server = Server(horizon_url="https://horizon-testnet.stellar.org")
    transactions = server.transactions().for_account(account_id).call()
    return transactions['_embedded']['records']
Enter fullscreen mode Exit fullscreen mode

3. Models

In this section, we'll define the models used to handle Stellar account information and user profiles in your Django application.

StellarAccount Model

The StellarAccount model is responsible for storing information about Stellar accounts linked to users.

  • Purpose: Links Stellar accounts to Django users and manages sensitive data securely.
  • Fields:
    • user: A OneToOneField linking each Stellar account to a Django User.
    • account_id: A CharField storing the public key for the Stellar account.
    • secret_seed: A CharField for storing the encrypted secret seed used for transactions.
    • created_at: A DateTimeField that automatically records the account creation timestamp.
  • Methods:
    • set_secret_seed(secret_seed): Encrypts and sets the secret seed.
    • get_secret_seed(): Decrypts and retrieves the secret seed.

Example:

class StellarAccount(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    account_id = models.CharField(max_length=56)
    secret_seed = models.CharField(max_length=256)  # Increased length for encrypted data
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.account_id

    def set_secret_seed(self, secret_seed):
        self.secret_seed = encrypt_data(secret_seed)

    def get_secret_seed(self):
        return decrypt_data(self.secret_seed)
Enter fullscreen mode Exit fullscreen mode

We can also include the model for user profiles:


class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=30, blank=True)
    last_name = models.CharField(max_length=30, blank=True)
    email = models.EmailField(blank=True)
    profile_picture = models.ImageField(upload_to='profile_pictures/', blank=True, null=True)

    def __str__(self):
        return self.user.username
Enter fullscreen mode Exit fullscreen mode

4. Serializers Overview

In this section, we define the serializers used to handle data validation and transformation for the Stellar account, user profile, and payment operations.

StellarAccountSerializer

The StellarAccountSerializer manages serialization and deserialization of StellarAccount model instances.

  • Purpose: Converts StellarAccount model instances to JSON and vice versa.
  • Fields:
    • user
    • account_id
    • secret_seed
    • created_at
from rest_framework import serializers
from .models import StellarAccount

class StellarAccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = StellarAccount
        fields = ['user', 'account_id', 'secret_seed', 'created_at']
Enter fullscreen mode Exit fullscreen mode

and

SendPaymentSerializer

The SendPaymentSerializer handles the serialization of payment data and includes validation for the payment amount.

  • Purpose: Validates and serializes payment requests.
  • Fields:
    • to_account: The Stellar account ID of the recipient.
    • amount: The amount to be sent.
from rest_framework import serializers
from pydantic import ValidationError

class SendPaymentSerializer(serializers.Serializer):
    to_account = serializers.CharField(max_length=56)
    amount = serializers.DecimalField(max_digits=10, decimal_places=2)

    def validate_amount(self, value):
        if value <= 0:
            raise ValidationError("Amount must be greater than zero.")
        return value
Enter fullscreen mode Exit fullscreen mode

We should also add serializers for user management

class UserProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserProfile
        fields = ['user', 'first_name', 'last_name', 'email', 'profile_picture']


class UserRegistrationSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ['username', 'password']
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = get_user_model().objects.create_user(**validated_data)
        UserProfile.objects.create(user=user)
        return user
Enter fullscreen mode Exit fullscreen mode

and finally we can add URLs map incoming requests to the appropriate views in the urls.py:

from django.urls import path, include
from rest_framework.routers import DefaultRouter

from .views import StellarAccountViewSet, UserProfileViewSet


router = DefaultRouter()
router.register(r'stellar_accounts', StellarAccountViewSet)
router.register(r'user_profiles', UserProfileViewSet)


urlpatterns = [
    path('', include(router.urls)),
]

Enter fullscreen mode Exit fullscreen mode

We can now be able to test our app using Postman to see our app at work

Postman Testing

Create Account

Image description

Sending Payments

Image description

Check Balance

Image description

Token

Image description

We are using jwt for authentication

Register

Image description

Transaction History

Image description

User Profile

Image description

A user profile is create on create for every user

In this tutorial, we explored how to integrate Stellar payments into a Django web application. We covered the setup of Stellar accounts, encrypted sensitive data, managed user profiles, and implemented the functionality for sending payments. By following these steps, you can now leverage the power of Stellar's blockchain technology to facilitate secure and efficient transactions within your Django projects. You can also have a look at the GitHub repo here: GitHub link.

💖 💪 🙅 🚩
ki3ani
Kenneth Kimani

Posted on August 19, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related