From 5db975f318fd70bb3145cc5f051dd2c0daa8c528 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:59:28 +0100 Subject: [PATCH] Add balance debugging scripts for financial log analysis - compare-balance-logs.sh: Compare two log entries and show asset changes - sum-asset-balances.sh: Sum asset balances by financial type - inspect-asset-balance.sh: Inspect detailed balance structure for specific assets These scripts help diagnose balance calculation issues and analyze financial data logs from the /gs/debug endpoint. --- scripts/compare-balance-logs.sh | 118 +++++++++++++++++++++++++++++++ scripts/inspect-asset-balance.sh | 114 +++++++++++++++++++++++++++++ scripts/sum-asset-balances.sh | 112 +++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100755 scripts/compare-balance-logs.sh create mode 100755 scripts/inspect-asset-balance.sh create mode 100755 scripts/sum-asset-balances.sh diff --git a/scripts/compare-balance-logs.sh b/scripts/compare-balance-logs.sh new file mode 100755 index 0000000000..82bb5093e3 --- /dev/null +++ b/scripts/compare-balance-logs.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# Compare two FinancialDataLog entries to find asset changes + +set -e + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: $0 " + exit 1 +fi + +LOG_ID_1="$1" +LOG_ID_2="$2" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="$SCRIPT_DIR/../.env" + +if [ ! -f "$ENV_FILE" ]; then + echo "Error: Environment file not found: $ENV_FILE" + exit 1 +fi + +DEBUG_ADDRESS=$(grep -E "^DEBUG_ADDRESS=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_SIGNATURE=$(grep -E "^DEBUG_SIGNATURE=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_API_URL=$(grep -E "^DEBUG_API_URL=" "$ENV_FILE" | cut -d'=' -f2-) + +if [ -z "$DEBUG_ADDRESS" ] || [ -z "$DEBUG_SIGNATURE" ]; then + echo "Error: DEBUG_ADDRESS and DEBUG_SIGNATURE must be set in .env" + exit 1 +fi + +API_URL="${DEBUG_API_URL:-https://api.dfx.swiss/v1}" + +# Authenticate +TOKEN_RESPONSE=$(curl -s -X POST "$API_URL/auth" \ + -H "Content-Type: application/json" \ + -d "{\"address\":\"$DEBUG_ADDRESS\",\"signature\":\"$DEBUG_SIGNATURE\"}") + +TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.accessToken' 2>/dev/null) + +if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then + echo "Authentication failed" + exit 1 +fi + +# Get both log entries +SQL="SELECT id, created, message FROM log WHERE id IN ($LOG_ID_1, $LOG_ID_2) ORDER BY id" +RESULT=$(curl -s -X POST "$API_URL/gs/debug" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"sql\":\"$SQL\"}") + +# Parse with jq +echo "$RESULT" | jq -r ' + # Extract both entries + .[0] as $entry1 | + .[1] as $entry2 | + + # Parse message JSON + ($entry1.message | fromjson) as $msg1 | + ($entry2.message | fromjson) as $msg2 | + + "=== Balance Comparison ===", + "", + "Entry 1: ID \($entry1.id) at \($entry1.created)", + " plusBalance: \($msg1.balancesTotal.plusBalanceChf)", + " minusBalance: \($msg1.balancesTotal.minusBalanceChf)", + " totalBalance: \($msg1.balancesTotal.plusBalanceChf - $msg1.balancesTotal.minusBalanceChf | tostring | .[0:12])", + "", + "Entry 2: ID \($entry2.id) at \($entry2.created)", + " plusBalance: \($msg2.balancesTotal.plusBalanceChf)", + " minusBalance: \($msg2.balancesTotal.minusBalanceChf)", + " totalBalance: \($msg2.balancesTotal.plusBalanceChf - $msg2.balancesTotal.minusBalanceChf | tostring | .[0:12])", + "", + "=== Changes ===", + " Δ plusBalance: \($msg2.balancesTotal.plusBalanceChf - $msg1.balancesTotal.plusBalanceChf | tostring | .[0:12])", + " Δ minusBalance: \($msg2.balancesTotal.minusBalanceChf - $msg1.balancesTotal.minusBalanceChf | tostring | .[0:12])", + " Δ totalBalance: \(($msg2.balancesTotal.plusBalanceChf - $msg2.balancesTotal.minusBalanceChf) - ($msg1.balancesTotal.plusBalanceChf - $msg1.balancesTotal.minusBalanceChf) | tostring | .[0:12])", + "", + "=== Top Asset Changes (by CHF impact) ===", + "", + # Get all asset IDs from both messages + ([($msg1.assets | keys[]), ($msg2.assets | keys[])] | unique) as $all_assets | + + # Calculate changes for each asset + [ + $all_assets[] | . as $asset_id | + { + assetId: $asset_id, + plus1: ($msg1.assets[$asset_id].plusBalance.total // 0), + plus2: ($msg2.assets[$asset_id].plusBalance.total // 0), + minus1: ($msg1.assets[$asset_id].minusBalance.total // 0), + minus2: ($msg2.assets[$asset_id].minusBalance.total // 0), + price1: ($msg1.assets[$asset_id].priceChf // 0), + price2: ($msg2.assets[$asset_id].priceChf // 0) + } | + . + { + deltaPlus: (.plus2 - .plus1), + deltaMinus: (.minus2 - .minus1), + price: (if .price2 > 0 then .price2 else .price1 end) + } | + . + { + deltaPlusChf: (.deltaPlus * .price), + deltaMinusChf: (.deltaMinus * .price), + deltaNetChf: ((.deltaPlus - .deltaMinus) * .price) + } + ] | + + # Filter out zero changes + map(select((.deltaNetChf | if . < 0 then -. else . end) > 10)) | + + # Sort by absolute net CHF change + sort_by(-.deltaNetChf | if . < 0 then -. else . end) | + + # Take top 20 + .[0:20][] | + + "Asset \(.assetId): Δnet=\(.deltaNetChf) CHF (Δplus: \(.deltaPlus) units, Δminus: \(.deltaMinus) units, price: \(.price) CHF)" +' diff --git a/scripts/inspect-asset-balance.sh b/scripts/inspect-asset-balance.sh new file mode 100755 index 0000000000..4b964dcf05 --- /dev/null +++ b/scripts/inspect-asset-balance.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# Inspect detailed balance structure for a specific asset + +set -e + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: $0 " + exit 1 +fi + +LOG_ID="$1" +ASSET_ID="$2" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="$SCRIPT_DIR/../.env" + +if [ ! -f "$ENV_FILE" ]; then + echo "Error: Environment file not found: $ENV_FILE" + exit 1 +fi + +DEBUG_ADDRESS=$(grep -E "^DEBUG_ADDRESS=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_SIGNATURE=$(grep -E "^DEBUG_SIGNATURE=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_API_URL=$(grep -E "^DEBUG_API_URL=" "$ENV_FILE" | cut -d'=' -f2-) + +if [ -z "$DEBUG_ADDRESS" ] || [ -z "$DEBUG_SIGNATURE" ]; then + echo "Error: DEBUG_ADDRESS and DEBUG_SIGNATURE must be set in .env" + exit 1 +fi + +API_URL="${DEBUG_API_URL:-https://api.dfx.swiss/v1}" + +# Authenticate +TOKEN_RESPONSE=$(curl -s -X POST "$API_URL/auth" \ + -H "Content-Type: application/json" \ + -d "{\"address\":\"$DEBUG_ADDRESS\",\"signature\":\"$DEBUG_SIGNATURE\"}") + +TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.accessToken' 2>/dev/null) + +if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then + echo "Authentication failed" + exit 1 +fi + +# Get log entry +SQL="SELECT id, created, message FROM log WHERE id = $LOG_ID" +RESULT=$(curl -s -X POST "$API_URL/gs/debug" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"sql\":\"$SQL\"}") + +# Parse with jq +echo "$RESULT" | jq -r --arg asset_id "$ASSET_ID" ' + .[0] as $entry | + ($entry.message | fromjson) as $msg | + $msg.assets[$asset_id] as $asset | + + if $asset then + "=== Asset \($asset_id) Balance Details ===", + "", + "Log Entry: \($entry.id) at \($entry.created)", + "Price CHF: \($asset.priceChf)", + "", + "=== Plus Balance ===", + "Total: \($asset.plusBalance.total)", + "", + if $asset.plusBalance.liquidity then + "Liquidity: \($asset.plusBalance.liquidity.total)", + (if $asset.plusBalance.liquidity.liquidityBalance then + " - liquidityBalance.total: \($asset.plusBalance.liquidity.liquidityBalance.total)", + ($asset.plusBalance.liquidity.liquidityBalance | to_entries[] | select(.key != "total") | " [\(.key)]: \(.value)") + else empty end), + (if $asset.plusBalance.liquidity.paymentDepositBalance then + " - paymentDepositBalance.total: \($asset.plusBalance.liquidity.paymentDepositBalance.total)" + else empty end), + (if $asset.plusBalance.liquidity.manualLiqPosition then + " - manualLiqPosition.total: \($asset.plusBalance.liquidity.manualLiqPosition.total)" + else empty end) + else + "Liquidity: N/A" + end, + "", + if $asset.plusBalance.custom then + "Custom: \($asset.plusBalance.custom.total)", + ($asset.plusBalance.custom | to_entries[] | select(.key != "total") | " - \(.key): \(.value)") + else + "Custom: N/A" + end, + "", + if $asset.plusBalance.pending then + "Pending: \($asset.plusBalance.pending.total)", + (if $asset.plusBalance.pending.cryptoInput then " - cryptoInput: \($asset.plusBalance.pending.cryptoInput)" else empty end), + (if $asset.plusBalance.pending.exchangeOrder then " - exchangeOrder: \($asset.plusBalance.pending.exchangeOrder)" else empty end), + (if $asset.plusBalance.pending.bridgeOrder then " - bridgeOrder: \($asset.plusBalance.pending.bridgeOrder)" else empty end), + (if $asset.plusBalance.pending.fromOlky then " - fromOlky: \($asset.plusBalance.pending.fromOlky)" else empty end), + (if $asset.plusBalance.pending.fromKraken then " - fromKraken: \($asset.plusBalance.pending.fromKraken)" else empty end), + (if $asset.plusBalance.pending.toKraken then " - toKraken: \($asset.plusBalance.pending.toKraken)" else empty end), + (if $asset.plusBalance.pending.fromScrypt then " - fromScrypt: \($asset.plusBalance.pending.fromScrypt)" else empty end), + (if $asset.plusBalance.pending.toScrypt then " - toScrypt: \($asset.plusBalance.pending.toScrypt)" else empty end) + else + "Pending: N/A" + end, + "", + "=== Minus Balance ===", + "Total: \($asset.minusBalance.total)", + "", + (if $asset.minusBalance.debt then "Debt: \($asset.minusBalance.debt)" else empty end), + (if $asset.minusBalance.pending then + "Pending: \($asset.minusBalance.pending.total)" + else empty end) + else + "Asset \($asset_id) not found in log entry \($entry.id)" + end +' diff --git a/scripts/sum-asset-balances.sh b/scripts/sum-asset-balances.sh new file mode 100755 index 0000000000..95adb97b29 --- /dev/null +++ b/scripts/sum-asset-balances.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Sum plusBalance.total for assets of a specific financialType + +set -e + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: $0 " + exit 1 +fi + +LOG_ID="$1" +FINANCIAL_TYPE="$2" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="$SCRIPT_DIR/../.env" + +if [ ! -f "$ENV_FILE" ]; then + echo "Error: Environment file not found: $ENV_FILE" + exit 1 +fi + +DEBUG_ADDRESS=$(grep -E "^DEBUG_ADDRESS=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_SIGNATURE=$(grep -E "^DEBUG_SIGNATURE=" "$ENV_FILE" | cut -d'=' -f2-) +DEBUG_API_URL=$(grep -E "^DEBUG_API_URL=" "$ENV_FILE" | cut -d'=' -f2-) + +if [ -z "$DEBUG_ADDRESS" ] || [ -z "$DEBUG_SIGNATURE" ]; then + echo "Error: DEBUG_ADDRESS and DEBUG_SIGNATURE must be set in .env" + exit 1 +fi + +API_URL="${DEBUG_API_URL:-https://api.dfx.swiss/v1}" + +# Authenticate +TOKEN_RESPONSE=$(curl -s -X POST "$API_URL/auth" \ + -H "Content-Type: application/json" \ + -d "{\"address\":\"$DEBUG_ADDRESS\",\"signature\":\"$DEBUG_SIGNATURE\"}") + +TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.accessToken' 2>/dev/null) + +if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then + echo "Authentication failed" + exit 1 +fi + +# Get asset IDs for this financial type +ASSET_IDS=$(curl -s -X POST "$API_URL/gs/debug" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"sql\":\"SELECT id FROM asset WHERE financialType = '$FINANCIAL_TYPE'\"}" | \ + jq -r '.[].id' | tr '\n' ',' | sed 's/,$//') + +echo "=== Asset Balance Sum for Financial Type: $FINANCIAL_TYPE ===" +echo "Log ID: $LOG_ID" +echo "Asset IDs: $ASSET_IDS" +echo "" + +# Get log entry +SQL="SELECT id, created, message FROM log WHERE id = $LOG_ID" +RESULT=$(curl -s -X POST "$API_URL/gs/debug" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"sql\":\"$SQL\"}") + +# Parse with jq +echo "$RESULT" | jq -r --arg asset_ids "$ASSET_IDS" ' + .[0] as $entry | + ($entry.message | fromjson) as $msg | + + # Split asset IDs + ($asset_ids | split(",") | map(tonumber)) as $ids | + + "Log Entry: \($entry.id) at \($entry.created)", + "", + "Individual Asset Balances:", + "", + + # Process each asset + [ + $ids[] | . as $id | + $msg.assets[($id | tostring)] as $asset | + if $asset then + { + id: $id, + plusTotal: ($asset.plusBalance.total // 0), + minusTotal: ($asset.minusBalance.total // 0), + priceChf: ($asset.priceChf // 0), + plusChf: (($asset.plusBalance.total // 0) * ($asset.priceChf // 0)), + minusChf: (($asset.minusBalance.total // 0) * ($asset.priceChf // 0)), + netChf: ((($asset.plusBalance.total // 0) - ($asset.minusBalance.total // 0)) * ($asset.priceChf // 0)) + } + else + { + id: $id, + plusTotal: 0, + minusTotal: 0, + priceChf: 0, + plusChf: 0, + minusChf: 0, + netChf: 0 + } + end + ] as $balances | + + # Print details + ($balances[] | "Asset \(.id): plus=\(.plusTotal | tostring | .[0:12]) minus=\(.minusTotal | tostring | .[0:12]) price=\(.priceChf | tostring | .[0:10]) → plusChf=\(.plusChf | tostring | .[0:12]) netChf=\(.netChf | tostring | .[0:12])"), + "", + "=== Summary ===", + "", + "Total Plus CHF: \($balances | map(.plusChf) | add)", + "Total Minus CHF: \($balances | map(.minusChf) | add)", + "Total Net CHF: \($balances | map(.netChf) | add)" +'