Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MVP for XDC ChatPay #19

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ yarn-debug.log*
yarn-error.log*
lerna-debug.log*

/xdcchatpay

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

Expand Down
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: gunicorn app:app
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## Inspiration
Although crytpto and blockchain has been on an increase in developing nations, there has been slow uptake due to low literacy levels, trust, device constraints and the lack of cash on/off ramps.

We are looking at building and launching XDC ChatPay as a simple yet effective remittance solution that addresses the challenges above. Being simple yet effective, our solution will drive users to use the remittance platform which has been built on the XDC network in order to increase adoption.

## What it does

XDC ChatPay allows users to easily on/off ramp by voucher top-ups or withdrawals directly to and from accounts using the [1Voucher](https://1foryou.com/) service, users are also able to send and receive funds in seconds. We are looking into adding additional functionalities like purchasing of utility vouchers, airtime, and allowing for scanning of QR codes for easy payments

## How we built it

The MVP was built using:

**Twilio for the Whatsapp messaging functionality**
**Python Flask app for the backend**
**Tatum.io for the XDC chain account integration**
**Heroku for hosting**

## Challenges we ran into

When ran into challenges when conneting the XinFin api endpoints on Tatum for account creation, however I was able to overcome this and get it to work. Also, doing the user research proved to be challenging because of time constraints. The business approval time on the 1Voucher platform is lengthy so I was not able to include the live voucher authentication to the demo

## Accomplishments that we're proud of

We managed to build a working MVP using the mainnet endpoints,

## What we learned

We learned a lot about the XinFin chain and also about designing simple yet effective systems.

## What's next for XDC ChatPay

Implement live voucher integration
Improve on application and user security
Add additional functionality to application

## TO run the application locally

- Create an account on Twilio
- Install ngrok
- Create a Python virtual environment
- PIP install the requirements.txt file
- Run the flask application
- Connect the ngrok endpoint to your Twilio account and start sending XDC ChatPay messages.
125 changes: 125 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import click
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from twilio.twiml.messaging_response import MessagingResponse
from messages import Messages

from registered_users import RegisteredUsers
from user import User
from wallet_handler import WalletHandler

app = Flask(__name__)

registered_users = RegisteredUsers()

wallet_handler = WalletHandler()

message_template = Messages()

@app.route('/')
def index():
return 'XDC ChatPay'

@app.route('/chat', methods=['POST'])
def chat():

resp = MessagingResponse()

print(request.form)
incoming_msg = request.values.get('Body', '').lower()

responded = False

if incoming_msg == 'hello xdc':
resp.message(message_template.home_menu())
responded = True

elif incoming_msg == '1':
resp.message(message_template.register_menu())
responded = True

elif incoming_msg == '2':
incoming_msg = request.values.get('WaId', '').lower()
user = registered_users.get_user(incoming_msg)
if user is None:
resp.message(message_template.wallet_not_found())
responded = True
else:
wallet = user.get_wallet()
resp.message(message_template.view_wallet(wallet_address=wallet))
responded = True

elif incoming_msg == '3':
incoming_msg = request.values.get('WaId', '').lower()
user = registered_users.get_user(incoming_msg)
if user is None:
resp.message(message_template.wallet_not_found())
responded = True
else:
wallet = user.get_wallet()
balance = wallet_handler.get_balance(wallet)
resp.message(message_template.wallet_balance(balance=balance))
responded = True


elif incoming_msg == '4':
resp.message(message_template.new_payment())
responded = True

elif incoming_msg == '5':
resp.message(message_template.top_up_menu())
responded = True

elif incoming_msg == '6':
incoming_msg = request.values.get('WaId', '').lower()
user = registered_users.get_user(incoming_msg)
if user is None:
resp.message(message_template.wallet_not_found())
responded = True
else:
wallet = user.get_wallet()
transactions = wallet_handler.get_transactions(wallet)
resp.message(message_template.transaction_history(transactions=transactions))
responded = True


elif incoming_msg == '7':
resp.message(message_template.withdraw_menu())
responded = True

elif incoming_msg == '8':
resp.message(message_template.exit_menu())
responded = True

elif len(incoming_msg.split(" ")) == 2 and incoming_msg.split()[0] == 'register':
name = incoming_msg.split()[1]
account_number, accountId = wallet_handler.create_wallet(name)
key = request.values.get('WaId', '').lower()
user = registered_users.register(User(name,account_number,accountId, key))
resp.message(message_template.wallet_created(accountId))
responded = True

elif len(incoming_msg.split(" ")) == 2 and incoming_msg.split()[0] == 'topup':
voucher = incoming_msg.split()[1]
user_number = request.values.get('WaId', '').lower()
user = registered_users.get_user(user_number)
topup_response = wallet_handler.buy_xdc(user.get_accountId())
resp.message(message_template.top_up_success())
responded = True

elif len(incoming_msg.split(" ")) == 3 and incoming_msg.split()[0] == 'pay':
wallet_address = incoming_msg.split()[1]
amount = incoming_msg.split()[2]
user_number = request.values.get('WaId', '').lower()
user = registered_users.get_user(user_number)
payment_response = wallet_handler.send_xdc(wallet_address, amount)
resp.message(message_template.payment_sent(amount, wallet_address))
responded = True

if not responded:
resp.message("Sorry, I don't understand.")
return str(resp)

if __name__ == '__main__':
app.run(debug=True)
# app.run(host='localhost', port=8080, debug=True)

123 changes: 123 additions & 0 deletions messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import random


class Messages:
def __init__(self):
pass

def home_menu(self):
return """
1. Register a wallet
2. View wallet
3. View balance
4. Send XDC
5. Buy XDC
6. Transactions
7. Withdraw XDC with 1Voucher
7. Exit
"""

def register_menu(self):
return """
Please enter your username in one word:
example: register JohnSmith123
"""

def wallet_created(self, wallet_address):
return """
Thank you for registering your wallet.
Your wallet address is: {0}
""".format(wallet_address)

def wallet_not_created(self):
return """
Sorry, your wallet could not be created.
Please try again.
"""

def wallet_not_found(self):
return """
Sorry, your wallet could not be found.
Please try again.
"""

def view_wallet(self, wallet_address):
return """
Your wallet address is: {0}
""".format(wallet_address)

def wallet_balance(self, balance):
return """
Your wallet balance is: {0}
""".format(balance)

def new_payment(self):
return """
Enter; pay + wallet/number + an amount.
example: pay 123456789 100
"""

def payment_sent(self, amount, address):
return """
You have sent {0} XDC to {1}
""".format(amount, address)

def payment_not_sent(self):
return """
Sorry, your payment could not be sent.
Please try again.
"""

def payment_received(self, amount, address):
return """
You have received {0} XDC from {1}
""".format(amount, address)

def transaction_history(self, transactions):
return """
Your transaction history is:
{0}
""".format(transactions)

def top_up_menu(self):
return """
Please enter topup + your 1Voucher reference number:
example: topup 123456789
"""

def top_up_success(self):
return """
You have successfully toped up your wallet with 50 XDC.
"""

def top_up_failure(self):
return """
Sorry, your top up could not be completed.
Please try again.
"""

def withdraw_menu(self):
return """
Please withdraw + the amount you wish to withdraw:
example: withdraw 100
"""

def withdraw_success(self, amount):
return """
You have successfully withdrawn {0} XDC.
Your 1Voucher reference is: {1}
""".format(amount, self.generate_reference())

def withdraw_failure(self):
return """
Sorry, your withdrawal could not be completed.
Please try again.
"""

def exit_menu(self):
return """
Thank you for using XDC ChatPay.
"""

def generate_reference(self):
return str(random.randint(1000000, 9999999))
27 changes: 27 additions & 0 deletions registered_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class RegisteredUsers():

def __init__(self):
self.registered_users = {}

def register(self, user):
if user.number in self.registered_users:
return False
else:
self.registered_users[user.number] = user
return True

def get_user(self, number):
if number in self.registered_users:
return self.registered_users[number]
else:
return None

def get_all_users(self):
return self.registered_users

def delete_user(self, number):
if number in self.registered_users:
del self.registered_users[number]
return True
else:
return False
Binary file added requirements.txt
Binary file not shown.
20 changes: 20 additions & 0 deletions user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class User:

def __init__(self, username, account_number, wallet, number):
self.username = username
self.account_number = account_number
self.accountId = wallet
self.number = number
self.verification_code = None

def set_wallet(self, wallet):
self.wallet = wallet

def get_accountId(self):
return self.accountId

def get_account_number(self):
return self.wallet

def set_verification_code(self, verification_code):
self.verification_code = verification_code
Loading