Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LNC Receiver (w/ microservice) #1763

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 7 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,10 @@ CPU_SHARES_IMPORTANT=1024
CPU_SHARES_MODERATE=512
CPU_SHARES_LOW=256

NEXT_TELEMETRY_DISABLED=1
NEXT_TELEMETRY_DISABLED=1

# LNCD
LNCD_URL=https://lncd:7167
# xxd -p -c0 docker/lncd/certs/cert.pem
LNCD_CERT=2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494944717a434341704f6741774942416749554a6872356137726671657867397737665a375930324e37686a5573774451594a4b6f5a496876634e4151454c0a425141775a54454c4d416b474131554542684d43534655784554415042674e564241674d43454a315a4746775a584e304d5245774477594456515148444168430a645752686347567a6444454e4d4173474131554543677745544535445244454e4d417347413155454377774554453544524445534d424147413155454177774a0a6247396a5957786f62334e304d423458445449304d54497a4d5449774d6a63314d566f58445449314d54497a4d5449774d6a63314d566f775a54454c4d416b470a4131554542684d43534655784554415042674e564241674d43454a315a4746775a584e304d524577447759445651514844416843645752686347567a6444454e0a4d4173474131554543677745544535445244454e4d417347413155454377774554453544524445534d424147413155454177774a6247396a5957786f62334e300a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b4341514541766c5763515935684a637a527a777877523741570a4c316d7839673143456c3631685255503443624555687a55592b70334334676b786a4f464c61666e3030445a6e56393537677632704d654e624449762f4935700a43753634715136362b3551664e5034485435475a737669317262346f56547775594932684a524f4272314c7a5875706d31446d43786d565944304761384a375a0a5239634f4a474471366f70316e6d643871764e6a32786a7741374e714e6c39642f69384d453236646e484a7a334e71704c61344b2f4550727a754478722b546a0a4e3658374a464157476a503833726e73714a7a73774f364b36664f766d31647550494961504e72316334675678556e773774496c4b6f44664a554651786854620a4c787a48466e4d6b454b4157485548346d4446745162316f4d435a4d704d6853413137483262506a7655784e66575342504f7635616c764e3871582f6e7641760a66774944415141426f314d775554416442674e56485134454667515553784d72386c36574a3049337469536b5755362f4948516b486b5177487759445652306a0a42426777466f415553784d72386c36574a3049337469536b5755362f4948516b486b517744775944565230544151482f42415577417745422f7a414e42676b710a686b6947397730424151734641414f434151454168445238766b75364a706c314a7a51744a62634e4a446c487056365368767053467a725231657858424b66330a324f414167535535577062354c75456b5a70765a4e684c4f6147576c6c6b676d5342712b796134475a3869584f6f4f4d4e31507650556e324e46486b525476650a3746642f476356684444754c51326547664a74532f673465626d6949505362645631627157536c4c6151487367314a30575043474a454b774e7032364e776a470a59436e315378594b496d3546316c504442394847735276634a5972476a785a446f68764e2f536d335a52416a792b637931567247557a3176316a6e73386b596b0a78644144754a4a6e30784966324734385361546f796e2f494335444b4f36567761716f315a4f684546336e3836695149396937306547773873626a41783843620a6152776165716b7362386874303962566e334c484d6e4c624542483433492b74645456755a57377436413d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a
LNCD_AUTH_TOKEN="satoshi"
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,7 @@ scripts/nwc-keys.json
docker/lnbits/data

# lndk
!docker/lndk/tls-*.pem
!docker/lndk/tls-*.pem

# lncd
!docker/lncd/certs/*.pem
24 changes: 15 additions & 9 deletions api/resolvers/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,19 @@ function injectResolvers (resolvers) {
})
}

const validData = await validateWallet(walletDef,
{ ...data, ...settings, vaultEntries: vaultEntries ?? existingVaultEntries },
{ serverSide: true })
if (validData) {
data && Object.keys(validData).filter(key => key in data).forEach(key => { data[key] = validData[key] })
settings && Object.keys(validData).filter(key => key in settings).forEach(key => { settings[key] = validData[key] })
const validate = async ({ data, settings, skipGenerated = false }) => {
const validData = await validateWallet(walletDef,
{ ...data, ...settings, vaultEntries: vaultEntries ?? existingVaultEntries },
{ serverSide: true, skipGenerated })
if (validData) {
data && Object.keys(validData).filter(key => key in data).forEach(key => { data[key] = validData[key] })
settings && Object.keys(validData).filter(key => key in settings).forEach(key => { settings[key] = validData[key] })
}
}

const needsTest = walletDef.testCreateInvoice && validateLightning && canReceive({ def: walletDef, config: data })
await validate({ data, settings, skipGenerated: needsTest })

// wallet in shape of db row
const wallet = {
field: walletDef.walletField,
Expand All @@ -67,7 +72,7 @@ function injectResolvers (resolvers) {
wallet,
walletDef,
testCreateInvoice:
walletDef.testCreateInvoice && validateLightning && canReceive({ def: walletDef, config: data })
needsTest
? (data) => withTimeout(
walletDef.testCreateInvoice(data, {
logger,
Expand All @@ -79,7 +84,7 @@ function injectResolvers (resolvers) {
settings,
data,
vaultEntries
}, { logger, me, models })
}, { logger, me, models, validate })
}
}
console.groupEnd()
Expand Down Expand Up @@ -785,7 +790,7 @@ export const walletLogger = ({ wallet, models }) => {
}

async function upsertWallet (
{ wallet, walletDef, testCreateInvoice }, { settings, data, vaultEntries }, { logger, me, models }) {
{ wallet, walletDef, testCreateInvoice }, { settings, data, vaultEntries }, { logger, me, models, validate }) {
if (!me) {
throw new GqlAuthenticationError()
}
Expand All @@ -794,6 +799,7 @@ async function upsertWallet (
if (testCreateInvoice) {
try {
await testCreateInvoice(data)
await validate({ data, settings, skipGenerated: false })
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file are not related to this pr specifically.
See #1769

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means this PR is based on #1769?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

} catch (err) {
const message = 'failed to create test invoice: ' + (err.message || err.toString?.())
logger.error(message)
Expand Down
19 changes: 19 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,25 @@ services:
CLI: "litcli"
CLI_ARGS: "-n regtest --rpcserver localhost:8444"
cpu_shares: "${CPU_SHARES_MODERATE}"
lncd:
container_name: lncd
build:
context: ./docker/lncd
profiles:
- wallets
restart: unless-stopped
environment:
- LNCD_DEBUG=true
- LNCD_DEV_UNSAFE_LOG=true
- LNCD_AUTH_TOKEN=${LNCD_AUTH_TOKEN}
healthcheck:
<<: *healthcheck
test: ["CMD", "curl", "-k", "-f", "-H", "Authorization: Bearer ${LNCD_AUTH_TOKEN}", "https://localhost:7167/health"]
depends_on:
litd:
condition: service_healthy
restart: true
cpu_shares: "${CPU_SHARES_MODERATE}"
cln:
build:
context: ./docker/cln
Expand Down
23 changes: 23 additions & 0 deletions docker/lncd/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM debian:bookworm-slim
RUN useradd -u 1000 -m lncd

ARG VERSION=0.3.2
ARG REPO=stackernews/lncd
ARG DOWNLOAD_URL=https://github.com/$REPO/releases/download/$VERSION/lncd

RUN mkdir -p /home/lncd
ADD certs /home/lncd/certs

ENV LNCD_TLS_CERT_PATH=/home/lncd/certs/cert.pem
ENV LNCD_TLS_KEY_PATH=/home/lncd/certs/key.pem

RUN chown 1000:1000 -Rvf /home/lncd/ &&\
apt-get update && apt-get install -y curl &&\
apt-get clean && rm -rf /var/lib/apt/lists/*

USER lncd
RUN curl --proto '=https' --tlsv1.2 -LsSf $DOWNLOAD_URL -o /home/lncd/lncd && chmod +x /home/lncd/lncd
WORKDIR /home/lncd
EXPOSE 7167

CMD ["./lncd"]
22 changes: 22 additions & 0 deletions docker/lncd/certs/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDqzCCApOgAwIBAgIUJhr5a7rfqexg9w7fZ7Y02N7hjUswDQYJKoZIhvcNAQEL
BQAwZTELMAkGA1UEBhMCSFUxETAPBgNVBAgMCEJ1ZGFwZXN0MREwDwYDVQQHDAhC
dWRhcGVzdDENMAsGA1UECgwETE5DRDENMAsGA1UECwwETE5DRDESMBAGA1UEAwwJ
bG9jYWxob3N0MB4XDTI0MTIzMTIwMjc1MVoXDTI1MTIzMTIwMjc1MVowZTELMAkG
A1UEBhMCSFUxETAPBgNVBAgMCEJ1ZGFwZXN0MREwDwYDVQQHDAhCdWRhcGVzdDEN
MAsGA1UECgwETE5DRDENMAsGA1UECwwETE5DRDESMBAGA1UEAwwJbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvlWcQY5hJczRzwxwR7AW
L1mx9g1CEl61hRUP4CbEUhzUY+p3C4gkxjOFLafn00DZnV957gv2pMeNbDIv/I5p
Cu64qQ66+5QfNP4HT5GZsvi1rb4oVTwuYI2hJROBr1LzXupm1DmCxmVYD0Ga8J7Z
R9cOJGDq6op1nmd8qvNj2xjwA7NqNl9d/i8ME26dnHJz3NqpLa4K/EPrzuDxr+Tj
N6X7JFAWGjP83rnsqJzswO6K6fOvm1duPIIaPNr1c4gVxUnw7tIlKoDfJUFQxhTb
LxzHFnMkEKAWHUH4mDFtQb1oMCZMpMhSA17H2bPjvUxNfWSBPOv5alvN8qX/nvAv
fwIDAQABo1MwUTAdBgNVHQ4EFgQUSxMr8l6WJ0I3tiSkWU6/IHQkHkQwHwYDVR0j
BBgwFoAUSxMr8l6WJ0I3tiSkWU6/IHQkHkQwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEAhDR8vku6Jpl1JzQtJbcNJDlHpV6ShvpSFzrR1exXBKf3
2OAAgSU5Wpb5LuEkZpvZNhLOaGWllkgmSBq+ya4GZ8iXOoOMN1PvPUn2NFHkRTve
7Fd/GcVhDDuLQ2eGfJtS/g4ebmiIPSbdV1bqWSlLaQHsg1J0WPCGJEKwNp26NwjG
YCn1SxYKIm5F1lPDB9HGsRvcJYrGjxZDohvN/Sm3ZRAjy+cy1VrGUz1v1jns8kYk
xdADuJJn0xIf2G48SaToyn/IC5DKO6Vwaqo1ZOhEF3n86iQI9i70eGw8sbjAx8Cb
aRwaeqksb8ht09bVn3LHMnLbEBH43I+tdTVuZW7t6A==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions docker/lncd/certs/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+VZxBjmElzNHP
DHBHsBYvWbH2DUISXrWFFQ/gJsRSHNRj6ncLiCTGM4Utp+fTQNmdX3nuC/akx41s
Mi/8jmkK7ripDrr7lB80/gdPkZmy+LWtvihVPC5gjaElE4GvUvNe6mbUOYLGZVgP
QZrwntlH1w4kYOrqinWeZ3yq82PbGPADs2o2X13+LwwTbp2ccnPc2qktrgr8Q+vO
4PGv5OM3pfskUBYaM/zeueyonOzA7orp86+bV248gho82vVziBXFSfDu0iUqgN8l
QVDGFNsvHMcWcyQQoBYdQfiYMW1BvWgwJkykyFIDXsfZs+O9TE19ZIE86/lqW83y
pf+e8C9/AgMBAAECggEAOPjlQdY9jBQIBWLixQKXUWsW0uDbEyaYTRKl4uGXyEBq
7tGC+sewwkcvqR/mS5zQxsOKes/H70DwOx+2r3FtTeFxEuGe5KlMwg773zxk9mZt
82jFJ+ZQt4QNZUy2d+VrhdDCIOpqE7rIJiDsIPRbc56S1B7SkowJcvXlIkKidDU4
SkOucahVUwpMz7IaTtfQNKJzCc9Ut5Q4cVizZbtNSVjhzvicLenjDTgqRoDxGa80
ZDd8Jtb/BMXJVTGs4W+I7Fu+KRCFc3FW/i3kHGyr7cqjLyzV5nIJnCJ9rXNukDYf
1TSdPfQyXc6wuhq3dK/tjfbuux82jipdBrKg4yGbiQKBgQD91QPwDAkWjNnteJSm
up21/j48vrdBsAdHJeK78KL4Mm6vMuqsp7kVm6sNGofRzv9KV6RWPw1zA5AVhJbF
ZZVvRRI28xpPWbh392ZJzRuHpHDrmurk/+OAEwi3cnolRfs5YHg87uZEqubuWWdK
4O8weu2TLT10WmW0mqtOaqc/pQKBgQC/9cMbqqWICOzTnsR78+dPoZTEfadEMJ/F
HvMA4FRy3IYxwPMNucH/7MTwaCFnR2GiN+2MWvS6aBWNTORBwwKHBp9+GYqSSGNQ
EvK8MUYo2XI6snWBdapayoaXNlO5KCiLtY+s46FYtW9Y3vUabZP8Khc9K0hyl3+r
KZq6hmbJUwKBgQC0SRvm32WFEr2moUJTubBSlyX1VzAqA7Dno80K17uotYlP/sYX
o3keE9bGE9Xr+y3vy5f5egc/bYRlBCtiQOiGg3SQetJxEbSn4JxSRtAK440gioPT
6rvXN621PiXrW204L4C3Jqd+ljQ3jmCDGohI0sbzBerkPWCHimOp6q6n0QKBgDnW
MH0Lg2hjWAfC1GyMZmtFwe8Z9OXEyL65vnnLHWamLwCapCDEkUEs84GDvlzB0xbv
RvF9DjOD3MqAGl3+BartQezagTfl+5ZKvzwYlI0GRzaMQn9JFpTYZIj2427sPJsr
jyiGRTzXHb9nHe5iia32eJ4DhoaQQvUtSeNdT2blAoGBANjREQBuA46nllFondmI
G5/XGOGYJAT7BiJ/hqq0XK9k+EHVhkJoLwC6DxomNAdySo11BSrSgKS83QXMLpam
8kznu/OOtG2+V4uCdR4X2/cQRNLDXUAr107QbAuQoWy05mfXy6HEchLv0Cwtz9s7
jdMAG8IYu7kUvokgc+/Uc4sh
-----END PRIVATE KEY-----
6 changes: 6 additions & 0 deletions fragments/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ export const WALLET_FIELDS = gql`
apiKeyRecv
currencyRecv
}
... on WalletLnc {
pairingPhraseRecv
localKeyRecv
remoteKeyRecv
serverHostRecv
}
}
}
`
Expand Down
22 changes: 22 additions & 0 deletions prisma/migrations/20241223232401_lnc_recv/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- CreateTable
CREATE TABLE "WalletLNC" (
"id" SERIAL NOT NULL,
"walletId" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"pairingPhraseRecv" TEXT NOT NULL,
"localKeyRecv" TEXT,
"remoteKeyRecv" TEXT,
"serverHostRecv" TEXT,
CONSTRAINT "WalletLNC_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "WalletLNC_walletId_key" ON "WalletLNC"("walletId");

-- AddForeignKey
ALTER TABLE "WalletLNC" ADD CONSTRAINT "WalletLNC_walletId_fkey" FOREIGN KEY ("walletId") REFERENCES "Wallet"("id") ON DELETE CASCADE ON UPDATE CASCADE;

CREATE TRIGGER wallet_lnc_as_jsonb
AFTER INSERT OR UPDATE ON "WalletLNC"
FOR EACH ROW EXECUTE PROCEDURE wallet_wallet_type_as_jsonb();
13 changes: 13 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ model Wallet {
walletNWC WalletNWC?
walletPhoenixd WalletPhoenixd?
walletBlink WalletBlink?
walletLNC WalletLNC?

vaultEntries VaultEntry[] @relation("VaultEntries")
withdrawals Withdrawl[]
Expand Down Expand Up @@ -319,6 +320,18 @@ model WalletBlink {
currencyRecv String?
}

model WalletLNC {
id Int @id @default(autoincrement())
walletId Int @unique
wallet Wallet @relation(fields: [walletId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
pairingPhraseRecv String
localKeyRecv String?
remoteKeyRecv String?
serverHostRecv String?
}

model WalletPhoenixd {
id Int @id @default(autoincrement())
walletId Int @unique
Expand Down
2 changes: 1 addition & 1 deletion wallets/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function useWalletConfigurator (wallet) {
throw err
}
} else if (canReceive({ def: wallet.def, config: serverConfig })) {
const transformedConfig = await validateWallet(wallet.def, serverConfig)
const transformedConfig = await validateWallet(wallet.def, serverConfig, { skipGenerated: true })
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file are not related to this pr specifically.
See #1769

if (transformedConfig) {
serverConfig = Object.assign(serverConfig, transformedConfig)
}
Expand Down
17 changes: 15 additions & 2 deletions wallets/lnc/ATTACH.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,33 @@ For testing litd as an attached receiving wallet, you'll need a pairing phrase:
This can be done one of two ways:

# cli

We only need permissions for the uri `/lnrpc.Lightning/SendPaymentSync`
Create an account

```bash
$ sndev cli litd accounts create --balance <budget>
```

Grab the `account.id` from the output and use it here:

### send attachment
The sender attachment only needs permissions for the uri `/lnrpc.Lightning/SendPaymentSync`

```bash
$ sndev cli litd sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/SendPaymentSync
```

Grab the `pairing_secret_mnemonic` from the output and that's your pairing phrase.

### receive attachment
The receive attachment only needs permissions for the uri `/lnrpc.Lightning/AddInvoice`


```bash
$ sndev cli litd sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/AddInvoice
```

Grab the `pairing_secret_mnemonic` from the output and that's your pairing phrase.

# gui

To open the gui, run:
Expand Down
76 changes: 58 additions & 18 deletions wallets/lnc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,37 @@ export const name = 'lnc'
export const walletType = 'LNC'
export const walletField = 'walletLNC'

const pairingPhraseSchema = string()
.test((value, context) => {
const words = value ? value.trim().split(/[\s]+/) : []
for (const w of words) {
try {
string().oneOf(bip39Words).validateSync(w)
} catch {
return context.createError({ message: `'${w}' is not a valid pairing phrase word` })
}
}
if (words.length < 2) {
return context.createError({ message: 'needs at least two words' })
}
if (words.length > 10) {
return context.createError({ message: 'max 10 words' })
}
return true
})

export const fields = [
{
name: 'pairingPhrase',
label: 'pairing phrase',
type: 'password',
optional: 'for sending',
help: 'We only need permissions for the uri `/lnrpc.Lightning/SendPaymentSync`\n\nCreate a budgeted account with narrow permissions:\n\n```$ litcli accounts create --balance <budget>```\n\n```$ litcli sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/SendPaymentSync```\n\nGrab the `pairing_secret_mnemonic` from the output and paste it here.',
editable: false,
clientOnly: true,
validate: string()
.test(async (value, context) => {
const words = value ? value.trim().split(/[\s]+/) : []
for (const w of words) {
try {
await string().oneOf(bip39Words).validate(w)
} catch {
return context.createError({ message: `'${w}' is not a valid pairing phrase word` })
}
}
if (words.length < 2) {
return context.createError({ message: 'needs at least two words' })
}
if (words.length > 10) {
return context.createError({ message: 'max 10 words' })
}
return true
})
validate: pairingPhraseSchema,
requiredWithout: 'pairingPhraseRecv'

},
{
name: 'localKey',
Expand All @@ -55,6 +60,41 @@ export const fields = [
clientOnly: true,
generated: true,
validate: string()
},
{
name: 'pairingPhraseRecv',
label: 'pairing phrase',
type: 'password',
optional: 'for receiving',
help: 'We only need permissions for the uri `/lnrpc.Lightning/AddInvoice`\n\nCreate an account with narrow permissions:\n\n```$ litcli accounts create```\n\n```$ litcli sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/AddInvoice```\n\nGrab the `pairing_secret_mnemonic` from the output and paste it here.',
editable: false,
serverOnly: true,
validate: pairingPhraseSchema,
requiredWithout: 'pairingPhrase'
},
{
name: 'localKeyRecv',
type: 'text',
hidden: true,
serverOnly: true,
generated: true,
validate: string()
},
{
name: 'remoteKeyRecv',
type: 'text',
hidden: true,
serverOnly: true,
generated: true,
validate: string()
},
{
name: 'serverHostRecv',
type: 'text',
hidden: true,
serverOnly: true,
generated: true,
validate: string()
}
]

Expand Down
Loading
Loading