Add commission wallet support in Lamassu configuration: update database schema to include commission_wallet_id, modify related models and CRUD operations, and implement commission payment functionality in transaction processing. Enhance UI components to allow selection of the commission wallet for improved user experience.

This commit is contained in:
padreug 2025-06-19 17:08:07 +02:00
parent 033e329870
commit df8b36fc0f
6 changed files with 116 additions and 2 deletions

View file

@ -309,9 +309,9 @@ async def create_lamassu_config(data: CreateLamassuConfigData) -> LamassuConfig:
await db.execute(
"""
INSERT INTO myextension.lamassu_config
(id, host, port, database_name, username, password, source_wallet_id, is_active, created_at, updated_at,
(id, host, port, database_name, username, password, source_wallet_id, commission_wallet_id, is_active, created_at, updated_at,
use_ssh_tunnel, ssh_host, ssh_port, ssh_username, ssh_password, ssh_private_key)
VALUES (:id, :host, :port, :database_name, :username, :password, :source_wallet_id, :is_active, :created_at, :updated_at,
VALUES (:id, :host, :port, :database_name, :username, :password, :source_wallet_id, :commission_wallet_id, :is_active, :created_at, :updated_at,
:use_ssh_tunnel, :ssh_host, :ssh_port, :ssh_username, :ssh_password, :ssh_private_key)
""",
{
@ -322,6 +322,7 @@ async def create_lamassu_config(data: CreateLamassuConfigData) -> LamassuConfig:
"username": data.username,
"password": data.password,
"source_wallet_id": data.source_wallet_id,
"commission_wallet_id": data.commission_wallet_id,
"is_active": True,
"created_at": datetime.now(),
"updated_at": datetime.now(),

View file

@ -200,3 +200,15 @@ async def m010_add_source_wallet_to_lamassu_config(db):
ADD COLUMN source_wallet_id TEXT;
"""
)
async def m011_add_commission_wallet_to_lamassu_config(db):
"""
Add commission wallet ID to Lamassu configuration table for commission earnings.
"""
await db.execute(
"""
ALTER TABLE myextension.lamassu_config
ADD COLUMN commission_wallet_id TEXT;
"""
)

View file

@ -111,6 +111,8 @@ class CreateLamassuConfigData(BaseModel):
password: str
# Source wallet for DCA distributions
source_wallet_id: Optional[str] = None
# Commission wallet for storing commission earnings
commission_wallet_id: Optional[str] = None
# SSH Tunnel settings
use_ssh_tunnel: bool = False
ssh_host: Optional[str] = None
@ -134,6 +136,8 @@ class LamassuConfig(BaseModel):
updated_at: datetime
# Source wallet for DCA distributions
source_wallet_id: Optional[str] = None
# Commission wallet for storing commission earnings
commission_wallet_id: Optional[str] = None
# SSH Tunnel settings
use_ssh_tunnel: bool = False
ssh_host: Optional[str] = None
@ -155,6 +159,8 @@ class UpdateLamassuConfigData(BaseModel):
is_active: Optional[bool] = None
# Source wallet for DCA distributions
source_wallet_id: Optional[str] = None
# Commission wallet for storing commission earnings
commission_wallet_id: Optional[str] = None
# SSH Tunnel settings
use_ssh_tunnel: Optional[bool] = None
ssh_host: Optional[str] = None

View file

@ -72,6 +72,7 @@ window.app = Vue.createApp({
username: '',
password: '',
selectedWallet: null,
selectedCommissionWallet: null,
// SSH Tunnel settings
use_ssh_tunnel: false,
ssh_host: '',
@ -156,6 +157,20 @@ window.app = Vue.createApp({
this.g.user.wallets[0].inkey
)
this.lamassuConfig = data
// When opening config dialog, populate the selected wallets if they exist
if (data && data.source_wallet_id) {
const wallet = this.g.user.wallets.find(w => w.id === data.source_wallet_id)
if (wallet) {
this.configDialog.data.selectedWallet = wallet
}
}
if (data && data.commission_wallet_id) {
const commissionWallet = this.g.user.wallets.find(w => w.id === data.commission_wallet_id)
if (commissionWallet) {
this.configDialog.data.selectedCommissionWallet = commissionWallet
}
}
} catch (error) {
// It's OK if no config exists yet
this.lamassuConfig = null
@ -171,6 +186,7 @@ window.app = Vue.createApp({
username: this.configDialog.data.username,
password: this.configDialog.data.password,
source_wallet_id: this.configDialog.data.selectedWallet?.id,
commission_wallet_id: this.configDialog.data.selectedCommissionWallet?.id,
// SSH Tunnel settings
use_ssh_tunnel: this.configDialog.data.use_ssh_tunnel,
ssh_host: this.configDialog.data.ssh_host,
@ -209,6 +225,7 @@ window.app = Vue.createApp({
username: '',
password: '',
selectedWallet: null,
selectedCommissionWallet: null,
// SSH Tunnel settings
use_ssh_tunnel: false,
ssh_host: '',

View file

@ -580,6 +580,16 @@
hint="Wallet that holds Bitcoin for distribution to DCA clients"
></q-select>
<q-select
filled
dense
:options="g.user.wallets"
v-model="configDialog.data.selectedCommissionWallet"
label="Commission Wallet (Optional)"
option-label="name"
hint="Wallet where commission earnings will be sent (leave empty to keep in source wallet)"
></q-select>
<q-separator class="q-my-md"></q-separator>
<div class="text-h6 q-mb-md">SSH Tunnel (Recommended)</div>

View file

@ -706,6 +706,58 @@ class LamassuTransactionProcessor:
logger.error(f"Error crediting source wallet for transaction {transaction.get('transaction_id', 'unknown')}: {e}")
return False
async def send_commission_payment(self, transaction: Dict[str, Any], commission_amount_sats: int) -> bool:
"""Send commission to the configured commission wallet"""
try:
# Get the configuration to find commission wallet
admin_config = await get_active_lamassu_config()
if not admin_config or not admin_config.commission_wallet_id:
logger.info("No commission wallet configured - commission remains in source wallet")
return True # Not an error, just no transfer needed
if not admin_config.source_wallet_id:
logger.error("No source wallet configured - cannot send commission")
return False
transaction_id = transaction["transaction_id"]
# Create invoice in commission wallet
commission_memo = f"Commission: {commission_amount_sats} sats from Lamassu transaction {transaction_id[:8]}..."
commission_payment = await create_invoice(
wallet_id=admin_config.commission_wallet_id,
amount=commission_amount_sats,
internal=True,
memo=commission_memo,
extra={
"tag": "dca_commission",
"lamassu_transaction_id": transaction_id,
"commission_amount": commission_amount_sats
}
)
if not commission_payment:
logger.error(f"Failed to create commission invoice for transaction {transaction_id}")
return False
# Pay the commission invoice from source wallet
await pay_invoice(
payment_request=commission_payment.bolt11,
wallet_id=admin_config.source_wallet_id,
description=commission_memo,
extra={
"tag": "dca_commission_payment",
"lamassu_transaction_id": transaction_id
}
)
logger.info(f"Commission payment completed: {commission_amount_sats} sats sent to commission wallet for transaction {transaction_id}")
return True
except Exception as e:
logger.error(f"Error sending commission payment for transaction {transaction.get('transaction_id', 'unknown')}: {e}")
return False
async def process_transaction(self, transaction: Dict[str, Any]) -> None:
"""Process a single transaction - calculate and distribute DCA payments"""
try:
@ -732,9 +784,25 @@ class LamassuTransactionProcessor:
logger.info(f"No distributions calculated for transaction {transaction_id}")
return
# Calculate commission amount for sending to commission wallet
crypto_atoms = transaction["crypto_amount"]
commission_percentage = transaction["commission_percentage"]
discount = transaction.get("discount", 0.0)
if commission_percentage > 0:
effective_commission = commission_percentage * (100 - discount) / 100
base_crypto_atoms = int(crypto_atoms / (1 + effective_commission))
commission_amount_sats = crypto_atoms - base_crypto_atoms
else:
commission_amount_sats = 0
# Distribute to clients
await self.distribute_to_clients(transaction, distributions)
# Send commission to commission wallet (if configured)
if commission_amount_sats > 0:
await self.send_commission_payment(transaction, commission_amount_sats)
logger.info(f"Successfully processed transaction {transaction_id}")
except Exception as e: