### Python Application Startup for Escrow Bot Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Initializes the Telegram bot application, sets up logging, database connection, and registers command handlers. It configures strategies for different blockchain types and starts the bot polling for updates. Dependencies include the 'telegram' library and internal modules for configuration, database, and handlers. ```python import logging from telegram.ext import Application, CommandHandler from src.config import settings from src.db.database import init_db from src.bot.handlers import start_command, help_command, get_escrow_conversation_handler from src.blockchain.bitcoin_strategy import BitcoinLikeStrategy from src.db.models import BlockchainType logger = logging.getLogger(__name__) def main(): """Initialize and start the bot.""" # Setup logging logging.basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO ) # Initialize database init_db(settings.DATABASE_URL) logger.info(f"Database initialized: {settings.DATABASE_URL}") # Initialize blockchain strategies bitcoin_like_strategy = BitcoinLikeStrategy( network=settings.BITCOIN_NETWORK, arbiter_privkey_wif=settings.ARBITER_PRIVATE_KEY ) STRATEGIES = { BlockchainType.BTC: bitcoin_like_strategy, BlockchainType.LTC: bitcoin_like_strategy, } TOKEN_TO_BLOCKCHAIN_TYPE = { "BTC": BlockchainType.BTC, "LTC": BlockchainType.LTC, "XMR": BlockchainType.XMR, } # Create Telegram application application = Application.builder().token(settings.TELEGRAM_BOT_TOKEN).build() # Store strategies in bot data for handler access application.bot_data['strategies_map'] = STRATEGIES application.bot_data['token_type_map'] = TOKEN_TO_BLOCKCHAIN_TYPE # Register command handlers application.add_handler(CommandHandler("start", start_command)) application.add_handler(CommandHandler("help", help_command)) application.add_handler(get_escrow_conversation_handler()) logger.info("Starting bot...") application.run_polling() if __name__ == "__main__": main() # Run the bot # python -m src.main ``` -------------------------------- ### Create Escrow Transaction via Telegram Bot Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Initiates a new escrow transaction between a buyer and seller for a specified amount and cryptocurrency. This command is sent by the buyer to the bot, which then facilitates the transaction setup. ```python # User interaction via Telegram # Buyer sends: /escrow @seller_username 100000 BTC # Bot creates transaction and sends confirmation request to seller # Conceptual implementation sketch (actual code would be in handlers.py and services.py) # from telegram import Update # from telegram.ext import ContextTypes # from src import services # async def escrow_command(update: Update, context: ContextTypes.DEFAULT_TYPE): # try: # # Parse arguments: seller_username, amount, currency # args = context.args # if len(args) != 3: # await update.message.reply_text("Usage: /escrow @seller_username ") # return # buyer_username = update.effective_user.username # seller_username = args[0].lstrip('@') # amount = float(args[1]) # currency = args[2].upper() # # Validate inputs (e.g., check if seller exists, amount is positive, currency is supported) # # ... validation logic ... # # Call service to create the escrow transaction # transaction = services.create_escrow_transaction( # buyer_username=buyer_username, # seller_username=seller_username, # amount=amount, # currency=currency # ) # await update.message.reply_text(f"Escrow transaction initiated for {amount} {currency}. Details: {transaction.id}") # # Further steps: Notify seller, create wallet/contract, etc. # except ValueError: # await update.message.reply_text("Invalid amount format. Please enter a number.") # except Exception as e: # logger.error(f"Error creating escrow: {e}") # await update.message.reply_text("An error occurred while creating the escrow transaction.") ``` -------------------------------- ### Initialize Bitcoin Strategy and Map Tokens Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt This snippet demonstrates the initialization of the BitcoinLikeStrategy for a specific network (e.g., 'testnet') and provides an arbiter's private key in WIF format. It also shows how to map different blockchain types (like BTC and LTC) and token symbols to their respective strategies and blockchain types within the application. ```Python # Example usage in application startup (src/main.py) from src.blockchain.bitcoin_strategy import BitcoinLikeStrategy from src.db.models import BlockchainType # Initialize Bitcoin strategy with testnet and arbiter key bitcoin_like_strategy = BitcoinLikeStrategy( network=settings.BITCOIN_NETWORK, # 'testnet' from .env arbiter_privkey_wif=settings.ARBITER_PRIVATE_KEY # WIF format key ) # Map blockchain types to strategies STRATEGIES = { BlockchainType.BTC: bitcoin_like_strategy, BlockchainType.LTC: bitcoin_like_strategy, # Same strategy for Litecoin } # Map token symbols to blockchain types TOKEN_TO_BLOCKCHAIN_TYPE = { "BTC": BlockchainType.BTC, "LTC": BlockchainType.LTC, "XMR": BlockchainType.XMR, } ``` -------------------------------- ### Initialize Database and Session Factory in Python Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Initializes the SQLAlchemy database engine and session factory. It also creates all defined database tables. The `get_db` function provides a session context manager, ensuring sessions are properly closed. ```python from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from .models import Base engine = None SessionLocal = None def init_db(database_url: str): """Initialize database engine, session factory, and create tables.""" global engine, SessionLocal engine = create_engine(database_url, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base.metadata.create_all(bind=engine) def get_db(): """Returns a new database session.""" if SessionLocal is None: raise RuntimeError("Database not initialized. Call init_db() first.") db = SessionLocal() try: yield db finally: db.close() ``` -------------------------------- ### Register User with Telegram Bot Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Handles user registration or welcomes existing users via the Telegram bot's /start command. It integrates with the database to create or retrieve user records. Requires the 'db_session' decorator and 'python-telegram-bot' library. ```python from telegram import Update from telegram.ext import ContextTypes from sqlalchemy.orm import Session # Assuming User and services are defined elsewhere # from src.database import db_session # from src import services, logger # from src.models import User # Placeholder for db_session decorator def db_session(func): def wrapper(*args, **kwargs): # In a real scenario, this would manage a DB session db = None # Mock session return func(*args, db=db, **kwargs) return wrapper # Placeholder for services.get_or_create_user class MockUser: def __init__(self, telegram_id, username): self.telegram_id = telegram_id self.username = username class MockServices: def get_or_create_user(self, db, telegram_user): # Mock user retrieval/creation logic print(f"Mock: Getting or creating user {telegram_user.id}") return MockUser(telegram_id=telegram_user.id, username=telegram_user.username) services = MockServices() # Placeholder for logger class MockLogger: def info(self, message): print(f"INFO: {message}") logger = MockLogger() # Mock Update and ContextTypes for standalone execution class MockMessage: def reply_text(self, text): print(f"Bot response: {text}") class MockUpdate: def __init__(self, user_id, username): self.effective_user = type('obj', (object,), {'id': user_id, 'username': username}) self.message = MockMessage() class MockContextTypes: DEFAULT_TYPE = None # Placeholder @db_session async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE, db=None): telegram_user = update.effective_user user = services.get_or_create_user(db, telegram_user) welcome_text = ( f"¡Hola, @{user.username}! 👋\n\n" "Bienvenido al Bot de Escrow de Criptomonedas. " "Usa este bot para realizar transacciones seguras con otros usuarios.\n\n" "Para ver todos los comandos disponibles, escribe /help." ) await update.message.reply_text(welcome_text) # Mock User model for standalone execution class User: def __init__(self, telegram_id, username): self.telegram_id = telegram_id self.username = username # Mock db.query and db.commit for standalone execution class MockSession: def query(self, model): print(f"Mock Query on {model.__name__}") return self def filter(self, condition): print(f"Mock Filter: {condition}") return self def first(self): print("Mock First: Returning None") return None def add(self, obj): print(f"Mock Add: {obj}") def commit(self): print("Mock Commit") # Example of how the function might be called (for demonstration) async def main(): mock_update = MockUpdate(user_id=12345, username="testuser") await start_command(mock_update, MockContextTypes.DEFAULT_TYPE) if __name__ == "__main__": import asyncio asyncio.run(main()) ``` -------------------------------- ### Python Application Configuration with Pydantic Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Defines application settings using Pydantic's BaseSettings for environment-based configuration. It includes types for Telegram bot token, optional arbiter private key, Bitcoin network, and database URL. Settings are loaded from a .env file. ```python # Configuration in src/config.py from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): """Centralized application settings with validation.""" TELEGRAM_BOT_TOKEN: str ARBITER_PRIVATE_KEY: str | None = None BITCOIN_NETWORK: str = "testnet" DATABASE_URL: str = "sqlite:///escrow.db" model_config = SettingsConfigDict(env_file=".env", env_file_encoding='utf-8') # Create singleton settings instance settings = Settings() # Environment variables in .env file """ TELEGRAM_BOT_TOKEN="your_telegram_bot_token_here" ARBITER_PRIVATE_KEY="cPrivateKeyInWIFFormat" BITCOIN_NETWORK="testnet" DATABASE_URL="sqlite:///escrow.db" """ ``` -------------------------------- ### Python DB Session Decorator for Async Handlers Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt A decorator that automates the lifecycle management of SQLAlchemy database sessions for asynchronous handler functions. It creates a session, injects it into the handler's keyword arguments as 'db', and ensures the session is closed after execution or upon error. This simplifies database interaction within handlers, preventing common session management errors. ```python import functools import logging from src.db.database import get_db logger = logging.getLogger(__name__) def db_session(func): """ Decorator that manages database session lifecycle. Creates a session, injects it as 'db' kwarg, and ensures proper cleanup. Handles exceptions and closes session in finally block. """ @functools.wraps(func) async def wrapper(*args, **kwargs): db = next(get_db()) logger.debug(f"DB session {id(db)} created for {func.__name__}") try: # Inject database session into function kwargs kwargs['db'] = db return await func(*args, **kwargs) except Exception as e: logger.error(f"Error in {func.__name__} with DB session {id(db)}: {e}") # Optionally: db.rollback() raise finally: logger.debug(f"Closing DB session {id(db)} for {func.__name__}") db.close() return wrapper # Usage example in handlers @db_session async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE, db=None): """Handler automatically receives 'db' parameter from decorator.""" telegram_user = update.effective_user user = services.get_or_create_user(db, telegram_user) # Use injected session await update.message.reply_text(f"Welcome, @{user.username}!") ``` -------------------------------- ### Generate Bitcoin-like Keys Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt This function generates a new random private key and derives its corresponding public key. It utilizes the bitcoin library for cryptographic operations. ```Python from bitcoin.wallet import P2SHBitcoinAddress, CBitcoinSecret from bitcoin.core import x, b2x from bitcoin.core.script import CScript, OP_2, OP_3, OP_CHECKMULTISIG class BitcoinLikeStrategy(BlockchainStrategy): def __init__(self, network='testnet', arbiter_privkey_wif: str = None): self.network = network self.arbiter_privkey = None self.arbiter_pubkey = None if arbiter_privkey_wif: self.arbiter_privkey = CBitcoinSecret(arbiter_privkey_wif) self.arbiter_pubkey = self.arbiter_privkey.pub logger.info("Arbiter private key loaded successfully.") logger.info(f"Initialized BitcoinLikeStrategy for network: {self.network}") def generate_keys(self): """Generates a new private key and derives its public key.""" private_key = CBitcoinSecret.from_random() public_key = private_key.pub return private_key, public_key ``` -------------------------------- ### Generate Bitcoin P2SH 2-of-3 Multisig Escrow Address Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt This method generates a P2SH (Pay-to-Script-Hash) address suitable for a 2-of-3 multi-signature escrow. It takes public keys of the buyer, seller, and arbiter as hexadecimal strings and returns the P2SH address along with its corresponding redeem script in hexadecimal format. Dependencies include the bitcoin library for script and address generation. ```Python from bitcoin.wallet import P2SHBitcoinAddress, CBitcoinSecret from bitcoin.core import x, b2x from bitcoin.core.script import CScript, OP_2, OP_3, OP_CHECKMULTISIG class BitcoinLikeStrategy(BlockchainStrategy): # ... (previous methods) def generate_escrow_address( self, buyer_pubkey_hex: str, seller_pubkey_hex: str, arbiter_pubkey_hex: str ) -> tuple[str, str]: """ Generates a 2-of-3 multi-signature P2SH address. Returns tuple of (address, redeem_script_hex). """ # Convert hex public keys to bytes buyer_pubkey = x(buyer_pubkey_hex) seller_pubkey = x(seller_pubkey_hex) arbiter_pubkey = x(arbiter_pubkey_hex) # Create the redeem script (2-of-3 multisig) # OP_2: 2 required signatures # Public keys # OP_3: 3 total public keys # OP_CHECKMULTISIG: verify signatures redeem_script = CScript([ OP_2, buyer_pubkey, seller_pubkey, arbiter_pubkey, OP_3, OP_CHECKMULTISIG ]) # Create P2SH address from redeem script p2sh_address = P2SHBitcoinAddress.from_script(redeem_script) logger.info(f"Generated P2SH Multi-sig address: {str(p2sh_address)}") # Return address and hex-encoded redeem script return str(p2sh_address), b2x(redeem_script) ``` -------------------------------- ### Create Escrow Transaction Service Function (Python) Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Handles the creation of a new escrow transaction. It validates tokens and blockchain strategies, retrieves or creates user records, generates necessary public keys and escrow addresses, and persists the transaction details to the database. Dependencies include a database session, user models, and strategy implementations. ```python from sqlalchemy.orm import Session from .models import User, EscrowTransaction, TransactionStatus from .exceptions import InvalidStrategyError, UserNotFoundError, SelfTransactionError from .strategies import strategies_map, token_type_map from .utils import get_or_create_user, logger def create_escrow_transaction( db: Session, *, buyer_tg_user, seller_username: str, amount: str, token: str, strategies_map: dict, token_type_map: dict ) -> EscrowTransaction: # Validate token and get blockchain strategy blockchain_type = token_type_map.get(token) if not blockchain_type: raise InvalidStrategyError(f"El token '{token}' no está soportado.") current_strategy = strategies_map.get(blockchain_type) if not current_strategy: raise InvalidStrategyError( f"La estrategia para '{token}' ({blockchain_type.name}) aún no está implementada." ) # Get or create buyer, verify seller exists buyer_db_user = get_or_create_user(db, buyer_tg_user) seller_db_user = db.query(User).filter(User.username == seller_username).first() if not seller_db_user: raise UserNotFoundError(f"El usuario '{seller_username}' no ha interactuado con el bot.") if buyer_db_user.id == seller_db_user.id: raise SelfTransactionError("No puedes realizar una transacción contigo mismo.") # Generate keys for all participants _, arbiter_pubkey_obj = current_strategy.get_arbiter_keys() _, buyer_pubkey_obj = current_strategy.generate_keys() _, seller_pubkey_obj = current_strategy.generate_keys() buyer_pubkey_hex = buyer_pubkey_obj.hex() seller_pubkey_hex = seller_pubkey_obj.hex() arbiter_pubkey_hex = arbiter_pubkey_obj.hex() # Generate escrow address and redeem script escrow_address, redeem_script_hex = current_strategy.generate_escrow_address( buyer_pubkey_hex=buyer_pubkey_hex, seller_pubkey_hex=seller_pubkey_hex, arbiter_pubkey_hex=arbiter_pubkey_hex ) # Create transaction record in database transaction = EscrowTransaction( buyer_id=buyer_db_user.id, seller_id=seller_db_user.id, blockchain_type=blockchain_type, escrow_address=escrow_address, token_identifier=token, amount=amount, status=TransactionStatus.PENDING_CONFIRMATION, buyer_pubkey=buyer_pubkey_hex, seller_pubkey=seller_pubkey_hex, arbiter_pubkey=arbiter_pubkey_hex, redeem_script=redeem_script_hex, ) db.add(transaction) db.commit() logger.info( f"Transacción de Escrow (ID: {transaction.id}) creada entre " f"{buyer_db_user.username} y {seller_db_user.username}." ) return transaction ``` -------------------------------- ### Custom Service Exception Definitions (Python) Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Defines custom exception classes used within the service layer for specific error conditions. These exceptions inherit from a base ServiceError class, providing clear and structured error handling for issues like missing users, self-transactions, or unsupported blockchain strategies. ```python class ServiceError(Exception): """Base class for service layer errors.""" pass class UserNotFoundError(ServiceError): """Raised when user not found in database.""" pass class SelfTransactionError(ServiceError): """Raised when user tries to transact with themselves.""" pass class InvalidStrategyError(ServiceError): """Raised when blockchain strategy not found.""" pass ``` -------------------------------- ### Solidity Escrow Smart Contract for EVM Chains Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt A Solidity smart contract designed for holding ERC20 tokens in escrow on EVM-compatible blockchains. It facilitates deposits, releases, dispute opening, and arbiter-based dispute resolution. Requires ERC20 token contract to be approved by the buyer before deposit. ```solidity // contracts/Escrow.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Escrow * @dev Escrow contract for ERC20 tokens with buyer, seller, and arbiter roles. */ contract Escrow { address public buyer; address public seller; address public arbiter; // Bot operator or dispute resolver IERC20 public token; // ERC20 token being traded uint256 public amount; // Amount of tokens in escrow enum State { AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE, DISPUTED, CANCELED } State public currentState; event FundsDeposited(address indexed buyer, uint256 amount); event FundsReleased(address indexed seller, uint256 amount); event DisputeOpened(address indexed by); event DisputeResolved(address indexed arbiter, address indexed winner); event EscrowCanceled(); modifier onlyBuyer() { require(msg.sender == buyer, "Only buyer can call this function"); _; } modifier onlySeller() { require(msg.sender == seller, "Only seller can call this function"); _; } modifier onlyArbiter() { require(msg.sender == arbiter, "Only arbiter can call this function"); _; } modifier inState(State _state) { require(currentState == _state, "Invalid state"); _; } /** * @dev Initialize escrow with participants and token details. */ constructor( address _buyer, address _seller, address _arbiter, address _token, uint256 _amount ) { buyer = _buyer; seller = _seller; arbiter = _arbiter; token = IERC20(_token); amount = _amount; currentState = State.AWAITING_PAYMENT; } /** * @dev Buyer deposits tokens (must approve contract first). */ function deposit() external onlyBuyer inState(State.AWAITING_PAYMENT) { uint256 initialBalance = token.balanceOf(address(this)); require(token.transferFrom(msg.sender, address(this), amount), "Token transfer failed"); uint256 finalBalance = token.balanceOf(address(this)); require(finalBalance - initialBalance == amount, "Incorrect amount transferred"); currentState = State.AWAITING_DELIVERY; emit FundsDeposited(buyer, amount); } /** * @dev Buyer confirms delivery and releases funds to seller. */ function release() external onlyBuyer inState(State.AWAITING_DELIVERY) { require(token.transfer(seller, amount), "Token release failed"); currentState = State.COMPLETE; emit FundsReleased(seller, amount); } /** * @dev Either party opens a dispute. */ function openDispute() external inState(State.AWAITING_DELIVERY) { require( msg.sender == buyer || msg.sender == seller, "Only buyer or seller can open a dispute" ); currentState = State.DISPUTED; emit DisputeOpened(msg.sender); } /** * @dev Arbiter resolves dispute by sending funds to winner. */ function resolveDispute(address winner) external onlyArbiter inState(State.DISPUTED) { require(winner == buyer || winner == seller, "Winner must be buyer or seller"); require(token.transfer(winner, amount), "Token transfer failed"); currentState = State.COMPLETE; emit DisputeResolved(arbiter, winner); } /** * @dev Buyer cancels escrow before funding. */ function cancel() external onlyBuyer inState(State.AWAITING_PAYMENT) { currentState = State.CANCELED; emit EscrowCanceled(); } } ``` -------------------------------- ### Bitcoin Multi-Sig Address Generation (Python) Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Implements the logic for generating a 2-of-3 multi-signature P2SH address for Bitcoin-like blockchains. This function requires the public keys of the buyer, seller, and arbiter to construct the address and redeem script. It is part of the BitcoinLikeStrategy. ```python # Assumed to be part of a BitcoinLikeStrategy class def generate_escrow_address(self, buyer_pubkey_hex: str, seller_pubkey_hex: str, arbiter_pubkey_hex: str) -> tuple[str, str]: # Implementation details for generating P2SH address and redeem script # This would involve cryptographic libraries for Bitcoin scripting # Example placeholder: redeem_script = f"2 {buyer_pubkey_hex} {seller_pubkey_hex} {arbiter_pubkey_hex} 3 OP_CHECKMULTISIG" escrow_address = f"bc1q..." # Placeholder for actual address generation return escrow_address, redeem_script ``` -------------------------------- ### Define SQLAlchemy Models and Enums in Python Source: https://context7.com/ericped/escrow-bot-tlg/llms.txt Defines SQLAlchemy models for 'User' and 'EscrowTransaction', including relationships and various data types. It also defines 'BlockchainType' and 'TransactionStatus' enums. These models are the foundation for the database schema. ```python from sqlalchemy import Column, Integer, String, BigInteger, DateTime, ForeignKey, Enum from sqlalchemy.orm import declarative_base, relationship import enum import datetime Base = declarative_base() class BlockchainType(enum.Enum): EVM = "EVM" BTC = "BTC" LTC = "LTC" XMR = "XMR" class TransactionStatus(enum.Enum): PENDING_CONFIRMATION = "pending_confirmation" PENDING_DEPOSIT = "pending_deposit" FUNDED = "funded" RELEASED = "released" DISPUTED = "disputed" CANCELED = "canceled" class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True) telegram_id = Column(BigInteger, unique=True, nullable=False) username = Column(String) # Wallet addresses for different blockchains wallet_address_evm = Column(String) wallet_address_btc = Column(String) wallet_address_ltc = Column(String) wallet_address_xmr = Column(String) # Relationships to transactions transactions_as_buyer = relationship( "EscrowTransaction", foreign_keys="[EscrowTransaction.buyer_id]" ) transactions_as_seller = relationship( "EscrowTransaction", foreign_keys="[EscrowTransaction.seller_id]" ) class EscrowTransaction(Base): __tablename__ = "transactions" id = Column(Integer, primary_key=True) buyer_id = Column(Integer, ForeignKey("users.id"), nullable=False) seller_id = Column(Integer, ForeignKey("users.id"), nullable=False) blockchain_type = Column(Enum(BlockchainType), nullable=False) escrow_address = Column(String, unique=True) # Smart contract or multi-sig address token_identifier = Column(String) # e.g., "USDT", "BTC" amount = Column(String) # String for high-precision numbers status = Column(Enum(TransactionStatus), nullable=False) created_at = Column(DateTime, default=datetime.datetime.utcnow) # Bitcoin-like multi-sig fields buyer_pubkey = Column(String, nullable=True) seller_pubkey = Column(String, nullable=True) arbiter_pubkey = Column(String, nullable=True) redeem_script = Column(String, nullable=True) # For P2SH multi-sig # Relationships to users buyer = relationship("User", foreign_keys=[buyer_id], overlaps="transactions_as_buyer") seller = relationship("User", foreign_keys=[seller_id], overlaps="transactions_as_seller") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.