mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 16:31:04 +00:00
Add nip57
This commit is contained in:
parent
70c94f9aa9
commit
d5c4fcd227
@ -95,7 +95,6 @@ export type Handle = {
|
||||
}
|
||||
|
||||
export type Zapper = {
|
||||
pubkey: string
|
||||
lnurl: string
|
||||
callback: string
|
||||
minSendable: number
|
||||
@ -117,7 +116,7 @@ export type Person = {
|
||||
handle_updated_at?: number
|
||||
handle: Handle
|
||||
zapper_updated_at?: number
|
||||
zapper: Handle
|
||||
zapper: Zapper
|
||||
}
|
||||
|
||||
export type Channel = {
|
||||
|
@ -2,6 +2,7 @@ import "./nip02"
|
||||
import "./nip05"
|
||||
import "./nip24"
|
||||
import "./nip28"
|
||||
import "./nip57"
|
||||
import "./nip65"
|
||||
import "./alerts"
|
||||
|
||||
|
56
src/engine2/projections/nip57.ts
Normal file
56
src/engine2/projections/nip57.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import {Fetch, tryFunc} from "hurdak"
|
||||
import {tryJson, hexToBech32, bech32ToHex} from "src/util/misc"
|
||||
import {people} from "src/engine2/state"
|
||||
import {dufflepud} from "src/engine2/queries"
|
||||
import {projections, updateKey} from "src/engine2/projections/core"
|
||||
|
||||
projections.addHandler(0, e => {
|
||||
tryJson(async () => {
|
||||
const {
|
||||
kind0: {lud16, lud06},
|
||||
} = JSON.parse(e.content)
|
||||
const address = (lud16 || lud06 || "").toLowerCase()
|
||||
|
||||
if (!address) {
|
||||
return
|
||||
}
|
||||
|
||||
const lnurl = getLnUrl(address)
|
||||
|
||||
if (!lnurl) {
|
||||
return
|
||||
}
|
||||
|
||||
const result = await tryFunc(() => Fetch.postJson(dufflepud("zapper/info"), {lnurl}))
|
||||
|
||||
if (!result?.allowsNostr || !result?.nostrPubkey) {
|
||||
return
|
||||
}
|
||||
|
||||
updateKey(people.key(e.pubkey), e.created_at, {
|
||||
zapper: {
|
||||
lnurl: hexToBech32("lnurl", lnurl),
|
||||
callback: result.callback,
|
||||
minSendable: result.minSendable,
|
||||
maxSendable: result.maxSendable,
|
||||
nostrPubkey: result.nostrPubkey,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function getLnUrl(address: string): string {
|
||||
// Try to parse it as a lud06 LNURL
|
||||
if (address.startsWith("lnurl1")) {
|
||||
return tryFunc(() => bech32ToHex(address)) as string
|
||||
}
|
||||
|
||||
// Try to parse it as a lud16 address
|
||||
if (address.includes("@")) {
|
||||
const [name, domain] = address.split("@")
|
||||
|
||||
if (domain && name) {
|
||||
return `https://${domain}/.well-known/lnurlp/${name}`
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
export * from "./session"
|
||||
export * from "./settings"
|
||||
export * from "./nip02"
|
||||
export * from "./nip05"
|
||||
export * from "./nip57"
|
||||
export * from "./nip65"
|
||||
export * from "./alerts"
|
||||
export * from "./channels"
|
||||
|
88
src/engine2/queries/nip57.ts
Normal file
88
src/engine2/queries/nip57.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {Fetch} from "hurdak"
|
||||
import {tryJson} from "src/util/misc"
|
||||
import {invoiceAmount} from "src/util/lightning"
|
||||
import {warn} from "src/util/logger"
|
||||
import {Tags} from "src/util/nostr"
|
||||
import type {Event, ZapEvent} from "src/engine2/model"
|
||||
import {people} from "src/engine2/state"
|
||||
|
||||
export function processZaps(zaps: Event[], pubkey: string) {
|
||||
const {zapper} = people.key(pubkey).get() || {}
|
||||
|
||||
if (!zapper) {
|
||||
return []
|
||||
}
|
||||
|
||||
return zaps
|
||||
.map((zap: Event) => {
|
||||
const zapMeta = Tags.from(zap).asMeta() as {
|
||||
bolt11: string
|
||||
description: string
|
||||
}
|
||||
|
||||
return tryJson(() => ({
|
||||
...zap,
|
||||
invoiceAmount: invoiceAmount(zapMeta.bolt11),
|
||||
request: JSON.parse(zapMeta.description),
|
||||
})) as ZapEvent
|
||||
})
|
||||
.filter((zap: ZapEvent) => {
|
||||
if (!zap) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Don't count zaps that the user sent himself
|
||||
if (zap.request.pubkey === pubkey) {
|
||||
return false
|
||||
}
|
||||
|
||||
const {invoiceAmount, request} = zap
|
||||
const reqMeta = Tags.from(request).asMeta() as {
|
||||
amount?: string
|
||||
lnurl?: string
|
||||
}
|
||||
|
||||
// Verify that the zapper actually sent the requested amount (if it was supplied)
|
||||
if (reqMeta.amount && parseInt(reqMeta.amount) !== invoiceAmount) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the sending client provided an lnurl tag, verify that too
|
||||
if (reqMeta.lnurl && reqMeta.lnurl !== zapper.lnurl) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify that the zap note actually came from the recipient's zapper
|
||||
if (zapper.nostrPubkey !== zap.pubkey) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
export async function fetchInvoice(zapper, event, amount) {
|
||||
const {callback, lnurl} = zapper
|
||||
const s = encodeURI(JSON.stringify(event))
|
||||
const res = await Fetch.fetchJson(`${callback}?amount=${amount}&nostr=${s}&lnurl=${lnurl}`)
|
||||
|
||||
if (!res.pr) {
|
||||
warn(JSON.stringify(res))
|
||||
}
|
||||
|
||||
return res?.pr
|
||||
}
|
||||
|
||||
export async function collectInvoice(invoice) {
|
||||
const {webln} = window as {webln?: any}
|
||||
|
||||
if (webln) {
|
||||
await webln.enable()
|
||||
|
||||
try {
|
||||
webln.sendPayment(invoice)
|
||||
} catch (e) {
|
||||
warn(e)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user