Enhance DCA distribution logic: Improved the proportional distribution algorithm to include precise calculations with banker's rounding and handle remainder allocation fairly among clients. Added verification to ensure total distributed amount matches the base allocation, enhancing accuracy and reliability in transaction processing.
This commit is contained in:
parent
e222922a6a
commit
1943da1fc3
1 changed files with 51 additions and 3 deletions
|
|
@ -704,15 +704,56 @@ class LamassuTransactionProcessor:
|
|||
logger.info("No clients with remaining DCA balance - skipping distribution")
|
||||
return {}
|
||||
|
||||
# Calculate proportional distribution
|
||||
# Calculate proportional distribution with remainder allocation
|
||||
distributions = {}
|
||||
distributed_sats = 0
|
||||
client_calculations = []
|
||||
|
||||
# First pass: calculate base amounts and track remainders
|
||||
for client_id, client_balance in client_balances.items():
|
||||
# Calculate this client's proportion of the total DCA pool
|
||||
proportion = client_balance / total_confirmed_deposits
|
||||
|
||||
# Calculate client's share of the base crypto (after commission)
|
||||
client_sats_amount = int(base_crypto_atoms * proportion)
|
||||
# Calculate exact share (with decimals)
|
||||
exact_share = base_crypto_atoms * proportion
|
||||
|
||||
# Use banker's rounding for base allocation
|
||||
client_sats_amount = round(exact_share)
|
||||
|
||||
client_calculations.append({
|
||||
'client_id': client_id,
|
||||
'proportion': proportion,
|
||||
'exact_share': exact_share,
|
||||
'allocated_sats': client_sats_amount,
|
||||
'client_balance': client_balance
|
||||
})
|
||||
|
||||
distributed_sats += client_sats_amount
|
||||
|
||||
# Handle any remainder due to rounding (should be small)
|
||||
remainder = base_crypto_atoms - distributed_sats
|
||||
|
||||
if remainder != 0:
|
||||
logger.info(f"Distributing remainder: {remainder} sats among {len(client_calculations)} clients")
|
||||
|
||||
# Sort clients by largest fractional remainder to distribute fairly
|
||||
client_calculations.sort(
|
||||
key=lambda x: x['exact_share'] - x['allocated_sats'],
|
||||
reverse=True
|
||||
)
|
||||
|
||||
# Distribute remainder one sat at a time to clients with largest fractional parts
|
||||
for i in range(abs(remainder)):
|
||||
if remainder > 0:
|
||||
client_calculations[i % len(client_calculations)]['allocated_sats'] += 1
|
||||
else:
|
||||
client_calculations[i % len(client_calculations)]['allocated_sats'] -= 1
|
||||
|
||||
# Second pass: create distributions with final amounts
|
||||
for calc in client_calculations:
|
||||
client_id = calc['client_id']
|
||||
client_sats_amount = calc['allocated_sats']
|
||||
proportion = calc['proportion']
|
||||
|
||||
# Calculate equivalent fiat value in centavos for tracking purposes (industry standard)
|
||||
# Store as centavos to maintain precision and avoid floating-point errors
|
||||
|
|
@ -726,6 +767,13 @@ class LamassuTransactionProcessor:
|
|||
|
||||
logger.info(f"Client {client_id[:8]}... gets {client_sats_amount} sats (≈{client_fiat_amount/100:.2f} GTQ, {proportion:.2%} share)")
|
||||
|
||||
# Verification: ensure total distribution equals base amount
|
||||
total_distributed = sum(dist["sats_amount"] for dist in distributions.values())
|
||||
if total_distributed != base_crypto_atoms:
|
||||
logger.error(f"Distribution mismatch! Expected: {base_crypto_atoms} sats, Distributed: {total_distributed} sats")
|
||||
raise ValueError(f"Satoshi distribution calculation error: {base_crypto_atoms} != {total_distributed}")
|
||||
|
||||
logger.info(f"Distribution verified: {total_distributed} sats distributed across {len(distributions)} clients")
|
||||
return distributions
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue