Dev Challenge: A Soroban Crowdfactoring dApp
Nacho Colomina Torregrosa
Posted on August 17, 2024
This is a submission for the Build Better on Stellar: Smart Contract Challenge : Build a dApp
What I Built
I have built a Crowdfactoring decentralized application capable to connect companies looking for funds to finance their projects with investors who want to participate on those projects and get a return for participating.
Users can withdraw their earnings and reinvest it in other projects thus taking advantage of the magic of compound interest.
I've decided to give the dApp the name of "Crowdfactoring" since this dApp would be more focused on finance specific projects or assets within any company and Crowdfunding is more often used to fund a business, specially start-ups.
Demo
You can check the application demo following this link: https://main-bvxea6i-aferydywmbeug.eu.platformsh.site/
Get some Test USDC tokens
Before getting USDC tokens, you will have to install a wallet (I recommend freighter-wallet. It's the wallet i've been used to test the application).
Once you have installed it, follow this instructions to add the USDC Soroban token to your wallet (USDC contract ID: CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA).
Now, having the token added on your wallet, you can proceed by two ways:
1.- Swap XLM by USDC: You can use the swap button (third button in the wallet bottom) to exchange some of your XLM by USDC.
2.- Get USDC from the Circle Faucet: You can go to the circle faucet and send some USDC to your wallet address.
How to navigate within the demo
Let's see how to use the application demo by following an example. Imagine that the GreenCycle company wants to get funds for its new recycling initative so it registers on this crowdfactoring platform to achieve this goal. First of all, GreenCycle enters into the application link and press on the Start Here Button.
After clicking, the user is redirected to the login page.
Click on the link bellow "Register here to get an account". It will redirect you to the register page:
Create a new company user. Introduce an email, a name and a password. In the last field, select the "company" type. Click on the "Register" button and, after registered, you will be redirected to the login page. After being redirected, login with your recently created user.
Before creating a new contract, click on the Tokens List option of the left menu. This will show you the current available tokens which can be used to send deposits to the contracts.
The available token for this demo is the Circle USDC token which is deployed on the Stellar Testnet. You can see more information here.
In a real application deployed on the Mainnet, we could add the EURC token and another stable-coins deployed as Stellar Contract Assets.
In the left menu, click on the Create Contract option. You will be redirected to a form to fill the required data to deploy the contract.
In the above image, we are going to create a contract to raise funds for the new GreenCycle recycling project. The form fields specify the following:
- The funds will be deposited using the Circle USDC token.
- The users will be rewarded with an 8.5 interest rate after the period finishes.
- The users must keep the investment during 6 months.
- The short description and large description describe the project.
If the data is correct, press the "Create Contract" button to deploy the contract. This can take a few seconds since it has to communicate with Stellar to deploy and install the contract. Then, you will be redirected to your contracts list.
As you can see, the row shows the contract address which ensures that the contract has been installed successfully on the Stellar Network. The first check (Initialized) indicates us that the contract has not been initialized yet. It means that the contract is installed but the contract init function needs to be called to set the main setting parameters: rate, months for claim, token and the admin address. To do it, simply click on the Initialize button and, after a few seconds, the page will reload and you will see that the initialized check is now OK and the Initialize button has been disabled.
If you click on the Edit button, you will see the contract information and the current contract funds (which are retrieved calling the contract get_contract_balance function).
The image does not show the "Withdraw funds" button. This is because this functionality was added after writing this section. As the contract have not been received funds yet, this button should be disabled.
As the image shows, the current funds is 0 since we have not received any deposit yet. The Stop Receiving Deposits button calls the contract stop_deposits function and change the contract state so no more deposits will be allowed. This can be used when the company considers that it's been reached enough funds.
Now, it's time to receive some funds so let's logout and log-in as an investor. Click on the logout menu option. You will return to the landing page. Go to the login page again by clicking on the Start Here button. Go then to the Register page and create a new user but this time using the "Investor" type. After being redirected, login with the new user.
You will be redirected to the user portfolio which, at the moment, is empty . Click on the menu Available Offers option to navigate within the available offers to invest.
Here we can see the recently created GreenCycle offer. It shows us a description about the project and the conditions bellow. Let's click on the "I want to invest" button to make a deposit.
You may see more offers available. This is because I've also tested the dApp and created my users, contracts and deposits. Click on the offer you've been created.
Once we are redirected, a modal is shown (stellar wallets kit modal) which requires us to select the wallet we are going to use to send the deposit. After selecting it, we will see a form which asks us for the amount we want to invest.
Enter the desired amount and click on the "Send Deposit" button. Your wallet will be prompted to approve and sign the transaction.
Make sure you have enough USDC tokens in your wallet address to send the deposit.
After the deposit has been sent, you will be redirected to your portfolio where you can see the information about your investment.
I've had an issue with the stellar wallet. If you take some time (more than 10 or 15 seconds maybe) to confirm the transaction, the wallet does not send the transaction and you have to reload the form.
The main information of the above image is the following:
- Withdrawal date: When you will be able to withdraw funds.
- Deposited: The amount deposited.
- Expected interests: The interests you are going to generate.
- Total to claim: The total you will be able to claim.
Now, click on the Edit button of the end of the row:
As the withdrawal date has not been reached yet, the Withdraw funds button is disabled.
Let's going back to the GreenCycle account and edit again the contract information:
As you can see, now the contract has funds since a user has been made a deposit.
You should also see the button "Withdraw funds" enabled since the company has already received funds. If you click on that button, your wallet will be prompted and, after signing the transaction, the funds will be sent to your address. After processed, the page will reload. It is possible that after reloading, the funds will still be displayed as before. This may be because the transaction has not yet been fully confirmed. If you wait a bit and reload again, you will see that the total funds will be 0.
My Code
This project code is divided in two repositories: The Smart Contract and the Decentralized Application. Below you can find the links to both repositories:
- Smart Contract: https://github.com/icolomina/soroban-contracts/tree/main/paid_account
- Dapp: https://github.com/icolomina/soroban-crowdfactoring-dapp
The smart contract code is part of a global repository where I have all my smart contracts. It is similar to the Stellar's soroban-examples repository. The README of that repository is located here: https://github.com/icolomina/soroban-contracts.
Implementation
Smart Contract
The Smart Contract is in charge of managing user deposits and withdrawals. Each contract represents a company project to invest in . After the contract is deployed and initialized (by using the contract init function), users can start to invest on the project by making deposits (by using the contract user_deposit function). When the contract receives a user deposit, it stores the user address balance and the total amount (deposited + interests) that the user will be able to claim once the investment period has been reached.
The contract also has functions that only the company which offers the project can call. This functions allow companies to withdraw funds to start the project and deposit funds to the contract so that, when users withdraw their earnings, the contract has sufficient funds.
The following figure shows the contract flow diagram:
Let's analyze it:
- When a company wants to fund a project, it creates and initializes a new contract.
- After the contract is initialized, it is ready to receive deposits.
- Users only can send a deposit per contract.
- Users only can withdraw their earnings after the deposit period is reached.
- Companies can withdraw funds so that they can start their projects.
- Companies can send deposits so that the contract has sufficient funds to satisfy the investors' withdrawals.
Now, let's enumerate the contract functions:
-
init: This function stores the following configuration parameters:
- admin_addr: The contract administrator address (This address will be the same that deploys and installs the contract).
- token_addr: The token used to send the funds. This dApp uses the Circle USDC token which is deployed in the Stellar Testnet.
- i_rate: Interest rate users will receive by keeping their tokens deposited.
- claim_block_days: Number of days during which the deposit must be maintained.
admin_deposit: This function is used by the companies to send deposits to the contract to ensure the contract has enough funds when users claim their earnings.
user_deposit: This function can be executed by the users who want to invest. It receives the user address which is sending the funds and the amount. The function transfers the funds to the contract address and writes the user address balance.
get_contract_balance: This function can only be executed by the admin address. It returns the contract address balance so that companies can know how much funds have been reached.
user_withdrawal: This function can be executed by the users to withdraw their earnings (deposited + interests). It will panic if the deposit period has not been reached yet.
admin_withdrawal: This function is used by the companies to withdraw the contract funds and start their projects.
stop_deposits: This function can only be executed by the admin address. It allows companies to change the contract status so that no more deposits will be accepted. It can be used when the company has been reached the funds they wanted to.
Dapp
Technical Overview
The following points provide a high-level overview of the dApp tech stack:
- Smart Contract: Developed in Rust and deployed to the Stellar Testnet.
- Backend: Built using PHP and the Symfony Framework, responsible for user authentication, contract management etc.
- Database: PostgreSQL database to store user data, contracts, and transactions. In the case of contracts, the address is stored and in the case of transactions (function calls) the transaction hash is stored.
- Frontend: Developed using Twig, React, Typescript and the Bootstrap CSS Framework. It provides a user interface for companies and investors.
- Contract interaction: The backend uses the Soneso Stellar SDK Component, while the Frontend uses the Stellar Js SDK and The Stellar Wallets Kit to choose the wallet and sign the transactions.
Architecture
In this section, I am describing the main Dapp functionalities. I am going to divide it in two parts:
-
Companies processes: The companies processes are those which can only be executed by company users. Some of this processes communicates with Soroban following a custodial model and the others follows a non-custodial model.
- Deploying contracts, initializing contracts, stopping deposits and getting contract funds follows a custodial model. The PHP/Symfony backend stores a KeyPair which is used to perform these operations.
- Companies deposits and withdrawals follows a non-custodial model ,that is, companies must connect their wallets to perform such operations as users do.
User Processes: The user processes follows a non-custodial model. Users must use their wallets to sign transactions and be able to send deposits and withdraw funds.
Let's start with the companies processes:
1.- How do companies create contracts and how are they stored on the Stellar network?
Let's analyze the flow diagram:
- A company wants to create a contract and posts the required data: Token to use (The Dapp allows the Circle USDC token deployed in the Stellar Testnet), the interest rate, the deposit period in months, a label and a description.
- If the data is valid, the contract is registered in the Dapp database (PostgreSQL).
- After been registered, the Dapp uses the PHP Soneso Stellar SDK to deploy and install the contract.
- After installed, the contract data (PostgreSQL) is updated with the contract address so that the functions can be called later.
2.- How do companies initialize a contract ?
Initializing a contract requires calling the contract init method. Let's analyze the flow diagram:
- A company wants to initialize a contract so it sends a request with the contract ID.
- The Dapp gets the contract data from the PostgreSQL database using the ID.
- The Dapp calls the contract init function using the Soneso Stellar SDK.
- Once the contract has been initialized, the Dapp updates the contract data flagging it as initialized.
3.- How a company can stop contract deposits ?
Stopping contract deposits requires calling the stop_deposits contract function. Let's analyze the flow:
- A company considers that its contract has enough funds and wants to stop deposits so it sends the corresponding request with the contract ID.
- The Dapp gets the contract address from the PostgreSQL database by using the ID.
- The Dapp calls the stop_deposits contract function.
- After the deposits have been stopped, the Dapp updates the contract data flagging it as "Funds Reached".
So far, we have analyzed the companies processes. Let's study now the user processes:
4.- How a user can send a deposit ?
Sending a deposit involves calling the contract user_deposit function. Let's analyze the flow:
- A user selects a deposit offer he wants to invest to.
- The Stellar Wallets kit opens a modal to select the wallet. (If no supported wallet is installed, the user will have to install one and get funds).
- After selecting a wallet, the user enters the amount to invest.
- The wallet is prompted so that the user can review and sign the transaction.
- After the transaction is sent, if there are no errors, the transaction is registered in the PostgreSQL database.
The Dapp takes into account the token number of decimals and normalize the amount before sending the transaction.
5.- How a user can withdraw funds ?
Withdrawal funds involves calling the contract user_withdrawal function. Let's analyze the flow:
- A user selects a deposit from the portfolio
- If the deposit period has been reached, the user must select the wallet before continuing.
- The user reviews and sign the transaction.
- If there are no errors, the user deposit is flagged as "Withdrawn" in the PostgreSQL database.
The admin withdraw and deposit processes are very similar to the user ones. The main difference is that, when a company wants to withdraw the contract funds, all the funds are sent to the company wallet.
Motivation
The main motivation to develop this Dapp was to create a easy, fast and inclusive way for companies to get funds and for users to invest. I am aware that there are currently crowdfactoring platforms, but this platforms depends on intermediaries (normally banks) to manage transfers and investments which presents the following disadvantages:
Centralized Control and Intermediary Risks: This can lead to risks such as fraud, mismanagement, or even bankruptcy, which can result in the loss of investor funds. Additionally, banks (even countries or central banks) may impose their own rules, regulations, and fees, which can limit the flexibility and accessibility of the crowdfactoring platform.
Higher Costs and Complexity: Traditional banks often charge various fees for their services, including transfer fees, administrative charges, and interest rates. These costs can add up quickly, reducing the returns for investors and increasing the burden on companies seeking funding. Furthermore, the involvement of banks can introduce complexity into the investment process, requiring additional paperwork, documentation, and compliance measures. This can slow down the funding process and create barriers to entry for smaller companies or individual investors.
This decentralized way focused on using smart-contracts in the Soroban platform removes the need of using banking intermediaries and relies on the Stellar Blockchain to register transactions and manage balances. This opens the gate for more people and companies to invest and finance their projects. Furthermore, the Dapp uses stable coins (The Circle USDC deployed to the Stellar Testnet) to manage the investments. This ensures low volatility since those assets are backed by the main FIAT currencies (USD, EUR ...).
Another advantage would be that deposits are sent in a matter of seconds (the time the blockchain takes to register the transaction) so that an investor does not have to wait a few days until the bank sends the money.
Finally, people can send the deposits using his own non-custodial wallet which gives them more control about their funds.
Drawbacks
As a drawback, we must highlight that, although we can reduce or even remove the use of intermediaries, this dApp should comply with the different countries regulations. These regulations usually include KYC (Know Your Customer) and AML (Anti Money Laundering) procedures which can delay the register process both for companies and investors. For instance, in the case of Europe, this dApp must comply with the requirements of MiCA.
What I have learned
I have been participated in other Soroban challenges such as Sorobanathon and Sorobounties Spectacular, but this challenge has been different. I have improved my react skills and I've learned how to integrate Backend and Frontend using the Symfony UX initiative. Besides, I've also learned how to deploy an application to the Platform.sh cloud.
I specially would like to mention that I have learned that web2 and web3 can live together and combining them can take us to develop incredible applications.
These Dapp combines an strong web2 environment (mainly composed of PHP, Symfony and React) with the a web3 environment which relies on the Stellar network and Soroban contracts. While the web2 (or off-chain) part is in charge of authenticating users, managing roles, register transactions data, prompt wallets etc, the web3 (or on-chain) part is in charge of register deposits in the blockchain, deploying and installing contracts, manage withdrawals and balances etc. The Soneso Stellar SDK and the Javascript Stellar SDK are the bridges to connect the web2 world with the web3 world.
Dapp improvements
There are many improvements that could be applied to this dApp. Among them, i would like to list the following:
-
Authentication:
- Add Two factor Authentication (Mobile App, Passkeys etc).
- Use DID (Digital Decentralized Identifiers).
-
Withdrawal:
- Allow transfer funds from a deposit that has been reached the period to another one the user wants to invest to. This would save the investor time since it would not be necessary to withdraw funds to the wallet and send another deposit later.
-
Predefined Offers portfolio:
- The Dapp could propose a set of investment offers to the user based on some criteria (sustainable level, expected profitability, period etc). The user will send a deposit to an intermediate contract which will deliver the specified funds for each offer.
Additional Prize Categories: Super Sustainable
I think that this Dapp should be considered for the sustainable prize category, not because the project itself is sustainable but because the own project nature. As this Dapp offers an innovative, fast and inclusive way to fund companies projects, those start-ups or companies whose business model is based on innovation through the generation and implementation of projects that improve environmental care and the relationship between humans and the planet can find here a way to fastly get funds and involve users in initiatives to improve our environment.
Conclusion
There are not many more words I can add. It's been stimulating to participate in this challenge and i've enjoyed developing this dApp. I simply hope you like it and you enjoy this post. Thanks for reading.
Posted on August 17, 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