Integrating Stellar Payments into a Django Web Application
Kenneth Kimani
Posted on August 19, 2024
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
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
Besides the Stellar SDK, you'll need to install Django,DRF and simplejwt for authentication:
pip install django djangorestframework djangorestframework-simplejwt
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 thecreate_stellar_account
utility function and saves it to the database. -
fund_account
: Funds an existing Stellar account using thefund_account
utility function. -
check_balance
: Checks the balance of the user’s Stellar account using thecheck_account_balance
utility function. -
send_payment
: Sends payments to other Stellar accounts using thesend_payment
utility function. -
transaction_history
: Retrieves the transaction history for the user’s Stellar account using theget_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})
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']
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
: AOneToOneField
linking each Stellar account to a DjangoUser
. -
account_id
: ACharField
storing the public key for the Stellar account. -
secret_seed
: ACharField
for storing the encrypted secret seed used for transactions. -
created_at
: ADateTimeField
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)
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
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']
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
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
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)),
]
We can now be able to test our app using Postman to see our app at work
Postman Testing
Create Account
Sending Payments
Check Balance
Token
We are using jwt for authentication
Register
Transaction History
User Profile
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.
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
August 19, 2024
August 19, 2024