This is a submission for the Build Better on Stellar: Smart Contract Challenge : Build a dApp
What I Built
Stellar360: A Comprehensive Stellar WebApp with Wallet, Exchange, Staking, Payment Gateway, and Faucet Functionality
Stellar360 is a sophisticated web application developed using Next.js, Node.js, and PostgreSQL, designed to offer an all-in-one solution for Stellar-based transactions.
The platform features:
Wallet Functionality: Users can register, and upon successful registration, a wallet is automatically created. The wallet supports custom tokens—STLLRUSDC, STLLRUSDT, STLLRBTC, and STLLRCSH—allowing users to view and manage their balances.
Token Faucet: Users can utilize the faucet to add tokens to their wallet and check their balances in real-time.
Token Exchange: Users can exchange one token for another seamlessly within the app.
Staking: The app supports staking of tokens with flexible time periods (7, 15, 30, 60, and 90 days). A custom smart contract, built using Soroban Stellar, manages the staking process and credits the tokens back to users' wallets at the end of the staking period. A master wallet is used to distribute the earned tokens to users.
Payment Gateway: Users can generate multiple child wallets for their websites. These wallets facilitate payments from customers, with successful transactions triggering WebSocket notifications to complete orders. Each customer gets a unique wallet for processing payments.
Paymaster Contract: To ensure smooth transactions, a paymaster contract is implemented to cover transaction fees in XLM. This contract enhances user experience by making transactions frictionless and cost-effective.
Automated Trustlines: Trustlines for the custom tokens are automatically created, ensuring seamless and successful transactions.
Whole code can be checked by referring the github links, Below are some code snippets which are the backbone contracts for this project -
Paymaster contract
The paymaster contract on Stellar is designed to pay for the transaction fees (in XLM) for users who do not have XLM in their accounts. The contract will also support whitelisting of addresses that are authorized to use the paymaster's services.
Features:
- Pay for Transaction Fees: The paymaster covers the XLM fees for transactions initiated by whitelisted addresses.
- Whitelist Management: Admin can add or remove addresses from the whitelist.
Components:
- Paymaster Contract: Manages the payment of transaction fees.
- Whitelist Management: Allows adding/removing addresses to/from the whitelist.
use soroban_sdk::{contractimpl, Address, Env, Symbol, Vec};
pub struct Paymaster;
#[contractimpl]
impl Paymaster {
// Initialize the contract with an admin address
pub fn initialize(env: Env, admin: Address) {
let whitelist = Vec::new();
env.storage().set(&Symbol::from("admin"), &admin);
env.storage().set(&Symbol::from("whitelist"), &whitelist);
}
// Add an address to the whitelist
pub fn add_to_whitelist(env: Env, address: Address) {
let admin = env.storage().get::<Address>(&Symbol::from("admin")).unwrap();
if env.caller() != admin {
panic!("Only admin can add to whitelist");
}
let mut whitelist: Vec<Address> = env.storage().get(&Symbol::from("whitelist")).unwrap();
if !whitelist.contains(&address) {
whitelist.push(address);
env.storage().set(&Symbol::from("whitelist"), &whitelist);
}
}
// Remove an address from the whitelist
pub fn remove_from_whitelist(env: Env, address: Address) {
let admin = env.storage().get::<Address>(&Symbol::from("admin")).unwrap();
if env.caller() != admin {
panic!("Only admin can remove from whitelist");
}
let mut whitelist: Vec<Address> = env.storage().get(&Symbol::from("whitelist")).unwrap();
whitelist.retain(|a| a != &address);
env.storage().set(&Symbol::from("whitelist"), &whitelist);
}
// Check if an address is whitelisted
pub fn is_whitelisted(env: Env, address: Address) -> bool {
let whitelist: Vec<Address> = env.storage().get(&Symbol::from("whitelist")).unwrap();
whitelist.contains(&address)
}
// Pay for transaction fees
pub fn pay_transaction_fee(env: Env, source: Address, fee: u64) {
if !Self::is_whitelisted(env.clone(), source.clone()) {
panic!("Address not whitelisted");
}
// Here, you would include logic to cover the fee.
// This typically involves interacting with Stellar to handle the fee.
// For demonstration purposes, we'll print the action.
println!("Paying {} XLM for transaction fee for {}", fee, source);
}
}
Staking Contract
The contract allows users to stake tokens for predefined periods, earning rewards based on the duration of their stake.
Features
- Staking Periods: Users can choose from five staking periods—7, 15, 30, 60, or 90 days.
- Reward Percentages: The reward percentage increases with the length of the staking period—0.1%, 2%, 5%, 10%, or 15%.
- Token Management: Users can stake tokens, and after the staking period ends, they can claim their tokens along with the rewards.
use soroban_sdk::{contractimpl, symbol, Address, Env, Symbol};
#[derive(Clone, Copy, Debug)]
pub enum StakingPeriod {
SevenDays,
FifteenDays,
ThirtyDays,
SixtyDays,
NinetyDays,
}
#[derive(Clone, Copy, Debug)]
pub enum RewardPercentage {
PointOnePercent,
TwoPercent,
FivePercent,
TenPercent,
FifteenPercent,
}
pub struct StakingContract;
#[contractimpl]
impl StakingContract {
pub fn stake_tokens(env: Env, user: Address, amount: u64, period: StakingPeriod) {
// Logic to handle token staking
let current_time = env.ledger().now();
let end_time = match period {
StakingPeriod::SevenDays => current_time + 7 * 24 * 60 * 60,
StakingPeriod::FifteenDays => current_time + 15 * 24 * 60 * 60,
StakingPeriod::ThirtyDays => current_time + 30 * 24 * 60 * 60,
StakingPeriod::SixtyDays => current_time + 60 * 24 * 60 * 60,
StakingPeriod::NinetyDays => current_time + 90 * 24 * 60 * 60,
};
// Store staking information
let staking_info = StakingInfo {
amount,
end_time,
period,
};
// Here, you would typically store this information in a state variable
// For demonstration, we will just print it
env.log(&format!(
"User: {:?}, Amount: {}, End Time: {}, Period: {:?}",
user, amount, end_time, period
));
}
pub fn claim_rewards(env: Env, user: Address) {
// Logic to calculate and distribute rewards
// This would involve checking if the staking period is over
// and calculating rewards based on the stored staking info
// For demonstration, we will just print a message
env.log(&format!("User: {:?} claiming rewards", user));
}
}
#[derive(Clone, Debug)]
pub struct StakingInfo {
amount: u64,
end_time: u64,
period: StakingPeriod,
}
Demo
You can explore the Stellar360 dApp through the following link: Live Demo
My Code
The source code for Stellar360 is available on GitHub:
Frontend Repository: Link to Frontend Repository
Backend Repository: Link to Backend Repository
Journey
Developing Stellar360 has been an exciting and challenging journey. The project began with the goal of creating a unified platform to manage and interact with Stellar assets, incorporating wallet, exchange, staking, and payment functionalities.
Implementation and Smart Contract Design:
- Smart Contracts: We utilized Soroban Stellar to create a custom smart contract for managing staking, ensuring accurate token credits at the end of each staking period.
- Paymaster Contract: The paymaster contract was designed to handle transaction fees, thus eliminating the need for users to hold XLM for transaction costs.
Motivation:
Our motivation was to simplify the user experience by integrating multiple features into a single platform, providing users with a seamless and efficient way to manage their Stellar assets.
Learning and Experience:
Throughout the development process, we deepened our understanding of Stellar’s ecosystem, smart contract capabilities, and efficient token management. We also gained insights into integrating various functionalities to enhance user experience.
Pride and Future Goals:
We are particularly proud of the seamless integration of diverse functionalities and the automation of trustline creation. Moving forward, we aim to refine the user experience further, gather user feedback, and explore additional enhancements based on real-world usage.
Top comments (0)