Module maker.offers
Offer management for makers.
Creates and manages liquidity offers based on wallet balance and configuration.
Classes
class OfferManager (wallet: WalletService, config: MakerConfig, maker_nick: str)-
Expand source code
class OfferManager: """ Creates and manages offers for the maker bot. """ def __init__(self, wallet: WalletService, config: MakerConfig, maker_nick: str): self.wallet = wallet self.config = config self.maker_nick = maker_nick async def create_offers(self) -> list[Offer]: """ Create offers based on wallet balance and configuration. Logic: 1. Find mixdepth with maximum balance 2. Calculate available amount (balance - dust - txfee) 3. Create offer with configured fee structure 4. Attach fidelity bond value if available Returns: List of offers (usually just one) """ try: balances = {} for mixdepth in range(self.wallet.mixdepth_count): balance = await self.wallet.get_balance(mixdepth) balances[mixdepth] = balance available_mixdepths = {md: bal for md, bal in balances.items() if bal > 0} if not available_mixdepths: logger.warning("No mixdepth with positive balance") return [] max_mixdepth = max(available_mixdepths, key=lambda md: available_mixdepths[md]) max_balance = available_mixdepths[max_mixdepth] # Reserve dust threshold + tx fee contribution max_available = max_balance - max( self.config.dust_threshold, self.config.tx_fee_contribution ) if max_available <= self.config.min_size: logger.warning(f"Insufficient balance: {max_available} <= {self.config.min_size}") return [] if self.config.offer_type in (OfferType.SW0_RELATIVE, OfferType.SWA_RELATIVE): cjfee = self.config.cj_fee_relative # Validate cj_fee_relative to prevent division by zero cj_fee_float = float(self.config.cj_fee_relative) if cj_fee_float <= 0: logger.error( f"Invalid cj_fee_relative: {self.config.cj_fee_relative}. " "Must be > 0 for relative offer types." ) return [] min_size_for_profit = int(1.5 * self.config.tx_fee_contribution / cj_fee_float) min_size = max(min_size_for_profit, self.config.min_size) else: cjfee = str(self.config.cj_fee_absolute) min_size = self.config.min_size # Get fidelity bond value if available fidelity_bond_value = 0 bond = get_best_fidelity_bond(self.wallet) if bond: fidelity_bond_value = bond.bond_value logger.info( f"Fidelity bond found: {bond.txid}:{bond.vout} " f"value={bond.value} sats, bond_value={bond.bond_value}" ) offer = Offer( counterparty=self.maker_nick, oid=0, ordertype=self.config.offer_type, minsize=min_size, maxsize=max_available, txfee=self.config.tx_fee_contribution, cjfee=cjfee, fidelity_bond_value=fidelity_bond_value, ) logger.info( f"Created offer: type={offer.ordertype}, " f"size={min_size}-{max_available}, " f"cjfee={cjfee}, txfee={self.config.tx_fee_contribution}, " f"bond_value={fidelity_bond_value}" ) return [offer] except Exception as e: logger.error(f"Failed to create offers: {e}") return [] def validate_offer_fill(self, offer: Offer, amount: int) -> tuple[bool, str]: """ Validate a fill request for an offer. Args: offer: The offer being filled amount: Requested amount Returns: (is_valid, error_message) """ if amount < offer.minsize: return False, f"Amount {amount} below minimum {offer.minsize}" if amount > offer.maxsize: return False, f"Amount {amount} above maximum {offer.maxsize}" return True, ""Creates and manages offers for the maker bot.
Methods
async def create_offers(self) ‑> list[Offer]-
Expand source code
async def create_offers(self) -> list[Offer]: """ Create offers based on wallet balance and configuration. Logic: 1. Find mixdepth with maximum balance 2. Calculate available amount (balance - dust - txfee) 3. Create offer with configured fee structure 4. Attach fidelity bond value if available Returns: List of offers (usually just one) """ try: balances = {} for mixdepth in range(self.wallet.mixdepth_count): balance = await self.wallet.get_balance(mixdepth) balances[mixdepth] = balance available_mixdepths = {md: bal for md, bal in balances.items() if bal > 0} if not available_mixdepths: logger.warning("No mixdepth with positive balance") return [] max_mixdepth = max(available_mixdepths, key=lambda md: available_mixdepths[md]) max_balance = available_mixdepths[max_mixdepth] # Reserve dust threshold + tx fee contribution max_available = max_balance - max( self.config.dust_threshold, self.config.tx_fee_contribution ) if max_available <= self.config.min_size: logger.warning(f"Insufficient balance: {max_available} <= {self.config.min_size}") return [] if self.config.offer_type in (OfferType.SW0_RELATIVE, OfferType.SWA_RELATIVE): cjfee = self.config.cj_fee_relative # Validate cj_fee_relative to prevent division by zero cj_fee_float = float(self.config.cj_fee_relative) if cj_fee_float <= 0: logger.error( f"Invalid cj_fee_relative: {self.config.cj_fee_relative}. " "Must be > 0 for relative offer types." ) return [] min_size_for_profit = int(1.5 * self.config.tx_fee_contribution / cj_fee_float) min_size = max(min_size_for_profit, self.config.min_size) else: cjfee = str(self.config.cj_fee_absolute) min_size = self.config.min_size # Get fidelity bond value if available fidelity_bond_value = 0 bond = get_best_fidelity_bond(self.wallet) if bond: fidelity_bond_value = bond.bond_value logger.info( f"Fidelity bond found: {bond.txid}:{bond.vout} " f"value={bond.value} sats, bond_value={bond.bond_value}" ) offer = Offer( counterparty=self.maker_nick, oid=0, ordertype=self.config.offer_type, minsize=min_size, maxsize=max_available, txfee=self.config.tx_fee_contribution, cjfee=cjfee, fidelity_bond_value=fidelity_bond_value, ) logger.info( f"Created offer: type={offer.ordertype}, " f"size={min_size}-{max_available}, " f"cjfee={cjfee}, txfee={self.config.tx_fee_contribution}, " f"bond_value={fidelity_bond_value}" ) return [offer] except Exception as e: logger.error(f"Failed to create offers: {e}") return []Create offers based on wallet balance and configuration.
Logic: 1. Find mixdepth with maximum balance 2. Calculate available amount (balance - dust - txfee) 3. Create offer with configured fee structure 4. Attach fidelity bond value if available
Returns
List of offers (usually just one)
def validate_offer_fill(self, offer: Offer, amount: int) ‑> tuple[bool, str]-
Expand source code
def validate_offer_fill(self, offer: Offer, amount: int) -> tuple[bool, str]: """ Validate a fill request for an offer. Args: offer: The offer being filled amount: Requested amount Returns: (is_valid, error_message) """ if amount < offer.minsize: return False, f"Amount {amount} below minimum {offer.minsize}" if amount > offer.maxsize: return False, f"Amount {amount} above maximum {offer.maxsize}" return True, ""Validate a fill request for an offer.
Args
offer- The offer being filled
amount- Requested amount
Returns
(is_valid, error_message)