diff --git a/crypto/sol/modules/storage.py b/crypto/sol/modules/storage.py new file mode 100644 index 0000000..2003934 --- /dev/null +++ b/crypto/sol/modules/storage.py @@ -0,0 +1,214 @@ +import aiosqlite +import json +from datetime import datetime + +DATABASE_FILE = "app_data.db" + +async def init_db(): + async with aiosqlite.connect(DATABASE_FILE) as db: + await db.executescript(""" + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + email TEXT UNIQUE NOT NULL, + api_key TEXT UNIQUE, + plan TEXT DEFAULT 'free' + ); + + CREATE TABLE IF NOT EXISTS wallets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + address TEXT NOT NULL, + name TEXT, + FOREIGN KEY (user_id) REFERENCES users(id) + ); + + CREATE TABLE IF NOT EXISTS transactions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + wallet_id INTEGER, + timestamp TEXT, + type TEXT, + sell_currency TEXT, + sell_amount REAL, + sell_value REAL, + buy_currency TEXT, + buy_amount REAL, + buy_value REAL, + closed BOOLEAN DEFAULT 0, + details TEXT, + FOREIGN KEY (wallet_id) REFERENCES wallets(id) + ); + + CREATE TABLE IF NOT EXISTS holdings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + wallet_id INTEGER, + currency TEXT, + amount REAL, + last_updated TEXT, + FOREIGN KEY (wallet_id) REFERENCES wallets(id) + ); + + CREATE TABLE IF NOT EXISTS price_alerts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + currency TEXT, + target_price REAL, + alert_type TEXT, + FOREIGN KEY (user_id) REFERENCES users(id) + ); + + CREATE TABLE IF NOT EXISTS followed_accounts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + address TEXT, + followed_address TEXT, + name TEXT, + FOREIGN KEY (address) REFERENCES wallets(address), + FOREIGN KEY (followed_address) REFERENCES wallets(address), + FOREIGN KEY (user_id) REFERENCES users(id) + ); + """) + await db.commit() + +async def store_transaction(wallet_id, transaction_type, sell_currency, sell_amount, sell_value, buy_currency, buy_amount, buy_value, details=None): + async with aiosqlite.connect(DATABASE_FILE) as db: + await db.execute(""" + INSERT INTO transactions (wallet_id, timestamp, type, sell_currency, sell_amount, sell_value, buy_currency, buy_amount, buy_value, details) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, (wallet_id, datetime.now().isoformat(), transaction_type, sell_currency, sell_amount, sell_value, buy_currency, buy_amount, buy_value, json.dumps(details or {}))) + await db.commit() + +async def update_holdings(wallet_id, currency, amount_change): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute("SELECT amount FROM holdings WHERE wallet_id = ? AND currency = ?", (wallet_id, currency)) + result = await cursor.fetchone() + if result: + new_amount = result[0] + amount_change + await db.execute("UPDATE holdings SET amount = ?, last_updated = ? WHERE wallet_id = ? AND currency = ?", + (new_amount, datetime.now().isoformat(), wallet_id, currency)) + else: + await db.execute("INSERT INTO holdings (wallet_id, currency, amount, last_updated) VALUES (?, ?, ?, ?)", + (wallet_id, currency, amount_change, datetime.now().isoformat())) + await db.commit() + +async def get_wallet_holdings(wallet_id): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute("SELECT currency, amount FROM holdings WHERE wallet_id = ?", (wallet_id,)) + return await cursor.fetchall() + +async def get_transaction_history(wallet_id, start_date=None, end_date=None, include_closed=False): + async with aiosqlite.connect(DATABASE_FILE) as db: + query = "SELECT * FROM transactions WHERE wallet_id = ?" + params = [wallet_id] + if not include_closed: + query += " AND closed = 0" + if start_date: + query += " AND timestamp >= ?" + params.append(start_date) + if end_date: + query += " AND timestamp <= ?" + params.append(end_date) + query += " ORDER BY timestamp DESC" + cursor = await db.execute(query, params) + return await cursor.fetchall() + +# New utility functions + +async def close_transaction(transaction_id): + async with aiosqlite.connect(DATABASE_FILE) as db: + await db.execute("UPDATE transactions SET closed = 1 WHERE id = ?", (transaction_id,)) + await db.commit() + +async def get_open_transactions(wallet_id, currency): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute(""" + SELECT * FROM transactions + WHERE wallet_id = ? AND buy_currency = ? AND closed = 0 + ORDER BY timestamp ASC + """, (wallet_id, currency)) + return await cursor.fetchall() + +async def calculate_current_holdings(wallet_id): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute(""" + SELECT + buy_currency AS currency, + SUM(buy_amount) - COALESCE( + (SELECT SUM(sell_amount) + FROM transactions t2 + WHERE t2.wallet_id = t1.wallet_id + AND t2.sell_currency = t1.buy_currency + AND t2.closed = 0), + 0 + ) AS amount + FROM transactions t1 + WHERE wallet_id = ? AND closed = 0 + GROUP BY buy_currency + HAVING amount > 0 + """, (wallet_id,)) + return await cursor.fetchall() + +STABLECOINS = ['USDC', 'USDT', 'SOL'] + +async def is_transaction_closed(wallet_id, transaction_id): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute(""" + SELECT t1.buy_currency, t1.buy_amount, + (SELECT SUM(sell_amount) + FROM transactions t2 + WHERE t2.wallet_id = t1.wallet_id + AND t2.sell_currency = t1.buy_currency + AND t2.timestamp > t1.timestamp) AS sold_amount + FROM transactions t1 + WHERE t1.id = ? AND t1.wallet_id = ? + """, (transaction_id, wallet_id)) + result = await cursor.fetchone() + + if result: + buy_currency, buy_amount, sold_amount = result + return sold_amount is not None and sold_amount >= buy_amount + return False + +async def close_completed_transactions(wallet_id): + async with aiosqlite.connect(DATABASE_FILE) as db: + cursor = await db.execute(""" + SELECT id FROM transactions + WHERE wallet_id = ? AND closed = 0 AND buy_currency NOT IN (?) + """, (wallet_id, ','.join(STABLECOINS))) + transactions = await cursor.fetchall() + + for (transaction_id,) in transactions: + if await is_transaction_closed(wallet_id, transaction_id): + await close_transaction(transaction_id) + +async def get_profit_loss(wallet_id, currency, start_date=None, end_date=None): + async with aiosqlite.connect(DATABASE_FILE) as db: + query = """ + SELECT + SUM(CASE WHEN sell_currency = ? THEN sell_value ELSE -buy_value END) as profit_loss + FROM transactions + WHERE wallet_id = ? AND (sell_currency = ? OR buy_currency = ?) + """ + params = [currency, wallet_id, currency, currency] + + if start_date: + query += " AND timestamp >= ?" + params.append(start_date) + if end_date: + query += " AND timestamp <= ?" + params.append(end_date) + + cursor = await db.execute(query, params) + result = await cursor.fetchone() + return result[0] if result else 0 + +# Example usage +if __name__ == "__main__": + import asyncio + + async def main(): + await init_db() + # Add more test functions here + + asyncio.run(main()) \ No newline at end of file