Building a NFT minting bot with Cardano, Telegram, and Python - part 2
Part 2: Our data storage backend for the bot
We need some sort of data storage for each bot session, so let's look at that.
Outline
- Intro: Overview
- Part 1: Building a simple bot with Python 3
- Part 2: Our data storage backend for the bot <- You are here.
- Part 3: Using IPFS utils
- Part 4: Using Token utils
- Part 5: Finishing the conversation
Intro
There are a few different choices to make in regards to data storage during a bot session. We need a way to store some variables on each session. Mainly we are passing data between the bot's conversation points. The Telegram API allows for storing data within the user's context, but that is fairly limited to a basic key/value type data structure. There are a few other data points needed and I felt that a simple database would work so I used the Python model sqlalchemy
to read and write from the SQLite DB on the host.
The cardano-cli
outputs to actual files for keys, and metadata. I tried to get around this, but that would have ended up with more reads and writes on the file system. So I opted to just use the cardano-cli
in its intended form.
OK, so let's walk through the db_model.py
script to see how it works.
Walk through the db_model.py
First, we need to import the needed models from sqlalchemy
. We then build up an engine and the Session.
from sqlalchemy import Column, Integer, \
String, DateTime, Boolean
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql.functions import current_timestamp
from sqlalchemy import create_engine
import config
engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
Session = sessionmaker(bind=engine)
Base = declarative_base()
In the config.py
file we setup sqlalchemy
to save the database as a file tokens_testnet.db
. You can send the data to a MySQL database if you want, but I am keeping it simple here.
import os
# Database
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
db_path = os.path.join(BASE_DIR, 'tokens_testnet.db')
SQLALCHEMY_DATABASE_URI = f'sqlite:///{db_path}'
SQLALCHEMY_TRACK_MODIFICATIONS = True
Next, we build out our Tokens table. See the inline comments for what the attributes are for.
class Tokens(Base):
""" Individual Token data """
__tablename__ = 'tokens'
id = Column(
Integer,
primary_key=True,
autoincrement=True
)
date_created = Column(
DateTime,
default=current_timestamp()
)
# Token Bot Session UUID
session_uuid = Column(String())
# Creator Details
creator_username = Column(String())
creator_pay_addr = Column(String())
# Token Details
token_ticker = Column(String(5))
token_name = Column(String(128))
token_desc = Column(String(128))
token_number = Column(Integer, default=0)
# Added, for future use with generic Native Tokens?
token_amount = Column(Integer, default=1)
token_ipfs_hash = Column(String(50))
# Stake Keys and Payment Keys
stake_keys_created = Column(Boolean, default=False)
payment_keys_created = Column(Boolean, default=False)
# The bot ADA address for funding
bot_payment_addr = Column(String(128))
# The blockchain protocol parameters
protocol_params_created = Column(Boolean, default=False)
policy_keys_created = Column(Boolean, default=False)
policy_script_created = Column(Boolean, default=False)
policy_keyhash = Column(String(64))
policy_id = Column(String(64))
# Our Slot information
current_slot = Column(Integer)
slot_cushion = Column(Integer)
invalid_after_slot = Column(Integer)
# Token metadata.json
metadata_created = Column(Boolean, default=False)
# UTXO to burn from bot payment_addr
utxo_tx_hash = Column(String(64))
utxo_tx_ix = Column(Integer)
utxo_lovelace = Column(Integer)
# Mint Transaction
raw_tx_created = Column(Boolean, default=False)
signed_tx_created = Column(Boolean, default=False)
tx_submitted = Column(Boolean, default=False)
token_tx_hash = Column(String(64))
# We need atleast a uuid to initialize a session
def __init__(self, session_uuid):
self.session_uuid = session_uuid
# Respond with the uuid and token ticker
def __repr__(self):
return f"{self.session_uuid} - {self.token_ticker}"
Special call out to the update()
function as it takes a python dictionary, breaks it out, and sets each attribute in the table. I found this on StackOverflow a long time ago and thought it was pretty clever, so I tend to include it in most of my Sqlalchemy sessions. I will be using it later in the token_utils.py
script.
def update(self, **kwargs):
""" Updates a Token information """
for key, value in kwargs.items():
setattr(self, key, value)
Wrapping up
Finally, let's wrap up with the main()
function that actually creates the DB.
def main():
""" Creates the DB with Token table """
Base.metadata.create_all(engine)
# Create a session, and commit it
session = Session()
session.commit()
session.close()
print("Created DB")
if __name__ == '__main__':
main()
When we run the script it creates a DB session and writes out the Tokens table.
cmd$ python db_model.py
Created DB
OK, we have a database, let's recap working with IPFS next.