Compare commits
2 commits
6dfa6a7723
...
bb60bba8fa
| Author | SHA1 | Date | |
|---|---|---|---|
| bb60bba8fa | |||
| 582081f2fe |
4 changed files with 143 additions and 48 deletions
88
AUTO_CREDIT_CHANGES.md
Normal file
88
AUTO_CREDIT_CHANGES.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# LNBits Auto-Credit Changes
|
||||
|
||||
## Overview
|
||||
Modified LNBits server to automatically credit new accounts with 1 million satoshis (1,000,000 sats) when they are created.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Modified `lnbits/core/services/users.py`
|
||||
|
||||
**Added imports:**
|
||||
- `get_wallet` from `..crud`
|
||||
- `update_wallet_balance` from `.payments`
|
||||
|
||||
**Modified `create_user_account_no_ckeck` function:**
|
||||
- Changed `create_wallet` call to capture the returned wallet object
|
||||
- Added automatic credit of 1,000,000 sats after wallet creation
|
||||
- Added error handling and logging for the credit operation
|
||||
|
||||
**Code changes:**
|
||||
```python
|
||||
# Before:
|
||||
await create_wallet(
|
||||
user_id=account.id,
|
||||
wallet_name=wallet_name or settings.lnbits_default_wallet_name,
|
||||
)
|
||||
|
||||
# After:
|
||||
wallet = await create_wallet(
|
||||
user_id=account.id,
|
||||
wallet_name=wallet_name or settings.lnbits_default_wallet_name,
|
||||
)
|
||||
|
||||
# Credit new account with 1 million satoshis
|
||||
try:
|
||||
await update_wallet_balance(wallet, 1_000_000)
|
||||
logger.info(f"Credited new account {account.id} with 1,000,000 sats")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to credit new account {account.id} with 1,000,000 sats: {e}")
|
||||
```
|
||||
|
||||
### 2. Updated Tests in `tests/api/test_auth.py`
|
||||
|
||||
**Modified test functions:**
|
||||
- `test_register_ok`: Added balance verification for regular user registration
|
||||
- `test_register_nostr_ok`: Added balance verification for Nostr authentication
|
||||
|
||||
**Added assertions:**
|
||||
```python
|
||||
# Check that the wallet has 1 million satoshis
|
||||
wallet = user.wallets[0]
|
||||
assert wallet.balance == 1_000_000, f"Expected 1,000,000 sats balance, got {wallet.balance} sats"
|
||||
```
|
||||
|
||||
## Affected Account Creation Paths
|
||||
|
||||
The automatic credit will be applied to all new accounts created through:
|
||||
|
||||
1. **Regular user registration** (`/api/v1/auth/register`)
|
||||
2. **Nostr authentication** (`/api/v1/auth/nostr`)
|
||||
3. **SSO login** (when new account is created)
|
||||
4. **API account creation** (`/api/v1/account`)
|
||||
5. **Admin user creation** (via admin interface)
|
||||
|
||||
## Excluded Paths
|
||||
|
||||
- **Superuser/Admin account creation** (`init_admin_settings`): This function creates the admin account directly and bypasses the user creation flow, so it won't receive the automatic credit.
|
||||
|
||||
## Testing
|
||||
|
||||
To test the changes:
|
||||
|
||||
1. Install dependencies: `poetry install`
|
||||
2. Run the modified tests: `poetry run pytest tests/api/test_auth.py::test_register_ok -v`
|
||||
3. Run Nostr test: `poetry run pytest tests/api/test_auth.py::test_register_nostr_ok -v`
|
||||
|
||||
## Logging
|
||||
|
||||
The system will log:
|
||||
- Success: `"Credited new account {account.id} with 1,000,000 sats"`
|
||||
- Failure: `"Failed to credit new account {account.id} with 1,000,000 sats: {error}"`
|
||||
|
||||
## Notes
|
||||
|
||||
- The credit uses the existing `update_wallet_balance` function which creates an internal payment record
|
||||
- The credit is applied after wallet creation but before user extensions are set up
|
||||
- Error handling ensures that account creation continues even if the credit fails
|
||||
- The credit amount is hardcoded to 1,000,000 sats (1MM sats)
|
||||
|
||||
|
|
@ -6,83 +6,73 @@
|
|||
"extensions": [
|
||||
{
|
||||
"id": "satmachineadmin",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/satmachineadmin",
|
||||
"repo": "https://git.atitlan.io/aiolabs/satmachineadmin",
|
||||
"name": "Satoshi Machine Admin",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.1",
|
||||
"short_description": "Admin Dashboard for Satoshi Machine",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/satmachineadmin/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/satmachineadmin/archive/v0.0.2.zip",
|
||||
"hash": "e46863d3c1133897d9fe9cc4afe149804df25b2aeee1716de4da4332ae9789b1"
|
||||
"icon": "https://git.atitlan.io/aiolabs/satmachineadmin/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/satmachineadmin/archive/v0.0.1.zip",
|
||||
"hash": "e9b61de40e940f05aca460a0560cd3cc8b98f2f0d861e37cef13b046eaec0b7c"
|
||||
},
|
||||
{
|
||||
"id": "satmachineclient",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/satmachineclient",
|
||||
"repo": "https://git.atitlan.io/aiolabs/satmachineclient",
|
||||
"name": "Satoshi Machine Client",
|
||||
"version": "0.0.1",
|
||||
"short_description": "Client Dashboard for Satoshi Machine",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/satmachineclient/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/satmachineclient/archive/v0.0.1.zip",
|
||||
"hash": "6d93e1a537ca3565fcf4dc4811497de10660a14639046854c1006b06d9a045e5"
|
||||
"icon": "https://git.atitlan.io/aiolabs/satmachineclient/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/satmachineclient/archive/v0.0.1.zip",
|
||||
"hash": "05cf74b0f8a39953ad9c063c40a983d6223ebbfa906f5598b6ebe2c58eccfd9a"
|
||||
},
|
||||
{
|
||||
"id": "events",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/events",
|
||||
"repo": "https://git.atitlan.io/aiolabs/events",
|
||||
"name": "AIO Events",
|
||||
"version": "0.0.1",
|
||||
"short_description": "AIO fork of lnbits-exts/events",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/events/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/events/archive/v0.0.1.zip",
|
||||
"hash": "681408f3f5f5b0773f0aa5fd7fbdefcd47ed9190b44409b80d2b119cc5516335"
|
||||
},
|
||||
{
|
||||
"id": "nostrrelay",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/nostrrelay",
|
||||
"name": "AIO Nostrrelay",
|
||||
"version": "0.0.2",
|
||||
"short_description": "AIO fork of lnbits-exts/nostrrelay",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/nostrrelay/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/nostrrelay/archive/v0.0.2.zip",
|
||||
"hash": "a46475f076557f5c5a426a9e3cbb680af855b833a9f66ba32b6f36778336302f"
|
||||
"short_description": "AIO fork of aiolabs/events",
|
||||
"icon": "https://git.atitlan.io/aiolabs/events/raw/branch/main/static/image/events.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/events/archive/v0.0.1.zip",
|
||||
"hash": "410ac9c340551aabe88e0dc7393ed30dc7f4703f1345af5e6b02b0ebc5337d52"
|
||||
},
|
||||
{
|
||||
"id": "nostrclient",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/nostrclient",
|
||||
"repo": "https://git.atitlan.io/aiolabs/nostrclient",
|
||||
"name": "AIO nostrclient",
|
||||
"version": "0.0.1",
|
||||
"short_description": "AIO fork of lnbits-exts/nostrclient",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/nostrclient/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/nostrclient/archive/v0.0.1.zip",
|
||||
"hash": "c71c6bd2105e299a2ff342fb9d94d619570f28f231a3025f52f29757f9b31d04"
|
||||
"short_description": "AIO fork of aiolabs/nostrclient",
|
||||
"icon": "https://git.atitlan.io/aiolabs/nostrclient/raw/branch/main/static/images/nostr-bitcoin.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/nostrclient/archive/v0.0.1.zip",
|
||||
"hash": "7f0b1861243a10d16d41d17bc6e64616d61c6b299a86f40dc1a0f9cfc7f9725a"
|
||||
},
|
||||
{
|
||||
"id": "nostrmarket",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/nostrmarket",
|
||||
"repo": "https://git.atitlan.io/aiolabs/nostrmarket",
|
||||
"name": "AIO nostrmarket",
|
||||
"version": "0.0.1",
|
||||
"short_description": "AIO fork of lnbits-exts/nostrmarket",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/nostrmarket/raw/branch/main/static/image/aio.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/nostrmarket/archive/v0.0.1.zip",
|
||||
"hash": "5177dfdae62554c75ba8244d5a26e371de6e512a8b6dc7bb6f90e8b05916ed35"
|
||||
"short_description": "AIO fork of aiolabs/nostrmarket",
|
||||
"icon": "https://git.atitlan.io/aiolabs/nostrmarket/raw/branch/main/static/image/bitcoin-shop.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/nostrmarket/archive/v0.0.1.zip",
|
||||
"hash": "7599485232c600c00896caac15c0fdec07aef26d2cce95c9b2df85b9807bf4f3"
|
||||
},
|
||||
{
|
||||
"id": "nostrrelay",
|
||||
"repo": "https://git.atitlan.io/aiolabs/nostrrelay",
|
||||
"name": "AIO Nostrrelay",
|
||||
"version": "0.0.1",
|
||||
"short_description": "AIO fork of aiolabs/nostrrelay",
|
||||
"icon": "https://git.atitlan.io/aiolabs/nostrrelay/raw/branch/main/static/image/nostrrelay.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/nostrrelay/archive/v0.0.1.zip",
|
||||
"hash": "2b1ba6a3b7a79f6595f075c332b82a0ba64c608637ad5bcf23182e40fdf7f68f"
|
||||
},
|
||||
{
|
||||
"id": "castle",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/castle",
|
||||
"repo": "https://git.atitlan.io/aiolabs/castle",
|
||||
"name": "Castle",
|
||||
"version": "0.0.1",
|
||||
"short_description": "Castle Accounting",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/castle/raw/branch/main/static/image/castle.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/castle/archive/v0.0.1.zip",
|
||||
"hash": "0b152190902e7377bfba9feb4c82998a9400a69413ee5482343f15da8308b89b"
|
||||
},
|
||||
{
|
||||
"id": "castle",
|
||||
"repo": "https://git.aiolabs.dev/lnbits-exts/castle",
|
||||
"name": "Castle",
|
||||
"version": "0.0.2",
|
||||
"short_description": "Castle Accounting",
|
||||
"icon": "https://git.aiolabs.dev/lnbits-exts/castle/raw/branch/main/static/image/castle.png",
|
||||
"archive": "https://git.aiolabs.dev/lnbits-exts/castle/archive/v0.0.2.zip",
|
||||
"hash": "0f742deb4777480a32ad239f6eae42c57583bf7a8ca9bd131903b6bb7282f069"
|
||||
"icon": "https://git.atitlan.io/aiolabs/castle/raw/branch/main/static/image/castle.png",
|
||||
"archive": "https://git.atitlan.io/aiolabs/castle/archive/v0.0.1.zip",
|
||||
"hash": "075a96a6f3151472302434fc50552346f7910f82b9ae1c6508d1bfd6db14607b"
|
||||
},
|
||||
{
|
||||
"id": "lnurlp",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from ..crud import (
|
|||
get_super_settings,
|
||||
get_user_extensions,
|
||||
get_user_from_account,
|
||||
get_wallet,
|
||||
update_account,
|
||||
update_super_user,
|
||||
update_user_extension,
|
||||
|
|
@ -37,6 +38,7 @@ from ..models import (
|
|||
UserExtra,
|
||||
)
|
||||
from .settings import update_cached_settings
|
||||
from .payments import update_wallet_balance
|
||||
|
||||
|
||||
async def create_user_account(
|
||||
|
|
@ -80,6 +82,13 @@ async def create_user_account_no_ckeck(
|
|||
conn=conn,
|
||||
)
|
||||
|
||||
# Credit new account with 1 million satoshis
|
||||
try:
|
||||
await update_wallet_balance(wallet, 1_000_000)
|
||||
logger.info(f"Credited new account {account.id} with 1,000,000 sats")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to credit new account {account.id} with 1,000,000 sats: {e}")
|
||||
|
||||
user_extensions = (default_exts or []) + settings.lnbits_user_default_extensions
|
||||
for ext_id in user_extensions:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -296,6 +296,10 @@ async def test_register_ok(http_client: AsyncClient):
|
|||
len(user.wallets) == 1
|
||||
), f"Expected 1 default wallet, not {len(user.wallets)}."
|
||||
|
||||
# Check that the wallet has 1 million satoshis
|
||||
wallet = user.wallets[0]
|
||||
assert wallet.balance == 1_000_000, f"Expected 1,000,000 sats balance, got {wallet.balance} sats"
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_register_email_twice(http_client: AsyncClient):
|
||||
|
|
@ -589,6 +593,10 @@ async def test_register_nostr_ok(http_client: AsyncClient, settings: Settings):
|
|||
len(user.wallets) == 1
|
||||
), f"Expected 1 default wallet, not {len(user.wallets)}."
|
||||
|
||||
# Check that the wallet has 1 million satoshis
|
||||
wallet = user.wallets[0]
|
||||
assert wallet.balance == 1_000_000, f"Expected 1,000,000 sats balance, got {wallet.balance} sats"
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_register_nostr_not_allowed(http_client: AsyncClient, settings: Settings):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue