Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ==========================================
# ⚙️ BOT BEHAVIOR & LIMITS
# ==========================================
# Max budget in Euro across all sessions (Optional)
MAX_BUDGET=1000

# Max concurrent sessions (Optional)
MAX_PARALLEL_SESSIONS=10

# ==========================================
# 🤖 TELEGRAM CONFIGURATION
# ==========================================
TELEGRAM_BOT_TOKEN=your_bot_token_here

# Root Users (Admins)
# Add up to 3 root user IDs (leave empty if not used)
TELEGRAM_ROOT_USER_ID_1=123456789
TELEGRAM_ROOT_USER_ID_2=
TELEGRAM_ROOT_USER_ID_3=

# ==========================================
# ⚡ LIGHTNING BACKEND: ALBY HUB (NWC)
# ==========================================
# Primary backend. Uses Nostr Wallet Connect.
# Format: nostr+walletconnect://PUBKEY?relay=RELAY_URL&secret=SECRET
ALBYHUB_CONNECTION_STRING=your_nwc_connection_string_here

# ==========================================
# ⚡ LIGHTNING BACKEND: LNBITS (Alternative)
# ==========================================
# To use LNBits instead of AlbyHub:
# 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
154 changes: 154 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Build and Deploy

on:
push:
branches: [ "master" ]
tags: [ "v*" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:

env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}

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'
outputs:
new_tag: ${{ steps.tag_version.outputs.new_tag }}
changelog: ${{ steps.tag_version.outputs.changelog }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required to calculate version history

- 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

build-and-test:
runs-on: ubuntu-latest
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 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

- name: Publish
run: dotnet publish src/teamZaps.csproj --configuration Release --output ./publish

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: teamZaps-binaries
path: ./publish

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
if: |
always() &&
(needs.build-and-test.result == 'success') &&
(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
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=sha
# Add the auto-calculated tag if available
type=raw,value=${{ needs.calculate-version.outputs.new_tag }},enable=${{ needs.calculate-version.outputs.new_tag != '' }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

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
if: |
always() &&
(needs.build-and-test.result == 'success') &&
(needs.calculate-version.outputs.new_tag != '' || startsWith(github.ref, 'refs/tags/v'))
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: teamZaps-binaries
path: ./teamZaps

# Determine the tag name to use (either auto-calculated or manual)
- name: Set Tag Name
id: tag_name
run: |
if [ -n "${{ needs.calculate-version.outputs.new_tag }}" ]; then
echo "tag=${{ needs.calculate-version.outputs.new_tag }}" >> $GITHUB_OUTPUT
else
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
fi

- name: Zip Artifacts
run: zip -r teamZaps-${{ steps.tag_name.outputs.tag }}.zip ./teamZaps

- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.tag_name.outputs.tag }}
files: teamZaps-${{ steps.tag_name.outputs.tag }}.zip
generate_release_notes: true
body: ${{ needs.calculate-version.outputs.changelog }}
32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Base image for runtime
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app

# SDK image for building
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# Copy csproj and restore dependencies
COPY ["src/teamZaps.csproj", "src/"]
RUN dotnet restore "src/teamZaps.csproj"

# Copy the rest of the source code
COPY . .
WORKDIR "/src/src"

# Build the application
RUN dotnet build "teamZaps.csproj" -c Release -o /app/build

# Publish the application
FROM build AS publish
RUN dotnet publish "teamZaps.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Final stage/image
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

# Create directory for data/logs if needed (optional, based on app needs)
# RUN mkdir -p /app/data

ENTRYPOINT ["dotnet", "teamZaps.dll"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 SatMeNow

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
72 changes: 43 additions & 29 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Team Zaps 🎯⚡

> **Split bills with Bitcoin Lightning in Telegram groups!**
**Split bills with Bitcoin Lightning in Telegram groups!**

Team Zaps helps groups coordinate Lightning payments for shared expenses. When Bitcoin isn't accepted at your favorite restaurant or bar, use Team Zaps to let everyone pay in sats while one person handles the fiat transaction.

Expand All @@ -21,35 +21,42 @@ Your team meets up for food and drinks, but the venue doesn't accept Bitcoin? He

## 🚀 Getting Started

### 1. Add Bot to Your Group
1. Add `@TeamZapsBot` to your Telegram group (replace with your actual bot username)
2. Grant the bot admin rights to pin messages
Follow the appropriate path below depending on whether you are a group admin or a regular user.

### 2. Start Using Team Zaps
### Admins: Set up the bot for your group
1. Add the bot to your group: search for `@TeamZapsBot` and invite it.
2. Open `Group Info` → `Administrators` → Promote the bot to an administrator.
- Grant these permissions at minimum:
- **Delete messages**
- Optional but recommended:
- **Pin messages** (if pinned session status is desired)
3. Confirm the bot appears in the admin list.
4. Configure who may start/close sessions in the bot settings (admins only by default).

**In your group chat:**
### Users: Join and use Team Zaps
Once the bot is added and has necessary permissions, users can interact:

In the group chat:
```
/startsession - Start a new payment session
/help - View all available commands
/startsession # Admins only (configurable)
/status # Show current session status
/help # Show help and commands
```

**The bot will guide you through:**
- Joining the session
- Entering the lottery (who's willing to pay fiat)
- Making Lightning payments in private chat
- Drawing the winner and executing the payout

### 3. Payment Flow

1. **Join Session** - Click the "🎯 Join" button on the pinned message
2. **Enter Lottery** - Click "🎰 Enter Lottery" if you're willing to pay the bill
3. **Send Payments** - In private chat with the bot, send amounts like:
- `5.99 beer`
- `12.50 pizza + 3.00 tip`
- Multiple lines also work!
4. **Pay Invoices** - Pay the Lightning invoices the bot sends you
5. **Wait for Draw** - When the group closes the session, a winner is drawn
6. **Automatic Payout** - Winner submits Lightning invoice and receives all payments
How to participate:
- Click the pinned session message's **🎯 Join** button to join a session.
- If you're willing to pay the bill in fiat, click **🎰 Enter Lottery**.
- For payments and private info, open a private chat with the bot and send amounts like:
- `5.99 beer`
- `12.50 pizza + 3.00 tip`
- Multiple lines are allowed.

Payment flow summary:
1. Join session in group
2. Enter lottery (optional)
3. Send payments in private chat
4. Admin closes session → winner is drawn
5. Winner submits Lightning invoice → automatic payout

## ⚡ Payment Examples

Expand All @@ -71,15 +78,19 @@ The bot accepts various payment formats:

## 🔧 Bot Commands

### Group (use in group chats)
| Command | Description | Who can Use |
|---------|-------------|-------------|
| `/startsession` | Start a new payment session | Admins (configurable) |
| `/closesession` | Close payments and draw winner | Admins (configurable) |
| `/cancelsession` | Cancel the current session | Admins |
| `/status` | View current session status | Anyone |
| `/recover` | Recover lost sats from failed sessions | Anyone (private chat) |
| `/help` | Show help information | Anyone |
| `/diag` | Show diagnostics | Root users |

### Private (use in direct messages with the bot)
| Command | Description |
|---------|-------------|
| `/recover` | Recover lost sats from failed sessions |
| `/help` | Show help information |

## 💰 Lost and Found Recovery

Expand Down Expand Up @@ -140,7 +151,10 @@ Want to run your own Team Zaps bot? Check the [developer documentation](src/READ

## 🤝 Contributing

Contributions are welcome! Please read the [developer documentation](src/README.md) for technical details and contribution guidelines.
Contributions are welcome

Please read the [developer documentation](src/README.md) for technical details and contribution guidelines.
You will find the [repository](https://github.com/SatMeNow/teamZaps) on github.

## 📞 Support

Expand Down
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
services:
teamzaps:
image: ghcr.io/satmenow/teamzaps:latest
container_name: teamzaps
restart: unless-stopped
environment:
- DOTNET_ENVIRONMENT=Production

# Bot Behavior
- BotBehavior__MaxBudget=${MAX_BUDGET}
- BotBehavior__MaxParallelSessions=${MAX_PARALLEL_SESSIONS}

# Telegram Settings
- Telegram__BotToken=${TELEGRAM_BOT_TOKEN}
- Telegram__RootUsers__0=${TELEGRAM_ROOT_USER_ID_1}
- Telegram__RootUsers__1=${TELEGRAM_ROOT_USER_ID_2}
- Telegram__RootUsers__2=${TELEGRAM_ROOT_USER_ID_3}

# Backend: AlbyHub (NWC)
- Backends__AlbyHub__ConnectionString=${ALBYHUB_CONNECTION_STRING}

# Backend: LNBits (Alternative)
# - Backends__LNBits__LndhubUrl=${LNBITS_URL}
# - Backends__LNBits__ApiKey=${LNBITS_API_KEY}

volumes:
# Mount appsettings.json if you want to configure it from the host
- ./appsettings.json:/app/appsettings.json
# Mount data directory if the app writes logs or data
- ./data:/app/data
3 changes: 0 additions & 3 deletions src/.env.example

This file was deleted.

Loading