Compare commits
	
		
			12 Commits
		
	
	
		
			f5ebd573d6
			...
			820ea90267
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					820ea90267 | ||
| 
						 | 
					31d3b2fd76 | ||
| 
						 | 
					46b2a57ece | ||
| 
						 | 
					d146e50660 | ||
| 
						 | 
					fd9b087c99 | ||
| 
						 | 
					e307573e8b | ||
| 
						 | 
					6049baf742 | ||
| 
						 | 
					88fa3bdca6 | ||
| 
						 | 
					c97ce2627b | ||
| 
						 | 
					d06f89d707 | ||
| 
						 | 
					596d67fc68 | ||
| 
						 | 
					75051f1c56 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -56,3 +56,6 @@ docker-compose.*.yml
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# nostr wallet connect
 | 
					# nostr wallet connect
 | 
				
			||||||
scripts/nwc-keys.json
 | 
					scripts/nwc-keys.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# lnbits
 | 
				
			||||||
 | 
					docker/lnbits/data
 | 
				
			||||||
@ -647,14 +647,21 @@ async function upsertWallet (
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { id, ...walletData } = data
 | 
					  const { id, ...walletData } = data
 | 
				
			||||||
  const { autoWithdrawThreshold, autoWithdrawMaxFeePercent, enabled, priority } = settings
 | 
					  const {
 | 
				
			||||||
 | 
					    autoWithdrawThreshold,
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeePercent,
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeeTotal,
 | 
				
			||||||
 | 
					    enabled,
 | 
				
			||||||
 | 
					    priority
 | 
				
			||||||
 | 
					  } = settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const txs = [
 | 
					  const txs = [
 | 
				
			||||||
    models.user.update({
 | 
					    models.user.update({
 | 
				
			||||||
      where: { id: me.id },
 | 
					      where: { id: me.id },
 | 
				
			||||||
      data: {
 | 
					      data: {
 | 
				
			||||||
        autoWithdrawMaxFeePercent,
 | 
					        autoWithdrawMaxFeePercent,
 | 
				
			||||||
        autoWithdrawThreshold
 | 
					        autoWithdrawThreshold,
 | 
				
			||||||
 | 
					        autoWithdrawMaxFeeTotal
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
 | 
				
			|||||||
@ -182,6 +182,7 @@ export default gql`
 | 
				
			|||||||
    withdrawMaxFeeDefault: Int!
 | 
					    withdrawMaxFeeDefault: Int!
 | 
				
			||||||
    autoWithdrawThreshold: Int
 | 
					    autoWithdrawThreshold: Int
 | 
				
			||||||
    autoWithdrawMaxFeePercent: Float
 | 
					    autoWithdrawMaxFeePercent: Float
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeeTotal: Int
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  type UserOptional {
 | 
					  type UserOptional {
 | 
				
			||||||
 | 
				
			|||||||
@ -91,6 +91,7 @@ const typeDefs = `
 | 
				
			|||||||
  input AutowithdrawSettings {
 | 
					  input AutowithdrawSettings {
 | 
				
			||||||
    autoWithdrawThreshold: Int!
 | 
					    autoWithdrawThreshold: Int!
 | 
				
			||||||
    autoWithdrawMaxFeePercent: Float!
 | 
					    autoWithdrawMaxFeePercent: Float!
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeeTotal: Int!
 | 
				
			||||||
    priority: Int
 | 
					    priority: Int
 | 
				
			||||||
    enabled: Boolean
 | 
					    enabled: Boolean
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -135,3 +135,5 @@ toyota-corolla0,pr,#1449,,good-first-issue,,,,20k,toyota_corolla0@stacker.news,2
 | 
				
			|||||||
toyota-corolla0,pr,#1455,#1437,good-first-issue,,,,20k,toyota_corolla0@stacker.news,2024-10-02
 | 
					toyota-corolla0,pr,#1455,#1437,good-first-issue,,,,20k,toyota_corolla0@stacker.news,2024-10-02
 | 
				
			||||||
SouthKoreaLN,issue,#1436,,easy,,,,10k,south_korea_ln@stacker.news,2024-10-02
 | 
					SouthKoreaLN,issue,#1436,,easy,,,,10k,south_korea_ln@stacker.news,2024-10-02
 | 
				
			||||||
TonyGiorgio,issue,#1462,,easy,urgent,,,30k,TonyGiorgio@stacker.news,2024-10-07
 | 
					TonyGiorgio,issue,#1462,,easy,urgent,,,30k,TonyGiorgio@stacker.news,2024-10-07
 | 
				
			||||||
 | 
					hkarani,issue,#1369,#1458,good-first-issue,,,,2k,asterisk32@stacker.news,2024-10-21
 | 
				
			||||||
 | 
					toyota-corolla0,pr,#1369,#1458,good-first-issue,,,,20k,toyota_corolla0@stacker.news,2024-10-20
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
@ -4,6 +4,7 @@ import { useMe } from './me'
 | 
				
			|||||||
import { useEffect, useState } from 'react'
 | 
					import { useEffect, useState } from 'react'
 | 
				
			||||||
import { isNumber } from '@/lib/validate'
 | 
					import { isNumber } from '@/lib/validate'
 | 
				
			||||||
import { useIsClient } from './use-client'
 | 
					import { useIsClient } from './use-client'
 | 
				
			||||||
 | 
					import Link from 'next/link'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function autoWithdrawThreshold ({ me }) {
 | 
					function autoWithdrawThreshold ({ me }) {
 | 
				
			||||||
  return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000
 | 
					  return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000
 | 
				
			||||||
@ -12,7 +13,8 @@ function autoWithdrawThreshold ({ me }) {
 | 
				
			|||||||
export function autowithdrawInitial ({ me }) {
 | 
					export function autowithdrawInitial ({ me }) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    autoWithdrawThreshold: autoWithdrawThreshold({ me }),
 | 
					    autoWithdrawThreshold: autoWithdrawThreshold({ me }),
 | 
				
			||||||
    autoWithdrawMaxFeePercent: isNumber(me?.privates?.autoWithdrawMaxFeePercent) ? me?.privates?.autoWithdrawMaxFeePercent : 1
 | 
					    autoWithdrawMaxFeePercent: isNumber(me?.privates?.autoWithdrawMaxFeePercent) ? me?.privates?.autoWithdrawMaxFeePercent : 1,
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeeTotal: isNumber(me?.privates?.autoWithdrawMaxFeeTotal) ? me?.privates?.autoWithdrawMaxFeeTotal : 1
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,13 +53,30 @@ export function AutowithdrawSettings ({ wallet }) {
 | 
				
			|||||||
            append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
 | 
					            append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
 | 
				
			||||||
            required
 | 
					            required
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					          <h3 className='text-center text-muted pt-3'>network fees</h3>
 | 
				
			||||||
 | 
					          <h6 className='text-center pb-3'>
 | 
				
			||||||
 | 
					            we'll use whichever setting is higher during{' '}
 | 
				
			||||||
 | 
					            <Link
 | 
				
			||||||
 | 
					              target='_blank'
 | 
				
			||||||
 | 
					              href='https://docs.lightning.engineering/the-lightning-network/pathfinding'
 | 
				
			||||||
 | 
					              rel='noreferrer'
 | 
				
			||||||
 | 
					            >pathfinding
 | 
				
			||||||
 | 
					            </Link>
 | 
				
			||||||
 | 
					          </h6>
 | 
				
			||||||
          <Input
 | 
					          <Input
 | 
				
			||||||
            label='max fee'
 | 
					            label='max fee rate'
 | 
				
			||||||
            name='autoWithdrawMaxFeePercent'
 | 
					            name='autoWithdrawMaxFeePercent'
 | 
				
			||||||
            hint='max fee as percent of withdrawal amount'
 | 
					            hint='max fee as percent of withdrawal amount'
 | 
				
			||||||
            append={<InputGroup.Text>%</InputGroup.Text>}
 | 
					            append={<InputGroup.Text>%</InputGroup.Text>}
 | 
				
			||||||
            required
 | 
					            required
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					          <Input
 | 
				
			||||||
 | 
					            label='max fee total'
 | 
				
			||||||
 | 
					            name='autoWithdrawMaxFeeTotal'
 | 
				
			||||||
 | 
					            hint='max fee for any withdrawal amount'
 | 
				
			||||||
 | 
					            append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
 | 
				
			|||||||
@ -586,7 +586,8 @@ services:
 | 
				
			|||||||
      - 'keys-file.json'
 | 
					      - 'keys-file.json'
 | 
				
			||||||
    cpu_shares: "${CPU_SHARES_LOW}"
 | 
					    cpu_shares: "${CPU_SHARES_LOW}"
 | 
				
			||||||
  lnbits:
 | 
					  lnbits:
 | 
				
			||||||
    image: lnbits/lnbits:0.12.5
 | 
					    build:
 | 
				
			||||||
 | 
					      context: ./docker/lnbits
 | 
				
			||||||
    container_name: lnbits
 | 
					    container_name: lnbits
 | 
				
			||||||
    profiles:
 | 
					    profiles:
 | 
				
			||||||
      - wallets
 | 
					      - wallets
 | 
				
			||||||
@ -596,6 +597,7 @@ services:
 | 
				
			|||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
      - stacker_lnd
 | 
					      - stacker_lnd
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
 | 
					      - LNBITS_ADMIN_UI=true
 | 
				
			||||||
      - LNBITS_BACKEND_WALLET_CLASS=LndWallet
 | 
					      - LNBITS_BACKEND_WALLET_CLASS=LndWallet
 | 
				
			||||||
      - LND_GRPC_ENDPOINT=stacker_lnd
 | 
					      - LND_GRPC_ENDPOINT=stacker_lnd
 | 
				
			||||||
      - LND_GRPC_PORT=10009
 | 
					      - LND_GRPC_PORT=10009
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								docker/lnbits/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								docker/lnbits/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					FROM lnbits/lnbits:0.12.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY ["./data/database.sqlite3", "/app/data/database.sqlite3"]
 | 
				
			||||||
 | 
					COPY ["./data/.super_user", "/app/data/.super_user"]
 | 
				
			||||||
							
								
								
									
										1
									
								
								docker/lnbits/data/.super_user
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/lnbits/data/.super_user
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					e46288268b67457399a5fca81809573e
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docker/lnbits/data/database.sqlite3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docker/lnbits/data/database.sqlite3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -27,6 +27,7 @@ ${STREAK_FIELDS}
 | 
				
			|||||||
      noReferralLinks
 | 
					      noReferralLinks
 | 
				
			||||||
      fiatCurrency
 | 
					      fiatCurrency
 | 
				
			||||||
      autoWithdrawMaxFeePercent
 | 
					      autoWithdrawMaxFeePercent
 | 
				
			||||||
 | 
					      autoWithdrawMaxFeeTotal
 | 
				
			||||||
      autoWithdrawThreshold
 | 
					      autoWithdrawThreshold
 | 
				
			||||||
      withdrawMaxFeeDefault
 | 
					      withdrawMaxFeeDefault
 | 
				
			||||||
      satsFilter
 | 
					      satsFilter
 | 
				
			||||||
 | 
				
			|||||||
@ -366,7 +366,8 @@ export function advSchema (args) {
 | 
				
			|||||||
export const autowithdrawSchemaMembers = {
 | 
					export const autowithdrawSchemaMembers = {
 | 
				
			||||||
  enabled: boolean(),
 | 
					  enabled: boolean(),
 | 
				
			||||||
  autoWithdrawThreshold: intValidator.required('required').min(0, 'must be at least 0').max(msatsToSats(BALANCE_LIMIT_MSATS), `must be at most ${abbrNum(msatsToSats(BALANCE_LIMIT_MSATS))}`),
 | 
					  autoWithdrawThreshold: intValidator.required('required').min(0, 'must be at least 0').max(msatsToSats(BALANCE_LIMIT_MSATS), `must be at most ${abbrNum(msatsToSats(BALANCE_LIMIT_MSATS))}`),
 | 
				
			||||||
  autoWithdrawMaxFeePercent: floatValidator.required('required').min(0, 'must be at least 0').max(50, 'must not exceed 50')
 | 
					  autoWithdrawMaxFeePercent: floatValidator.required('required').min(0, 'must be at least 0').max(50, 'must not exceed 50'),
 | 
				
			||||||
 | 
					  autoWithdrawMaxFeeTotal: intValidator.required('required').min(0, 'must be at least 0').max(1_000, 'must not exceed 1000')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const lnAddrAutowithdrawSchema = object({
 | 
					export const lnAddrAutowithdrawSchema = object({
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -7057,9 +7057,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/bitcore-lib": {
 | 
					    "node_modules/bitcore-lib": {
 | 
				
			||||||
      "version": "8.25.40",
 | 
					      "version": "8.25.47",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-8.25.40.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-8.25.47.tgz",
 | 
				
			||||||
      "integrity": "sha512-mb6kvfhoiIdoyFsDlhIFVst3HpeGjGYBf0XDxTdZ+H07EC4JuiViA3bnQ5uZbZjHFngEl0GTPaoK1Zaolutw4A==",
 | 
					      "integrity": "sha512-qDZr42HuP4P02I8kMGZUx/vvwuDsz8X3rQxXLfM0BtKzlQBcbSM7ycDkDN99Xc5jzpd4fxNQyyFXOmc6owUsrQ==",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "bech32": "=2.0.0",
 | 
					        "bech32": "=2.0.0",
 | 
				
			||||||
        "bip-schnorr": "=0.6.4",
 | 
					        "bip-schnorr": "=0.6.4",
 | 
				
			||||||
@ -15626,9 +15626,9 @@
 | 
				
			|||||||
      "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ=="
 | 
					      "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/node-addon-api": {
 | 
					    "node_modules/node-addon-api": {
 | 
				
			||||||
      "version": "2.0.2",
 | 
					      "version": "5.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
 | 
					      "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/node-fetch": {
 | 
					    "node_modules/node-fetch": {
 | 
				
			||||||
      "version": "2.7.0",
 | 
					      "version": "2.7.0",
 | 
				
			||||||
@ -18038,17 +18038,17 @@
 | 
				
			|||||||
      "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
 | 
					      "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/secp256k1": {
 | 
					    "node_modules/secp256k1": {
 | 
				
			||||||
      "version": "4.0.3",
 | 
					      "version": "4.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz",
 | 
				
			||||||
      "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
 | 
					      "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==",
 | 
				
			||||||
      "hasInstallScript": true,
 | 
					      "hasInstallScript": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "elliptic": "^6.5.4",
 | 
					        "elliptic": "^6.5.7",
 | 
				
			||||||
        "node-addon-api": "^2.0.0",
 | 
					        "node-addon-api": "^5.0.0",
 | 
				
			||||||
        "node-gyp-build": "^4.2.0"
 | 
					        "node-gyp-build": "^4.2.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=10.0.0"
 | 
					        "node": ">=18.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/secure-json-parse": {
 | 
					    "node_modules/secure-json-parse": {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					-- AlterTable
 | 
				
			||||||
 | 
					ALTER TABLE "users" ADD COLUMN     "autoWithdrawMaxFeeTotal" INTEGER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- set max total fee for users with autowithdrawals enabled to not interfere with them.
 | 
				
			||||||
 | 
					-- we set it to 0 instead of 1 because that preserves old behavior.
 | 
				
			||||||
 | 
					UPDATE "users"
 | 
				
			||||||
 | 
					SET "autoWithdrawMaxFeeTotal" = 0
 | 
				
			||||||
 | 
					WHERE "autoWithdrawMaxFeePercent" IS NOT NULL;
 | 
				
			||||||
@ -118,6 +118,7 @@ model User {
 | 
				
			|||||||
  lnAddr                    String?
 | 
					  lnAddr                    String?
 | 
				
			||||||
  autoWithdrawMaxFeePercent Float?
 | 
					  autoWithdrawMaxFeePercent Float?
 | 
				
			||||||
  autoWithdrawThreshold     Int?
 | 
					  autoWithdrawThreshold     Int?
 | 
				
			||||||
 | 
					  autoWithdrawMaxFeeTotal   Int?
 | 
				
			||||||
  muters                    Mute[]               @relation("muter")
 | 
					  muters                    Mute[]               @relation("muter")
 | 
				
			||||||
  muteds                    Mute[]               @relation("muted")
 | 
					  muteds                    Mute[]               @relation("muted")
 | 
				
			||||||
  ArcOut                    Arc[]                @relation("fromUser")
 | 
					  ArcOut                    Arc[]                @relation("fromUser")
 | 
				
			||||||
 | 
				
			|||||||
@ -201,6 +201,7 @@ function useConfig (wallet) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        // these are stored on the server
 | 
					        // these are stored on the server
 | 
				
			||||||
        delete newClientConfig.autoWithdrawMaxFeePercent
 | 
					        delete newClientConfig.autoWithdrawMaxFeePercent
 | 
				
			||||||
 | 
					        delete newClientConfig.autoWithdrawThreshold
 | 
				
			||||||
        delete newClientConfig.autoWithdrawMaxFeeTotal
 | 
					        delete newClientConfig.autoWithdrawMaxFeeTotal
 | 
				
			||||||
      } catch {
 | 
					      } catch {
 | 
				
			||||||
        valid = false
 | 
					        valid = false
 | 
				
			||||||
@ -296,6 +297,7 @@ function useServerConfig (wallet) {
 | 
				
			|||||||
  const saveConfig = useCallback(async ({
 | 
					  const saveConfig = useCallback(async ({
 | 
				
			||||||
    autoWithdrawThreshold,
 | 
					    autoWithdrawThreshold,
 | 
				
			||||||
    autoWithdrawMaxFeePercent,
 | 
					    autoWithdrawMaxFeePercent,
 | 
				
			||||||
 | 
					    autoWithdrawMaxFeeTotal,
 | 
				
			||||||
    priority,
 | 
					    priority,
 | 
				
			||||||
    enabled,
 | 
					    enabled,
 | 
				
			||||||
    ...config
 | 
					    ...config
 | 
				
			||||||
@ -310,6 +312,7 @@ function useServerConfig (wallet) {
 | 
				
			|||||||
          settings: {
 | 
					          settings: {
 | 
				
			||||||
            autoWithdrawThreshold: Number(autoWithdrawThreshold),
 | 
					            autoWithdrawThreshold: Number(autoWithdrawThreshold),
 | 
				
			||||||
            autoWithdrawMaxFeePercent: Number(autoWithdrawMaxFeePercent),
 | 
					            autoWithdrawMaxFeePercent: Number(autoWithdrawMaxFeePercent),
 | 
				
			||||||
 | 
					            autoWithdrawMaxFeeTotal: Number(autoWithdrawMaxFeeTotal),
 | 
				
			||||||
            priority,
 | 
					            priority,
 | 
				
			||||||
            enabled
 | 
					            enabled
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,27 +1,24 @@
 | 
				
			|||||||
For testing LNbits, you need to create a LNbits account first via the web interface.
 | 
					LNbits' database is seeded with a superuser (see https://docs.lnbits.org/guide/admin_ui.html).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By default, you can access it at `localhost:5001` (see `LNBITS_WEB_PORT` in .env.development).
 | 
					The following credentials were used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
After you created a wallet, you should find the invoice and admin key under `Node URL, API keys and API docs`.
 | 
					- username: `stackernews`
 | 
				
			||||||
 | 
					- password: `stackernews`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!IMPORTANT]
 | 
					To get access to the superuser, you need to visit the admin UI:
 | 
				
			||||||
>
 | 
					
 | 
				
			||||||
> Since your browser is running on your host machine but the server is running inside a docker container, the server will not be able to reach LNbits with `localhost:5001` to create invoices. This makes it hard to test send+receive at the same time.
 | 
					http://localhost:5001/wallet?usr=e46288268b67457399a5fca81809573e
 | 
				
			||||||
>
 | 
					
 | 
				
			||||||
> For now, you need to patch the `_createInvoice` function in wallets/lnbits/server.js to always use `lnbits:5000` as the URL:
 | 
					After that, the cookies will be set to access this wallet:
 | 
				
			||||||
>
 | 
					
 | 
				
			||||||
> ```diff
 | 
					http://localhost:5001/wallet?&wal=15ffe06c74cc4082a91f528d016d9028
 | 
				
			||||||
> diff --git a/wallets/lnbits/server.js b/wallets/lnbits/server.js
 | 
					
 | 
				
			||||||
> index 39949775..e3605c45 100644
 | 
					Or simply copy the keys from here:
 | 
				
			||||||
> --- a/wallets/lnbits/server.js
 | 
					
 | 
				
			||||||
> +++ b/wallets/lnbits/server.js
 | 
					* admin key: `640cc7b031eb427c891eeaa4d9c34180`
 | 
				
			||||||
> @@ -11,6 +11,7 @@ async function _createInvoice ({ url, invoiceKey, amount, expiry }, { me }) {
 | 
					
 | 
				
			||||||
>    const memo = me.hideInvoiceDesc ? undefined : 'autowithdraw to LNbits from SN'
 | 
					* invoice key: `5deed7cd634e4306bb5e696f4a03cdac`
 | 
				
			||||||
>    const body = JSON.stringify({ amount, unit: 'sat', expiry, memo, out: false })
 | 
					
 | 
				
			||||||
>
 | 
					( These keys can be found under `Node URL, API keys and API docs`. )
 | 
				
			||||||
> +  url = 'http://lnbits:5000'
 | 
					
 | 
				
			||||||
>    const res = await fetch(url + path, { method: 'POST', headers, body })
 | 
					To use the same URL to connect to LNbits in the browser and server during local development, `localhost:<port>` is mapped to `lnbits:5000` on the server.
 | 
				
			||||||
>    if (!res.ok) {
 | 
					 | 
				
			||||||
>      const errBody = await res.json()
 | 
					 | 
				
			||||||
> ```
 | 
					 | 
				
			||||||
>
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -28,9 +28,14 @@ export async function createInvoice (
 | 
				
			|||||||
    out: false
 | 
					    out: false
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const hostname = url.replace(/^https?:\/\//, '')
 | 
					  let hostname = url.replace(/^https?:\/\//, '')
 | 
				
			||||||
  const agent = getAgent({ hostname })
 | 
					  const agent = getAgent({ hostname })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (process.env.NODE_ENV !== 'production' && hostname.startsWith('localhost:')) {
 | 
				
			||||||
 | 
					    // to make it possible to attach LNbits for receives during local dev
 | 
				
			||||||
 | 
					    hostname = 'lnbits:5000'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const res = await fetch(`${agent.protocol}//${hostname}${path}`, {
 | 
					  const res = await fetch(`${agent.protocol}//${hostname}${path}`, {
 | 
				
			||||||
    method: 'POST',
 | 
					    method: 'POST',
 | 
				
			||||||
    headers,
 | 
					    headers,
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,10 @@ import { createInvoice } from 'wallets/server'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export async function autoWithdraw ({ data: { id }, models, lnd }) {
 | 
					export async function autoWithdraw ({ data: { id }, models, lnd }) {
 | 
				
			||||||
  const user = await models.user.findUnique({ where: { id } })
 | 
					  const user = await models.user.findUnique({ where: { id } })
 | 
				
			||||||
  if (user.autoWithdrawThreshold === null || user.autoWithdrawMaxFeePercent === null) return
 | 
					  if (
 | 
				
			||||||
 | 
					    user.autoWithdrawThreshold === null ||
 | 
				
			||||||
 | 
					    user.autoWithdrawMaxFeePercent === null ||
 | 
				
			||||||
 | 
					    user.autoWithdrawMaxFeeTotal === null) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const threshold = satsToMsats(user.autoWithdrawThreshold)
 | 
					  const threshold = satsToMsats(user.autoWithdrawThreshold)
 | 
				
			||||||
  const excess = Number(user.msats - threshold)
 | 
					  const excess = Number(user.msats - threshold)
 | 
				
			||||||
@ -13,7 +16,10 @@ export async function autoWithdraw ({ data: { id }, models, lnd }) {
 | 
				
			|||||||
  if (excess < Number(threshold) * 0.1) return
 | 
					  if (excess < Number(threshold) * 0.1) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // floor fee to nearest sat but still denominated in msats
 | 
					  // floor fee to nearest sat but still denominated in msats
 | 
				
			||||||
  const maxFeeMsats = msatsSatsFloor(Math.ceil(excess * (user.autoWithdrawMaxFeePercent / 100.0)))
 | 
					  const maxFeeMsats = msatsSatsFloor(Math.max(
 | 
				
			||||||
 | 
					    Math.ceil(excess * (user.autoWithdrawMaxFeePercent / 100.0)),
 | 
				
			||||||
 | 
					    Number(satsToMsats(user.autoWithdrawMaxFeeTotal))
 | 
				
			||||||
 | 
					  ))
 | 
				
			||||||
  // msats will be floored by createInvoice if it needs to be
 | 
					  // msats will be floored by createInvoice if it needs to be
 | 
				
			||||||
  const msats = BigInt(excess) - maxFeeMsats
 | 
					  const msats = BigInt(excess) - maxFeeMsats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user