Skip to content

Commit

Permalink
zbd
Browse files Browse the repository at this point in the history
  • Loading branch information
riccardobl committed Dec 19, 2024
1 parent 8b4b35c commit 83a9907
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 20 deletions.
1 change: 1 addition & 0 deletions public/wallets/zbd-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/wallets/zbd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 11 additions & 10 deletions wallets/zebedee/client.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { API_URL, PREIMAGE_AWAIT_TIMEOUT_MS } from '@/wallets/zebedee'
import { assertContentTypeJson } from '@/lib/url'
import { withTimeout } from '@/lib/time'
import { callWithTimeout } from '@/lib/time'
import { fetchWithTimeout } from '@/lib/fetch'

export * from '@/wallets/zebedee'

export async function testSendPayment ({ apiKey }, { signal }) {
const wallet = await apiCall('wallet', {}, { apiKey, method: 'GET' })
const wallet = await apiCall('wallet', { apiKey, method: 'GET' }, { signal })
if (!wallet.data) throw new Error('wallet not found')
}

export async function sendPayment (bolt11, { apiKey }, { signal }) {
const res = await apiCall('payments', { invoice: bolt11 }, { apiKey })
const res = await apiCall('payments', { body: { invoice: bolt11 }, apiKey }, { signal })
const { id, preimage } = res?.data
if (preimage) return preimage
// the api might return before the invoice is paid, so we'll wait for the preimage
return await waitForPreimage(id, { apiKey })
return await waitForPreimage(id, { apiKey }, { signal })
}

async function waitForPreimage (id, { apiKey }) {
return await withTimeout(async () => {
async function waitForPreimage (id, { apiKey }, { signal }) {
return await callWithTimeout(async () => {
let preimage
while (true) {
const res = await apiCall('payments/{id}', { id }, { apiKey, method: 'GET' })
const res = await apiCall('payments/{id}', { body: { id }, apiKey, method: 'GET' }, { signal })
preimage = res?.data?.preimage
if (preimage) break
await new Promise(resolve => setTimeout(resolve, 10))
Expand All @@ -31,19 +31,20 @@ async function waitForPreimage (id, { apiKey }) {
}, PREIMAGE_AWAIT_TIMEOUT_MS)
}

export async function apiCall (api, body, { apiKey, method = 'POST' }) {
export async function apiCall (api, { body, apiKey, method = 'POST' }, { signal }) {
const headers = {
apikey: apiKey,
'Content-Type': 'application/json'
}
if (method === 'GET') {
if (method === 'GET' && body) {
for (const [k, v] of Object.entries(body)) {
api = api.replace('{' + k + '}', v)
}
}
const res = await fetchWithTimeout(API_URL + api, {
method,
headers,
signal,
body: method === 'POST' ? JSON.stringify(body) : undefined
})
// https://zbd.dev/api-reference/errors
Expand All @@ -52,7 +53,7 @@ export async function apiCall (api, body, { apiKey, method = 'POST' }) {
try {
assertContentTypeJson(res)
const json = await res.json()
if (json?.error) error = json.error
if (json?.message) error = json.message
} catch (e) {
error = res.statusText || 'error ' + res.status
}
Expand Down
8 changes: 5 additions & 3 deletions wallets/zebedee/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const fields = [
label: 'api key',
type: 'password',
optional: 'for sending',
help: `you can get an API key from [Zebedee Dashboard](${DASHBOARD_URL}).`,
help: `you can get an API key from [Zebedee Dashboard](${DASHBOARD_URL}) from \n\`Project->API->Live\``,
clientOnly: true,
requiredWithout: 'gamerTagId',
validate: string()
Expand All @@ -27,7 +27,7 @@ export const fields = [
label: 'gamer tag or id',
type: 'text',
optional: 'for receiving',
help: `you can find your Gamertag in the [Zebedee Dashboard](${DASHBOARD_URL}) under 'Account' -> 'Gamertag' section, or in the Zebedee app on the Wallet card.\nNote: You can also use your @${ZEBEDEE_LNDOMAIN} Lightning address here.`,
help: `you can find your Gamertag in the [Zebedee Dashboard](${DASHBOARD_URL}) under \n\`Account->Gamertag\`\n section, or in the Zebedee app on the Wallet card.\nNote: You can also use your \`@${ZEBEDEE_LNDOMAIN}\` Lightning address here.`,
serverOnly: true,
requiredWithout: 'apiKey',
validate: string()
Expand All @@ -36,5 +36,7 @@ export const fields = [

export const card = {
title: 'Zebedee',
subtitle: 'use [Zebedee](https://zebedee.io) for payments'
subtitle: 'use [Zebedee](https://zebedee.io) for payments',
image: { src: '/wallets/zbd.svg' }

}
13 changes: 6 additions & 7 deletions wallets/zebedee/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { assertContentTypeJson } from '@/lib/url'

export * from '@/wallets/zebedee'

async function fetchJson (url) {
let res = await fetchWithTimeout(url)
async function fetchJson (url, { signal }) {
let res = await fetchWithTimeout(url, { signal })
assertContentTypeJson(res)
if (!res.ok) {
res.text().catch(() => {})
Expand All @@ -23,13 +23,13 @@ function isGamerTag (value) {
return value.length > 0 && value.length < 30
}

export async function fetchGamerId (value) {
export async function fetchGamerId (value, { signal }) {
if (isGamerTag(value)) {
const [gamerTag, domain] = value.split('@')
if (domain && domain !== ZEBEDEE_LNDOMAIN) throw new Error(`invalid gamer tag: not a @${ZEBEDEE_LNDOMAIN} lightning address`)
const url = GAMER_TAG_LNADDR_BASEURL + gamerTag
try {
const res = await fetchJson(url)
const res = await fetchJson(url, { signal })
const callback = res.callback
if (!callback) throw new Error('cannot fetch gamer id: ' + (res.statusText || 'error ' + res.status))
const gamerId = callback.substring(callback.lastIndexOf('/') + 1)
Expand All @@ -42,16 +42,15 @@ export async function fetchGamerId (value) {
}

export async function testCreateInvoice (credentials, { signal }) {
credentials.gamerTagId = await fetchGamerId(credentials.gamerTagId)
credentials.gamerTagId = await fetchGamerId(credentials.gamerTagId, { signal })
return await createInvoice({ msats: 1000, expiry: 1 }, credentials, { signal })
}

export async function createInvoice ({ msats, description, expiry }, { gamerTagId }, { signal }) {
try {
const url = STATIC_CHARGE_URL + gamerTagId + '?amount=' + msats + '&comment=' + description
const res = await fetchJson(url)
const res = await fetchJson(url, { signal })
if (!res.pr) throw new Error('cannot fetch invoice')
console.log('INVOICE', res.pr)
return res.pr
} catch (e) {
throw new Error(e.message)
Expand Down

0 comments on commit 83a9907

Please sign in to comment.