stacker.news/worker/autowithdraw.js
Keyan cc289089cf
not-custodial zap beta (#1178)
* not-custodial zap scaffolding

* invoice forward state machine

* small refinements to state machine

* make wrap invoice work

* get state machine working end to end

* untested logic layout for paidAction invoice wraps

* perform pessimisitic actions before outgoing payment

* working end to end

* remove unneeded params from wallets/server/createInvoice

* fix cltv relative/absolute confusion + cancelling forwards

* small refinements

* add p2p wrap info to paidAction docs

* fallback to SN invoice when wrap fails

* fix paidAction retry description

* consistent naming scheme for state machine

* refinements

* have sn pay bounded outbound fee

* remove debug logging

* reenable lnc permissions checks

* don't p2p zap on item forward splits

* make createInvoice params json encodeable

* direct -> p2p badge on notifications

* allow no tls in dev for core lightning

* fix autowithdraw to create invoice with msats

* fix autowithdraw msats/sats inconsitency

* label p2p zaps properly in satistics

* add fees to autowithdrawal notifications

* add RETRYING as terminal paid action state

* Update api/paidAction/README.md

Co-authored-by: ekzyis <ek@stacker.news>

* Update api/paidAction/README.md

Co-authored-by: ekzyis <ek@stacker.news>

* Update api/lnd/index.js

Co-authored-by: ekzyis <ek@stacker.news>

* ek suggestions

* add bugetable to nwc card

* get paranoid with numbers

* better finalize retries and better max timeout height

* refine forward failure transitions

* more accurate satistics p2p status

* make sure paidaction cancel in state machine only

* dont drop bolt11s unless status is not null

* only allow PENDING_HELD to transition to FORWARDING

* add mermaid state machine diagrams to paid action doc

* fix cancel transition name

* cleanup readme

* move forwarding outside of transition

* refine testServerConnect and make sure ensureB64 transforms

* remove unused params from testServerConnect

---------

Co-authored-by: ekzyis <ek@stacker.news>
Co-authored-by: k00b <k00b@stacker.news>
2024-08-13 09:48:30 -05:00

47 lines
1.6 KiB
JavaScript

import { msatsToSats, satsToMsats } from '@/lib/format'
import { createWithdrawal } from '@/api/resolvers/wallet'
import { createInvoice } from 'wallets/server'
export async function autoWithdraw ({ data: { id }, models, lnd }) {
const user = await models.user.findUnique({ where: { id } })
if (user.autoWithdrawThreshold === null || user.autoWithdrawMaxFeePercent === null) return
const threshold = satsToMsats(user.autoWithdrawThreshold)
const excess = Number(user.msats - threshold)
// excess must be greater than 10% of threshold
if (excess < Number(threshold) * 0.1) return
const maxFeeMsats = Math.ceil(excess * (user.autoWithdrawMaxFeePercent / 100.0))
const msats = excess - maxFeeMsats
// must be >= 1 sat
if (msats < 1000) return
// maxFee is expected to be in sats, ie "msatsFeePaying" is always divisible by 1000
const maxFee = msatsToSats(maxFeeMsats)
// check that
// 1. the user doesn't have an autowithdraw pending
// 2. we have not already attempted to autowithdraw this fee recently
const [pendingOrFailed] = await models.$queryRaw`
SELECT EXISTS(
SELECT *
FROM "Withdrawl"
WHERE "userId" = ${id} AND "autoWithdraw"
AND (status IS NULL
OR (
status <> 'CONFIRMED' AND
now() < created_at + interval '1 hour' AND
"msatsFeePaying" >= ${satsToMsats(maxFee)}
))
)`
if (pendingOrFailed.exists) return
const { invoice, wallet } = await createInvoice(id, { msats, description: 'SN: autowithdrawal', expiry: 360 }, { models })
return await createWithdrawal(null,
{ invoice, maxFee },
{ me: { id }, models, lnd, walletId: wallet.id })
}