From 0a1f94b3776f26c8b835f73a10fd7542a30bace6 Mon Sep 17 00:00:00 2001 From: gsovereignty Date: Sat, 3 Aug 2024 17:20:28 +0800 Subject: [PATCH] problem: bitcoin addresses not added to rocket --- src/components/AssociateBitcoinAddress.svelte | 46 ++++++++ src/components/BitcoinAssociations.svelte | 67 +++++++++++ src/components/InputBitcoinAddress.svelte | 32 +++++ src/components/RocketCard.svelte | 21 ++-- src/components/RocketDashboard.svelte | 2 + src/lib/event_helpers/rockets.ts | 111 +++++++++++++++--- src/lib/helpers.ts | 11 +- src/routes/buymerits/+page.svelte | 16 ++- src/routes/sellmerits/+page.svelte | 6 +- .../AssociateBitcoinAddress.svelte | 63 ++++++++++ src/views/rockets/Rockets.svelte | 39 ++++-- 11 files changed, 362 insertions(+), 52 deletions(-) create mode 100644 src/components/AssociateBitcoinAddress.svelte create mode 100644 src/components/BitcoinAssociations.svelte create mode 100644 src/components/InputBitcoinAddress.svelte create mode 100644 src/stateupdaters/AssociateBitcoinAddress.svelte diff --git a/src/components/AssociateBitcoinAddress.svelte b/src/components/AssociateBitcoinAddress.svelte new file mode 100644 index 0000000..3f1eb40 --- /dev/null +++ b/src/components/AssociateBitcoinAddress.svelte @@ -0,0 +1,46 @@ + + + + Associate Bitcoin Address + +
+ You must associate at least one Bitcoin address with your npub before you can pay a Contributor. +
+
+
+
\ No newline at end of file diff --git a/src/components/BitcoinAssociations.svelte b/src/components/BitcoinAssociations.svelte new file mode 100644 index 0000000..30222f5 --- /dev/null +++ b/src/components/BitcoinAssociations.svelte @@ -0,0 +1,67 @@ + + + + + Registered Bitcoin Addresses + These people have registered a Bitcoin address and want to sponsor Contributors working on {rocket.Name()} + + + + + + Sponsor + + Amount (Sats) + + + + {#each rocket.BitcoinAssociations() as [pubkey, ba], _ (pubkey)} + + +
+ +
+
+ + {ba.Address} + +
+ {/each} +
+
+
+
diff --git a/src/components/InputBitcoinAddress.svelte b/src/components/InputBitcoinAddress.svelte new file mode 100644 index 0000000..924c6f5 --- /dev/null +++ b/src/components/InputBitcoinAddress.svelte @@ -0,0 +1,32 @@ + + +
+
+ +
+ {#if bitcoinAddressError} +
{bitcoinAddressError}
+ {/if} +
diff --git a/src/components/RocketCard.svelte b/src/components/RocketCard.svelte index d23ca3b..de992ed 100644 --- a/src/components/RocketCard.svelte +++ b/src/components/RocketCard.svelte @@ -3,41 +3,40 @@ import { base } from '$app/paths'; import { Button } from '$lib/components/ui/button/index.js'; import * as Card from '$lib/components/ui/card/index.js'; - import { Name, Avatar } from '@nostr-dev-kit/ndk-svelte-components'; - import { getMission, getRocketURL } from '@/helpers'; - import type { NDKEvent } from '@nostr-dev-kit/ndk'; - import { ChevronRight } from 'lucide-svelte'; + import type { Rocket } from '@/event_helpers/rockets'; import { ndk } from '@/ndk'; + import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components'; + import { ChevronRight } from 'lucide-svelte'; - export let rocketEvent: NDKEvent; + export let rocket: Rocket; //$page.url.searchParams.get("tab") - {rocketEvent.getMatchingTags('d')[0][1]} - {getMission(rocketEvent)} + {rocket.Name()} + {rocket.Mission()}
- +
diff --git a/src/components/RocketDashboard.svelte b/src/components/RocketDashboard.svelte index 003cdef..e9f3feb 100644 --- a/src/components/RocketDashboard.svelte +++ b/src/components/RocketDashboard.svelte @@ -12,6 +12,7 @@ import Todo from './Todo.svelte'; import UpdateMission from './UpdateMission.svelte'; import { Rocket } from '@/event_helpers/rockets'; + import BitcoinAssociations from './BitcoinAssociations.svelte'; export let rocket: NDKEvent; @@ -42,6 +43,7 @@ + Actions diff --git a/src/lib/event_helpers/rockets.ts b/src/lib/event_helpers/rockets.ts index 921b10f..5d8a4ef 100644 --- a/src/lib/event_helpers/rockets.ts +++ b/src/lib/event_helpers/rockets.ts @@ -5,10 +5,68 @@ import validate from 'bitcoin-address-validation'; import { BitcoinTipTag } from '@/stores/bitcoin'; export class Rocket { + UpsertBitcoinAssociation(association: BitcoinAssociation): NDKEvent { + let event: NDKEvent | undefined = undefined; + if (true) { //todo: check if exists + this.PrepareForUpdate(); + event = new NDKEvent(this.Event.ndk, this.Event.rawEvent()); + event.created_at = Math.floor(new Date().getTime() / 1000); + event.tags.push(["address", `${association.Pubkey}:${association.Address}`]) + event.tags.push(['proof_full', JSON.stringify(association.Event.rawEvent())]); + updateIgnitionAndParentTag(event); + updateBitcoinTip(event); + } + return event; + } + BitcoinAssociations():Map { + let a = new Map() + for (let t of this.Event.getMatchingTags("address")) { + if (t.length == 2) { + let split = t[1].split(":") + if (split.length == 2) { + let ba = new BitcoinAssociation() + ba.Address = split[1] + ba.Pubkey = split[0] + if (ba.Validate()) { + a.set(ba.Pubkey, ba) + } + } + + } + } + return a + } Event: NDKEvent; + + URL(): string { + let ignitionID = undefined; + if ( + this.Event.getMatchingTags('ignition') && + this.Event.getMatchingTags('ignition')[0] && + this.Event.getMatchingTags('ignition')[0][1] + ) { + ignitionID = this.Event.getMatchingTags('ignition')[0][1]; + } + if (!ignitionID) { + ignitionID = this.Event.id; + } + let d = this.Event.getMatchingTags('d')[0][1]; + let p = this.Event.pubkey; + return `${ignitionID}?d=${d}&p=${p}`; + } Name(): string { return this.Event.dTag!; } + Mission(): string { + if ( + this.Event.getMatchingTags('mission') && + this.Event.getMatchingTags('mission')[0] && + this.Event.getMatchingTags('mission')[0][1] + ) { + return this.Event.getMatchingTags('mission')[0][1]; + } + return ''; + } Products(): RocketProduct[] { let _products: RocketProduct[] = []; for (let p of this.Event.getMatchingTags('product')) { @@ -118,7 +176,7 @@ export class Rocket { event.tags.push(['merit', `${request.Pubkey}:${request.ID}:0:0:${request.Merits}`]); event.tags.push(['proof_full', JSON.stringify(signedProof.rawEvent())]); updateIgnitionAndParentTag(event); - updateBitcionTip(event); + updateBitcoinTip(event); } return event; } @@ -133,33 +191,32 @@ export class Rocket { a.StartPrice = parseInt(items[2], 10); a.EndPrice = parseInt(items[3], 10); a.Merits = parseInt(items[4], 10); - + let ids = items[5].match(/.{1,64}/g); if (ids) { for (let id of ids) { a.AMRIDs.push(id); } } - let amrs = this.ApprovedMeritRequests() + let amrs = this.ApprovedMeritRequests(); let failed = false; for (let id of a.AMRIDs) { - let amr = amrs.get(id) + let amr = amrs.get(id); if (!amr) { - failed = true + failed = true; } else { if (!a.Owner) { - a.Owner = amr.Pubkey + a.Owner = amr.Pubkey; } else if (a.Owner != amr.Pubkey) { - failed = true + failed = true; } } } if (!failed) { - auctions.push(a) + auctions.push(a); } else { - throw new Error("this should not happen, bug!") + throw new Error('this should not happen, bug!'); } - } } } @@ -214,7 +271,7 @@ export class Rocket { ]); // event.tags.push(['proof_full', JSON.stringify(request.Event!.rawEvent())]); updateIgnitionAndParentTag(event); - updateBitcionTip(event); + updateBitcoinTip(event); } if (invalid) { event = undefined; @@ -238,7 +295,7 @@ export class Rocket { purchases ]); updateIgnitionAndParentTag(event); - updateBitcionTip(event); + updateBitcoinTip(event); return event; } UpdateMission(mission: string): NDKEvent { @@ -248,7 +305,7 @@ export class Rocket { event.removeTag('mission'); event.tags.push(['mission', mission]); updateIgnitionAndParentTag(event); - updateBitcionTip(event); + updateBitcoinTip(event); return event; } CurrentProducts(): Map { @@ -335,7 +392,7 @@ function updateIgnitionAndParentTag(event: NDKEvent) { event.tags.push(['parent', event.id]); } -function updateBitcionTip(event: NDKEvent) { +function updateBitcoinTip(event: NDKEvent) { let existingBitcoinTip = event.getMatchingTags('bitcoin'); let existing = []; for (let t of event.tags) { @@ -639,7 +696,7 @@ export class AMRAuction { } for (let pending of rocket.PendingAMRAuctions()) { if (pending.AMRIDs.includes(id)) { - valid = false + valid = false; } } } @@ -693,3 +750,27 @@ export class AMRAuction { } } } + +export class BitcoinAssociation { + Pubkey: string; + Address: string | undefined; + Event: NDKEvent; + Validate(): boolean { + let valid = true; + if (this.Pubkey.length != 64) { + valid = false; + } + if ((this.Address && !validate(this.Address)) || !this.Address) { + valid = false; + } + return valid; + } + + constructor(event?: NDKEvent) { + if (event) { + this.Pubkey = event.pubkey; + this.Address = event.tagValue('onchain'); + this.Event = event; + } + } +} diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts index 86b7093..86a0292 100644 --- a/src/lib/helpers.ts +++ b/src/lib/helpers.ts @@ -19,16 +19,7 @@ export function getRocketURL(e: NDKEvent): string { return `${ignitionID}?d=${d}&p=${p}`; } -export function getMission(rocketEvent: NDKEvent): string { - if ( - rocketEvent.getMatchingTags('mission') && - rocketEvent.getMatchingTags('mission')[0] && - rocketEvent.getMatchingTags('mission')[0][1] - ) { - return rocketEvent.getMatchingTags('mission')[0][1]; - } - return ''; -} + export function unixTimeNow() { return Math.floor(new Date().getTime() / 1000); diff --git a/src/routes/buymerits/+page.svelte b/src/routes/buymerits/+page.svelte index 2954100..efc98b8 100644 --- a/src/routes/buymerits/+page.svelte +++ b/src/routes/buymerits/+page.svelte @@ -8,6 +8,7 @@ import { Avatar } from '@nostr-dev-kit/ndk-svelte-components'; import { onDestroy } from 'svelte'; import { derived } from 'svelte/store'; + import AssociateBitcoinAddress from '../../components/AssociateBitcoinAddress.svelte'; import Login from '../../components/Login.svelte'; import MeritAuctions from '../../stateupdaters/MeritAuctions.svelte'; let rocketEvents = $ndk.storeSubscribe([{ kinds: [31108 as number] }], { subId: 'all_rockets' }); @@ -40,10 +41,21 @@ return merits; }); - + let noAssociatedBitcoinAddress = derived([currentUser, pendingSales], ([$currentUser, $pendingSales])=>{ + let show = false + if ($currentUser) { + for (let [r, _] of $pendingSales) { + if (!r.BitcoinAssociations().get($currentUser.pubkey)) { + show = true + } + } + } + return show + }) + -

Sponsor a Contributor

+{#if $noAssociatedBitcoinAddress}{/if} {#if $currentUser} {#each $pendingSales as [rocket, amr]} diff --git a/src/routes/sellmerits/+page.svelte b/src/routes/sellmerits/+page.svelte index a898ed5..dd1495b 100644 --- a/src/routes/sellmerits/+page.svelte +++ b/src/routes/sellmerits/+page.svelte @@ -12,6 +12,7 @@ import Login from '../../components/Login.svelte'; import CreateAMRAuction from '../../components/CreateAMRAuction.svelte'; import MeritAuctions from '../../stateupdaters/MeritAuctions.svelte'; + import Heading from '../../components/Heading.svelte'; let rocketEvents = $ndk.storeSubscribe([{ kinds: [31108 as number] }], { subId: 'all_rockets' }); onDestroy(() => { rocketEvents?.unsubscribe(); @@ -101,8 +102,7 @@ // return thisRocket // } - -

Trade your Merits for Sats

+ {#if $currentUser} {#each $myMeritRequests as [rocket, amr]} @@ -122,7 +122,7 @@ {#each rocket.PendingAMRAuctions().filter(r=>{return Boolean(r.Owner == $currentUser.pubkey)}) as p} - + {p.AMRIDs.length > 1 ? 'multiple' : p.AMRIDs[0].substring(0,12)} {p.Merits} diff --git a/src/stateupdaters/AssociateBitcoinAddress.svelte b/src/stateupdaters/AssociateBitcoinAddress.svelte new file mode 100644 index 0000000..5372808 --- /dev/null +++ b/src/stateupdaters/AssociateBitcoinAddress.svelte @@ -0,0 +1,63 @@ + diff --git a/src/views/rockets/Rockets.svelte b/src/views/rockets/Rockets.svelte index 57ff955..4fbcdfa 100644 --- a/src/views/rockets/Rockets.svelte +++ b/src/views/rockets/Rockets.svelte @@ -1,27 +1,44 @@ -{#if entries && $entries} +{#if rockets && $rockets} + - {#each $entries as rocketEvent (rocketEvent.id)} - + {#each $rockets as rocket (`${rocket.Event.pubkey}${rocket.Name()}`)} + {/each} {/if}