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:
parent
033e329870
commit
df8b36fc0f
6 changed files with 116 additions and 2 deletions
5
crud.py
5
crud.py
|
|
@ -309,9 +309,9 @@ async def create_lamassu_config(data: CreateLamassuConfigData) -> LamassuConfig:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO myextension.lamassu_config
|
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)
|
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)
|
: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,
|
"username": data.username,
|
||||||
"password": data.password,
|
"password": data.password,
|
||||||
"source_wallet_id": data.source_wallet_id,
|
"source_wallet_id": data.source_wallet_id,
|
||||||
|
"commission_wallet_id": data.commission_wallet_id,
|
||||||
"is_active": True,
|
"is_active": True,
|
||||||
"created_at": datetime.now(),
|
"created_at": datetime.now(),
|
||||||
"updated_at": datetime.now(),
|
"updated_at": datetime.now(),
|
||||||
|
|
|
||||||
|
|
@ -200,3 +200,15 @@ async def m010_add_source_wallet_to_lamassu_config(db):
|
||||||
ADD COLUMN source_wallet_id TEXT;
|
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;
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,8 @@ class CreateLamassuConfigData(BaseModel):
|
||||||
password: str
|
password: str
|
||||||
# Source wallet for DCA distributions
|
# Source wallet for DCA distributions
|
||||||
source_wallet_id: Optional[str] = None
|
source_wallet_id: Optional[str] = None
|
||||||
|
# Commission wallet for storing commission earnings
|
||||||
|
commission_wallet_id: Optional[str] = None
|
||||||
# SSH Tunnel settings
|
# SSH Tunnel settings
|
||||||
use_ssh_tunnel: bool = False
|
use_ssh_tunnel: bool = False
|
||||||
ssh_host: Optional[str] = None
|
ssh_host: Optional[str] = None
|
||||||
|
|
@ -134,6 +136,8 @@ class LamassuConfig(BaseModel):
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
# Source wallet for DCA distributions
|
# Source wallet for DCA distributions
|
||||||
source_wallet_id: Optional[str] = None
|
source_wallet_id: Optional[str] = None
|
||||||
|
# Commission wallet for storing commission earnings
|
||||||
|
commission_wallet_id: Optional[str] = None
|
||||||
# SSH Tunnel settings
|
# SSH Tunnel settings
|
||||||
use_ssh_tunnel: bool = False
|
use_ssh_tunnel: bool = False
|
||||||
ssh_host: Optional[str] = None
|
ssh_host: Optional[str] = None
|
||||||
|
|
@ -155,6 +159,8 @@ class UpdateLamassuConfigData(BaseModel):
|
||||||
is_active: Optional[bool] = None
|
is_active: Optional[bool] = None
|
||||||
# Source wallet for DCA distributions
|
# Source wallet for DCA distributions
|
||||||
source_wallet_id: Optional[str] = None
|
source_wallet_id: Optional[str] = None
|
||||||
|
# Commission wallet for storing commission earnings
|
||||||
|
commission_wallet_id: Optional[str] = None
|
||||||
# SSH Tunnel settings
|
# SSH Tunnel settings
|
||||||
use_ssh_tunnel: Optional[bool] = None
|
use_ssh_tunnel: Optional[bool] = None
|
||||||
ssh_host: Optional[str] = None
|
ssh_host: Optional[str] = None
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ window.app = Vue.createApp({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
selectedWallet: null,
|
selectedWallet: null,
|
||||||
|
selectedCommissionWallet: null,
|
||||||
// SSH Tunnel settings
|
// SSH Tunnel settings
|
||||||
use_ssh_tunnel: false,
|
use_ssh_tunnel: false,
|
||||||
ssh_host: '',
|
ssh_host: '',
|
||||||
|
|
@ -156,6 +157,20 @@ window.app = Vue.createApp({
|
||||||
this.g.user.wallets[0].inkey
|
this.g.user.wallets[0].inkey
|
||||||
)
|
)
|
||||||
this.lamassuConfig = data
|
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) {
|
} catch (error) {
|
||||||
// It's OK if no config exists yet
|
// It's OK if no config exists yet
|
||||||
this.lamassuConfig = null
|
this.lamassuConfig = null
|
||||||
|
|
@ -171,6 +186,7 @@ window.app = Vue.createApp({
|
||||||
username: this.configDialog.data.username,
|
username: this.configDialog.data.username,
|
||||||
password: this.configDialog.data.password,
|
password: this.configDialog.data.password,
|
||||||
source_wallet_id: this.configDialog.data.selectedWallet?.id,
|
source_wallet_id: this.configDialog.data.selectedWallet?.id,
|
||||||
|
commission_wallet_id: this.configDialog.data.selectedCommissionWallet?.id,
|
||||||
// SSH Tunnel settings
|
// SSH Tunnel settings
|
||||||
use_ssh_tunnel: this.configDialog.data.use_ssh_tunnel,
|
use_ssh_tunnel: this.configDialog.data.use_ssh_tunnel,
|
||||||
ssh_host: this.configDialog.data.ssh_host,
|
ssh_host: this.configDialog.data.ssh_host,
|
||||||
|
|
@ -209,6 +225,7 @@ window.app = Vue.createApp({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
selectedWallet: null,
|
selectedWallet: null,
|
||||||
|
selectedCommissionWallet: null,
|
||||||
// SSH Tunnel settings
|
// SSH Tunnel settings
|
||||||
use_ssh_tunnel: false,
|
use_ssh_tunnel: false,
|
||||||
ssh_host: '',
|
ssh_host: '',
|
||||||
|
|
|
||||||
|
|
@ -580,6 +580,16 @@
|
||||||
hint="Wallet that holds Bitcoin for distribution to DCA clients"
|
hint="Wallet that holds Bitcoin for distribution to DCA clients"
|
||||||
></q-select>
|
></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>
|
<q-separator class="q-my-md"></q-separator>
|
||||||
|
|
||||||
<div class="text-h6 q-mb-md">SSH Tunnel (Recommended)</div>
|
<div class="text-h6 q-mb-md">SSH Tunnel (Recommended)</div>
|
||||||
|
|
|
||||||
|
|
@ -706,6 +706,58 @@ class LamassuTransactionProcessor:
|
||||||
logger.error(f"Error crediting source wallet for transaction {transaction.get('transaction_id', 'unknown')}: {e}")
|
logger.error(f"Error crediting source wallet for transaction {transaction.get('transaction_id', 'unknown')}: {e}")
|
||||||
return False
|
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:
|
async def process_transaction(self, transaction: Dict[str, Any]) -> None:
|
||||||
"""Process a single transaction - calculate and distribute DCA payments"""
|
"""Process a single transaction - calculate and distribute DCA payments"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -732,9 +784,25 @@ class LamassuTransactionProcessor:
|
||||||
logger.info(f"No distributions calculated for transaction {transaction_id}")
|
logger.info(f"No distributions calculated for transaction {transaction_id}")
|
||||||
return
|
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
|
# Distribute to clients
|
||||||
await self.distribute_to_clients(transaction, distributions)
|
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}")
|
logger.info(f"Successfully processed transaction {transaction_id}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue