Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
d548c62
ci: improve CI/CD pipeline #minor
SatMeNow Dec 22, 2025
7e7dbb5
Minor changes
SatMeNow Dec 22, 2025
e1ea76c
ci: improve CI/CD pipeline #minor
SatMeNow Dec 22, 2025
a43d871
Minor code improvements
SatMeNow Dec 22, 2025
68feed6
Implement file service
SatMeNow Dec 23, 2025
78e28b7
ci: improve CI/CD pipeline
SatMeNow Dec 23, 2025
4240b51
Implement admin options
SatMeNow Dec 22, 2025
ca4c33e
Minor changes
SatMeNow Dec 23, 2025
b199563
Implement electrumx service
SatMeNow Dec 24, 2025
942048f
Configure current locale
SatMeNow Dec 24, 2025
f7cc28b
LNBits: Improve supported currencies
SatMeNow Dec 24, 2025
4d3fd05
Fix join session for new users
SatMeNow Dec 25, 2025
447fd2e
Improve backend injection
SatMeNow Dec 26, 2025
758f409
Minor changes
SatMeNow Dec 26, 2025
b5a6562
Implement statistics
SatMeNow Dec 26, 2025
1a802ba
Add liquidity monitoring
SatMeNow Jan 3, 2026
a0e6a24
Customize session title
SatMeNow Jan 3, 2026
e9904b5
Add about command
SatMeNow Jan 3, 2026
06cce10
Minor backend connection improvements
SatMeNow Jan 6, 2026
e71500f
Fix appsettings
SatMeNow Jan 7, 2026
fa6c7fc
Fix logger configuration
SatMeNow Jan 8, 2026
37c9473
Minor improvements
SatMeNow Jan 9, 2026
493c1ed
ElectrumX: Add multi-server support
SatMeNow Jan 8, 2026
c76dad1
Improve connection validation
SatMeNow Jan 9, 2026
3157788
ElectrumX: Implement SSL support
SatMeNow Jan 9, 2026
1f5463f
ElectrumX: Improve request handling
SatMeNow Jan 10, 2026
385046c
ElectrumX: Test stale hosts
SatMeNow Jan 11, 2026
7e06525
Fix build configuration selection
SatMeNow Jan 11, 2026
8f07b95
CoinGecko: **Depricated from now**
SatMeNow Jan 12, 2026
983754f
Minor changes
SatMeNow Jan 12, 2026
110c2e3
CoinCap: **Depricated from now**
SatMeNow Jan 12, 2026
9a1a636
Yadio: Implement exchange rate backend
SatMeNow Jan 12, 2026
bd5da17
Refactor code: make namespaces upper-case
SatMeNow Jan 14, 2026
342b30a
Improve user statistics
SatMeNow Jan 14, 2026
f7df266
Write log files
SatMeNow Jan 15, 2026
c85d1c5
Improve exceptional user answers
SatMeNow Jan 15, 2026
7b8e948
Minor changes
SatMeNow Jan 15, 2026
4e512fc
Save user options
SatMeNow Jan 15, 2026
c750a7d
Minor changes
SatMeNow Jan 17, 2026
77cfa79
ElectrumX: Enhance connection
SatMeNow Jan 17, 2026
d1592af
ElectrumX: Fix connection reuse
SatMeNow Jan 18, 2026
d284023
Add root users to admin permission checks
SatMeNow Jan 18, 2026
60aa09e
ElectrumX: Estimate blocks for failed requests
SatMeNow Jan 18, 2026
24680c8
RecoveryService: Fix execution
SatMeNow Jan 19, 2026
8d779c4
Fix command handling for explicit recipients
SatMeNow Jan 20, 2026
1398429
Schedule lost sats recovery notifications
SatMeNow Jan 20, 2026
b2cdee6
Debug: Add trace listener
SatMeNow Jan 20, 2026
3b9b1cd
Minor improvements
SatMeNow Jan 20, 2026
97d25c8
Add participants to liquidity log
SatMeNow Jan 20, 2026
347c039
Split payments
SatMeNow Jan 20, 2026
d3cc603
LiquidityLog: Add separate tag column
SatMeNow Jan 21, 2026
57bd4a6
Add salutation when answering users
SatMeNow Jan 21, 2026
170fba6
ElectrumX: Redesign subscription workflow
SatMeNow Jan 21, 2026
8dd0a54
Fix detecting for lost sats
SatMeNow Jan 22, 2026
06fdb71
Validate bot permissions
SatMeNow Jan 22, 2026
9a7348e
Minor improvements
SatMeNow Jan 22, 2026
469b06d
Redirect user answers
SatMeNow Jan 22, 2026
e77bbdf
Implement backend sanity checks
SatMeNow Jan 23, 2026
fe9b61e
Recovery: Shift lost sats to winner
SatMeNow Jan 24, 2026
8df4563
Delete expired chat messages
SatMeNow Jan 24, 2026
aa2ca0b
LightningBackends: Improve error handling
SatMeNow Jan 26, 2026
e343517
Add timezone configuration to Docker volumes
SatMeNow Jan 26, 2026
70f9e87
Improve winner selection entropy
SatMeNow Jan 26, 2026
972972d
Make exchange rate backend madatory
SatMeNow Jan 30, 2026
7d8c832
Estimate locked sats
SatMeNow Jan 31, 2026
05e8afc
Fix deleting expired messages
SatMeNow Jan 31, 2026
410dcbc
Fix missing user name
SatMeNow Feb 2, 2026
d5c089a
Fix welcome message
SatMeNow Feb 23, 2026
7c2e173
Cancel outstanding unpaid invoices
SatMeNow Feb 23, 2026
248f3af
Fix join as new user
SatMeNow Feb 28, 2026
3a475c7
Implement dedicated payment phase
SatMeNow Feb 25, 2026
6d09ba9
Minor fixes
SatMeNow Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
# ==========================================
# 🐳 DOCKER DEPLOYMENT SETTINGS
# ==========================================
# Tag to deploy (latest, beta, rc, or specific version like v1.0.1)
# Defaults to 'latest' if not set
# DOCKER_TAG=latest

# Environment (Production, Development, Staging)
# Defaults to 'Production' if not set
# DOTNET_ENVIRONMENT=Production

# ==========================================
# ⚙️ BOT BEHAVIOR & LIMITS
# ==========================================
# Max budget in Euro across all sessions (Optional)
MAX_BUDGET=1000
# Maximum locked sats (exact) across all active sessions (Optional)
MAX_LOCKED_SATS=1000000
# Maximum estimated locked sats (heuristic) across all active sessions (Optional)
MAX_ESTIMATED_LOCKED_SATS=2000000

# Max concurrent sessions (Optional)
MAX_PARALLEL_SESSIONS=10

# Bot locale/culture for formatting and localization (en-US, de-DE, it-IT, fr-FR, etc.)
BOT_LOCALE=en-US

# Time of day for backend sanity checks (HH:MM:SS format, default: 03:00:00)
# SANITY_CHECK_TIME=03:00:00

# ==========================================
# 🤖 TELEGRAM CONFIGURATION
# ==========================================
Expand All @@ -18,6 +39,22 @@ TELEGRAM_ROOT_USER_ID_1=123456789
TELEGRAM_ROOT_USER_ID_2=
TELEGRAM_ROOT_USER_ID_3=

# ==========================================
# 🔗 BLOCKCHAIN BACKEND: ELECTRUMX
# ==========================================
# ElectrumX servers for blockchain data (block height, timestamps)
# Configure multiple hosts for automatic failover (recommended: 3-5 hosts)
# SSL/TLS is automatically used for port 50002, plain TCP for 50001
# Format: hostname or hostname:port
ELECTRUMX_HOST_1=electrum.blockstream.info
ELECTRUMX_HOST_2=fulcrum.sethforprivacy.com
ELECTRUMX_HOST_3=electrum.emzy.de
# ELECTRUMX_HOST_4=bitcoin.lu.ke
# ELECTRUMX_HOST_5=bitcoin.grey.pw
ELECTRUMX_PORT=50002
ELECTRUMX_VALIDATE_CERT=false
ELECTRUMX_TIMEOUT=10000

# ==========================================
# ⚡ LIGHTNING BACKEND: ALBY HUB (NWC)
# ==========================================
Expand All @@ -32,4 +69,32 @@ ALBYHUB_CONNECTION_STRING=your_nwc_connection_string_here
# 1. Uncomment these lines
# 2. Uncomment the corresponding lines in docker-compose.yml
# LNBITS_URL=https://legend.lnbits.com/lndhub/ext/
# LNBITS_API_KEY=your_lnbits_admin_key
# LNBITS_API_KEY=your_lnbits_invoice_or_admin_key

# ==========================================
# 💱 EXCHANGE RATE BACKEND: YADIO
# ==========================================
# Yadio provides free exchange rates without authentication.
# Rate limit: 100 requests per minute
#
# Yadio has no configurable properties and cannot be enabled via env vars.
# To enable it, add the following to the Backends section in appsettings.json:
# "Yadio": {}

# ==========================================
# 💱 EXCHANGE RATE BACKENDS (DEPRECATED)
# ==========================================
# CoinCap API (requires paid subscription)
# COINCAP_API_KEY=your_coincap_api_key_here

# CoinGecko API (requires paid subscription)
# COINGECKO_API_KEY=your_coingecko_api_key_here

# ==========================================
# 🔄 RECOVERY SYSTEM
# ==========================================
# Enable/disable lost sats recovery system
# RECOVERY_ENABLE=true

# Daily scan time for recovery notifications (HH:MM:SS format)
# RECOVERY_DAILY_SCAN_TIME=08:00:00
152 changes: 133 additions & 19 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,26 @@ name: Build and Deploy

on:
push:
branches: [ "master" ]
branches: [ "master", "nextMaster" ]
tags: [ "v*" ]
pull_request:
branches: [ "master" ]
branches: [ "master", "nextMaster" ]
workflow_dispatch:
inputs:
release_type:
description: 'Release type (for manual workflow dispatch builds)'
required: true
default: 'beta'
type: choice
options:
- beta
- rc
- debug
run_unittests:
description: 'Run unit tests'
required: false
default: true
type: boolean

env:
# Use docker.io for Docker Hub if empty
Expand All @@ -18,32 +33,109 @@ jobs:
# 1. Calculate the next version based on commits
calculate-version:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
if: |
(github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/nextMaster')) ||
(github.event_name == 'workflow_dispatch')
outputs:
new_tag: ${{ steps.tag_version.outputs.new_tag }}
new_version: ${{ steps.tag_version.outputs.new_version }}
changelog: ${{ steps.tag_version.outputs.changelog }}
is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required to calculate version history

- name: Determine Pre-release Suffix
id: check_prerelease
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "suffix=${{ inputs.release_type }}" >> $GITHUB_OUTPUT
echo "is_prerelease=true" >> $GITHUB_OUTPUT
else
echo "suffix=" >> $GITHUB_OUTPUT
echo "is_prerelease=false" >> $GITHUB_OUTPUT
fi

- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
default_bump: patch # Default to patch (v1.0.0 -> v1.0.1) if no #major/#minor found
default_bump: patch
# If suffix is set (e.g. 'beta'), it creates v1.0.1-beta.0
append_to_pre_release_tag: ${{ steps.check_prerelease.outputs.suffix }}
# Treat nextMaster as a pre-release branch
pre_release_branches: nextMaster
# Don't push tags for debug builds or nextMaster
dry_run: ${{ inputs.release_type == 'debug' || github.ref == 'refs/heads/nextMaster' }}

test:
runs-on: ubuntu-latest
if: |
(github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/nextMaster')) ||
(github.event_name == 'pull_request') ||
(github.event_name == 'workflow_dispatch' && inputs.run_unittests == true)
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x

- name: Restore dependencies
run: dotnet restore

- name: Run Tests
run: dotnet test --verbosity normal

build-and-test:
needs: [calculate-version, test]
if: always() && (needs.calculate-version.result == 'success' || needs.calculate-version.result == 'skipped') && (needs.test.result == 'success' || needs.test.result == 'skipped')
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version_output }}
base_version: ${{ steps.version.outputs.base_version_output }}
permissions:
contents: read

steps:
- uses: actions/checkout@v4

- name: Determine Configuration
id: config
run: |
if [[ "${{ inputs.release_type }}" == "debug" ]]; then
echo "BUILD_CONFIGURATION=Debug" >> $GITHUB_ENV
else
echo "BUILD_CONFIGURATION=Release" >> $GITHUB_ENV
fi

- name: Determine Version
id: version
run: |
VERSION="0.0.0-ci"
BASE_VERSION="0.0.0-ci"
if [ "${{ needs.calculate-version.result }}" == "success" ] && [ -n "${{ needs.calculate-version.outputs.new_version }}" ]; then
VERSION="${{ needs.calculate-version.outputs.new_version }}"
# Extract base version without pre-release suffix for debug tag generation
BASE_VERSION=$(echo "$VERSION" | sed 's/-.*$//')
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
VERSION="${{ github.ref_name }}"
# Strip 'v' prefix if present
VERSION="${VERSION#v}"
BASE_VERSION="$VERSION"
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV
echo "version_output=$VERSION" >> $GITHUB_OUTPUT
echo "base_version_output=$BASE_VERSION" >> $GITHUB_OUTPUT
echo "Determined version: $VERSION (base: $BASE_VERSION)"

- name: Setup .NET
uses: actions/setup-dotnet@v4
Expand All @@ -54,14 +146,10 @@ jobs:
run: dotnet restore src/teamZaps.csproj

- name: Build
run: dotnet build src/teamZaps.csproj --no-restore --configuration Release

# TODO: No tests implemented yet
# - name: Test
# run: dotnet test src/teamZaps.csproj --no-build --verbosity normal
run: dotnet build src/teamZaps.csproj --no-restore --configuration ${{ env.BUILD_CONFIGURATION }} /p:Version=${{ env.VERSION }}

- name: Publish
run: dotnet publish src/teamZaps.csproj --configuration Release --output ./publish
run: dotnet publish src/teamZaps.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --output ./publish /p:Version=${{ env.VERSION }}

- name: Upload Artifacts
uses: actions/upload-artifact@v4
Expand All @@ -72,11 +160,17 @@ jobs:
docker-build-push:
needs: [build-and-test, calculate-version]
runs-on: ubuntu-latest
# Only run if we are on master (auto-tagging) OR if a tag was pushed manually
# Run if:
# 1. Build passed
# 2. AND (Master push OR Tag push OR Manual trigger with new tag / debug)
if: |
always() &&
(needs.build-and-test.result == 'success') &&
(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
(
(github.event_name == 'push' && github.ref == 'refs/heads/master') ||
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' && (inputs.release_type == 'debug' || needs.calculate-version.outputs.new_tag != ''))
)
permissions:
contents: read
packages: write
Expand All @@ -98,13 +192,21 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}},enable=${{ github.event_name != 'workflow_dispatch' || inputs.release_type != 'debug' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name != 'workflow_dispatch' || inputs.release_type != 'debug' }}
type=sha
# Add the auto-calculated tag if available
type=raw,value=${{ needs.calculate-version.outputs.new_tag }},enable=${{ needs.calculate-version.outputs.new_tag != '' }}

# Master -> latest
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}

# nextMaster manual trigger / manual debug -> beta/rc/debug
type=raw,value=${{ inputs.release_type }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.release_type != '' }}

# Add the auto-calculated tag if available (skip for debug, since we emit a debug version tag)
type=raw,value=${{ needs.calculate-version.outputs.new_tag }},enable=${{ needs.calculate-version.outputs.new_tag != '' && (github.event_name != 'workflow_dispatch' || inputs.release_type != 'debug') }}
# Make sure debug runs still publish a semver-style tag that includes the suffix and run number
type=raw,value=v${{ needs.build-and-test.outputs.base_version }}-debug.${{ github.run_number }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.release_type == 'debug' }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
Expand All @@ -113,14 +215,25 @@ jobs:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ needs.build-and-test.outputs.version }}
BUILD_CONFIGURATION=${{ inputs.release_type == 'debug' && 'Debug' || 'Release' }}

create-release:
needs: [build-and-test, docker-build-push, calculate-version]
# Run if we are on master (auto-tagging) OR if a tag was pushed manually
# Run if:
# 1. Build passed
# 2. AND (Master push OR Tag push OR Manual trigger with new tag)
# 3. AND NOT debug build
if: |
always() &&
(needs.build-and-test.result == 'success') &&
(needs.calculate-version.outputs.new_tag != '' || startsWith(github.ref, 'refs/tags/v'))
(inputs.release_type != 'debug') &&
(
(github.event_name == 'push' && github.ref == 'refs/heads/master') ||
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' && needs.calculate-version.outputs.new_tag != '')
)
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -152,3 +265,4 @@ jobs:
files: teamZaps-${{ steps.tag_name.outputs.tag }}.zip
generate_release_notes: true
body: ${{ needs.calculate-version.outputs.changelog }}
prerelease: ${{ needs.calculate-version.outputs.is_prerelease == 'true' }}
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ project.fragment.lock.json
artifacts/

appsettings.*.json
!appsettings.Example.json

# Tye
.tye/
Expand Down Expand Up @@ -129,8 +130,8 @@ ipch/
# Visual Studio Trace Files
*.e2e

# Goose
/.goosehints
# AI
/AGENTS.md

# TFS 2012 Local Workspace
$tf/
Expand Down
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
"cwd": "${workspaceFolder}/src",
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Test",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "dotnet",
"args": [
"test",
"${workspaceFolder}/tests/teamZaps.Tests.csproj"
],
"cwd": "${workspaceFolder}",
"console": "internalConsole",
"stopAtEntry": false
}
]
}
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ COPY . .
WORKDIR "/src/src"

# Build the application
RUN dotnet build "teamZaps.csproj" -c Release -o /app/build
ARG VERSION=0.0.0.0-local
ARG BUILD_CONFIGURATION=Release
RUN dotnet build "teamZaps.csproj" -c ${BUILD_CONFIGURATION} -o /app/build /p:Version=${VERSION}

# Publish the application
FROM build AS publish
RUN dotnet publish "teamZaps.csproj" -c Release -o /app/publish /p:UseAppHost=false
ARG VERSION=0.0.0.0-local
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "teamZaps.csproj" -c ${BUILD_CONFIGURATION} -o /app/publish /p:UseAppHost=false /p:Version=${VERSION}

# Final stage/image
FROM base AS final
Expand Down
Loading