mirror of
https://github.com/aljazceru/hypergolic.git
synced 2025-12-18 22:14:21 +01:00
problem: voting and rocket logic is spread out and messy
This commit is contained in:
@@ -6,54 +6,21 @@
|
|||||||
import { Input } from '$lib/components/ui/input/index.js';
|
import { Input } from '$lib/components/ui/input/index.js';
|
||||||
import { Label } from '$lib/components/ui/label/index.js';
|
import { Label } from '$lib/components/ui/label/index.js';
|
||||||
import * as Alert from '@/components/ui/alert';
|
import * as Alert from '@/components/ui/alert';
|
||||||
import { getRocketURL } from '@/helpers';
|
|
||||||
import { ndk } from '@/ndk';
|
import { ndk } from '@/ndk';
|
||||||
import { currentUser } from '@/stores/session';
|
import { currentUser } from '@/stores/session';
|
||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { Terminal } from 'lucide-svelte';
|
import { Terminal } from 'lucide-svelte';
|
||||||
import Todo from './Todo.svelte';
|
import Todo from './Todo.svelte';
|
||||||
|
import { Rocket } from '@/event_helpers/rockets';
|
||||||
|
|
||||||
export let product: NDKEvent;
|
export let product: NDKEvent;
|
||||||
export let rocket: NDKEvent;
|
export let rocket: NDKEvent;
|
||||||
|
|
||||||
|
let parsedRocket: Rocket = new Rocket(rocket);
|
||||||
|
|
||||||
let price: number = 0;
|
let price: number = 0;
|
||||||
let max: number = 0;
|
let max: number = 0;
|
||||||
|
|
||||||
function updateIgnitionAndParentTag(rocket: NDKEvent) {
|
|
||||||
let existingIgnition = rocket.getMatchingTags('ignition');
|
|
||||||
//let existingParent = rocket.getMatchingTags("parent")
|
|
||||||
removeIgnitionAndParentTag(rocket);
|
|
||||||
if (existingIgnition.length > 1) {
|
|
||||||
throw new Error('too many ignition tags!');
|
|
||||||
}
|
|
||||||
if (existingIgnition.length == 0) {
|
|
||||||
rocket.tags.push(['ignition', rocket.id]);
|
|
||||||
}
|
|
||||||
if (existingIgnition.length == 1) {
|
|
||||||
if (existingIgnition[0][1].length == 64) {
|
|
||||||
rocket.tags.push(existingIgnition[0]);
|
|
||||||
}
|
|
||||||
if (existingIgnition[0][1] == 'this') {
|
|
||||||
rocket.tags.push(['ignition', rocket.id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rocket.tags.push(['parent', rocket.id]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeIgnitionAndParentTag(rocket: NDKEvent) {
|
|
||||||
let existing = [];
|
|
||||||
for (let t of rocket.tags) {
|
|
||||||
existing.push(t);
|
|
||||||
}
|
|
||||||
rocket.tags = [];
|
|
||||||
for (let t of existing) {
|
|
||||||
if (t[0] !== 'ignition' && t[0] !== 'parent') {
|
|
||||||
rocket.tags.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function publish() {
|
function publish() {
|
||||||
if (!$ndk.signer) {
|
if (!$ndk.signer) {
|
||||||
throw new Error('no ndk signer found');
|
throw new Error('no ndk signer found');
|
||||||
@@ -67,16 +34,8 @@
|
|||||||
console.log(rocket.author, author);
|
console.log(rocket.author, author);
|
||||||
throw new Error('you are not the creator of this rocket');
|
throw new Error('you are not the creator of this rocket');
|
||||||
}
|
}
|
||||||
rocket.created_at = Math.floor(new Date().getTime() / 1000);
|
let event = parsedRocket.UpsertProduct(product.id, price, max);
|
||||||
//todo validate d tag
|
event.publish().then((x) => {
|
||||||
rocket.tags.push([
|
|
||||||
'product',
|
|
||||||
`${product.id}:${price}:${rocket.created_at}:${max}`,
|
|
||||||
'wss://relay.nostrocket.org',
|
|
||||||
JSON.stringify([])
|
|
||||||
]);
|
|
||||||
updateIgnitionAndParentTag(rocket)
|
|
||||||
rocket.publish().then((x) => {
|
|
||||||
console.log(x);
|
console.log(x);
|
||||||
goto(`${base}/products`);
|
goto(`${base}/products`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
{#each $merits as [id, merit], _ (id)}
|
{#each $merits as [id, merit], _ (id)}
|
||||||
<Table.Row
|
<Table.Row
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
console.log(merit.Event.rawEvent());
|
|
||||||
goto(`${base}/rockets/merits/${merit.ID}`);
|
goto(`${base}/rockets/merits/${merit.ID}`);
|
||||||
}}
|
}}
|
||||||
class="cursor-pointer bg-accent"
|
class="cursor-pointer bg-accent"
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as Card from '$lib/components/ui/card/index.js';
|
import * as Card from '$lib/components/ui/card/index.js';
|
||||||
import { Vote, type MeritRequest } from '@/event_helpers/merits';
|
import { Vote, Votes, type MeritRequest } from '@/event_helpers/merits';
|
||||||
import { ndk } from '@/ndk';
|
import { ndk } from '@/ndk';
|
||||||
import type { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKEvent, type NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
||||||
import { ExternalLink, Info } from 'lucide-svelte';
|
import { ExternalLink, Info } from 'lucide-svelte';
|
||||||
import { onDestroy } from 'svelte';
|
import { onDestroy } from 'svelte';
|
||||||
import VoteOnMeritRequest from './VoteOnMeritRequest.svelte';
|
import VoteOnMeritRequest from './VoteOnMeritRequest.svelte';
|
||||||
|
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
import { base } from '$app/paths';
|
|
||||||
import { Separator } from '$lib/components/ui/separator/index.js';
|
import { Separator } from '$lib/components/ui/separator/index.js';
|
||||||
import * as Table from '@/components/ui/table';
|
import * as Table from '@/components/ui/table';
|
||||||
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
import { Rocket, RocketATagFilter } from '@/event_helpers/rockets';
|
||||||
@@ -19,12 +17,15 @@
|
|||||||
import { Button } from '$lib/components/ui/button/index.js';
|
import { Button } from '$lib/components/ui/button/index.js';
|
||||||
import { Label } from '$lib/components/ui/label/index.js';
|
import { Label } from '$lib/components/ui/label/index.js';
|
||||||
import { Textarea } from '$lib/components/ui/textarea/index.js';
|
import { Textarea } from '$lib/components/ui/textarea/index.js';
|
||||||
import CornerDownLeft from 'lucide-svelte/icons/corner-down-left';
|
|
||||||
import Alert from '@/components/ui/alert/alert.svelte';
|
import Alert from '@/components/ui/alert/alert.svelte';
|
||||||
|
import { currentUser } from '@/stores/session';
|
||||||
|
import CornerDownLeft from 'lucide-svelte/icons/corner-down-left';
|
||||||
|
|
||||||
export let merit: MeritRequest;
|
export let merit: MeritRequest;
|
||||||
export let rocket: NDKEvent;
|
export let rocket: NDKEvent;
|
||||||
|
|
||||||
|
let parsedRocket = new Rocket(rocket);
|
||||||
|
|
||||||
let _votes = $ndk.storeSubscribe(
|
let _votes = $ndk.storeSubscribe(
|
||||||
{ '#a': [RocketATagFilter(rocket)], '#e': [merit.ID], kinds: [1410 as NDKKind] },
|
{ '#a': [RocketATagFilter(rocket)], '#e': [merit.ID], kinds: [1410 as NDKKind] },
|
||||||
{
|
{
|
||||||
@@ -52,11 +53,36 @@
|
|||||||
for (let [_, v] of vMap) {
|
for (let [_, v] of vMap) {
|
||||||
let existing = pMap.get(v.Pubkey);
|
let existing = pMap.get(v.Pubkey);
|
||||||
if (!existing || (existing && existing.TimeStamp < v.TimeStamp)) {
|
if (!existing || (existing && existing.TimeStamp < v.TimeStamp)) {
|
||||||
|
//todo: check if this merit request has already been included in the rocket. If not, and if we have enough votes to approve it, update the rocket.
|
||||||
pMap.set(v.Pubkey, v);
|
pMap.set(v.Pubkey, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pMap;
|
vMap = new Map<string, Vote>();
|
||||||
|
for (let [_, v] of pMap) {
|
||||||
|
vMap.set(v.ID, v);
|
||||||
|
}
|
||||||
|
return vMap;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let rocketUpdates = derived([votes, currentUser], ([$votes, $currentUser]) => {
|
||||||
|
let events: NDKEvent[] = [];
|
||||||
|
if (
|
||||||
|
$currentUser &&
|
||||||
|
parsedRocket &&
|
||||||
|
parsedRocket.VotePowerForPubkey($currentUser.pubkey) > 0
|
||||||
|
) {
|
||||||
|
let votes = new Votes(Array.from($votes, ([_, v])=>(v)))
|
||||||
|
let result = votes.Results().Result(parsedRocket)
|
||||||
|
if (result && result == "ratify" && !parsedRocket.ApprovedMeritRequests().get(votes.Request)) {
|
||||||
|
//todo: parsedRocket.AppendAMR(votes.ConstructProof())
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events;
|
||||||
|
});
|
||||||
|
|
||||||
|
rocketUpdates.subscribe((c)=>{if (c.length > 0){console.log(c)}})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card.Root class="sm:col-span-2">
|
<Card.Root class="sm:col-span-2">
|
||||||
@@ -116,14 +142,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<Separator class="my-4" />
|
<Separator class="my-4" />
|
||||||
<div class="font-semibold">Votes</div>
|
<div class="font-semibold">Votes</div>
|
||||||
{#if $votes.size == 0}<Alert><Info />Waiting for existing <span class="italic">{new Rocket(rocket).Name()}</span> Merit holders to vote</Alert> {/if}
|
{#if $votes.size == 0}<Alert
|
||||||
|
><Info />Waiting for existing <span class="italic">{new Rocket(rocket).Name()}</span> Merit
|
||||||
|
holders to vote</Alert
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
<Table.Root>
|
<Table.Root>
|
||||||
<Table.Body>
|
<Table.Body>
|
||||||
{#each $votes as [id, vote], _ (id)}
|
{#each $votes as [id, vote], _ (id)}
|
||||||
<Table.Row
|
<Table.Row
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
console.log(vote.Event.rawEvent());
|
console.log(vote.Event.rawEvent());
|
||||||
goto(`${base}/rockets/merits/${vote.ID}`);
|
|
||||||
}}
|
}}
|
||||||
class="cursor-pointer {vote.VoteDirection == 'ratify'
|
class="cursor-pointer {vote.VoteDirection == 'ratify'
|
||||||
? 'bg-lime-600'
|
? 'bg-lime-600'
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class MeritRequest {
|
|||||||
return _solution;
|
return _solution;
|
||||||
}
|
}
|
||||||
IncludedInRocketState(rocket: Rocket): boolean {
|
IncludedInRocketState(rocket: Rocket): boolean {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
BasicValidation(): boolean {
|
BasicValidation(): boolean {
|
||||||
//todo: make a ValidateAgainstRocket and check that pubkey is in WoT
|
//todo: make a ValidateAgainstRocket and check that pubkey is in WoT
|
||||||
@@ -94,26 +94,21 @@ export class Vote {
|
|||||||
BasicValidation(): boolean {
|
BasicValidation(): boolean {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
if (
|
if (
|
||||||
!(
|
!(this.ID.length == 64 && this.Request.length == 64 && this.VoteDirection && this.TimeStamp)
|
||||||
this.ID.length == 64 &&
|
|
||||||
this.Request.length == 64 &&
|
|
||||||
this.VoteDirection &&
|
|
||||||
this.TimeStamp
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
ValidateAgainstRocket(rocket:Rocket):boolean {
|
ValidateAgainstRocket(rocket: Rocket): boolean {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
if (!(rocket.VotePowerForPubkey(this.Pubkey) > 0)) {
|
if (!(rocket.VotePowerForPubkey(this.Pubkey) > 0)) {
|
||||||
valid = false
|
valid = false;
|
||||||
}
|
}
|
||||||
return valid
|
return valid;
|
||||||
}
|
}
|
||||||
ValidateAgainstMeritRequest(merit:MeritRequest):boolean {
|
ValidateAgainstMeritRequest(merit: MeritRequest): boolean {
|
||||||
return this.Request == merit.ID
|
return this.Request == merit.ID;
|
||||||
}
|
}
|
||||||
RocketTag(): NDKTag | undefined {
|
RocketTag(): NDKTag | undefined {
|
||||||
let tag: NDKTag | undefined = undefined;
|
let tag: NDKTag | undefined = undefined;
|
||||||
@@ -151,17 +146,119 @@ export class Vote {
|
|||||||
if (this.Event.created_at) {
|
if (this.Event.created_at) {
|
||||||
this.TimeStamp = this.Event.created_at;
|
this.TimeStamp = this.Event.created_at;
|
||||||
}
|
}
|
||||||
for (let t of this.Event.getMatchingTags("vote")) {
|
for (let t of this.Event.getMatchingTags('vote')) {
|
||||||
if (t && t.length == 2 && (t[1] == "blackball" || t[1] == "ratify")) {
|
if (t && t.length == 2 && (t[1] == 'blackball' || t[1] == 'ratify')) {
|
||||||
this.VoteDirection = t[1]
|
this.VoteDirection = t[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let t of this.Event.getMatchingTags("request")) {
|
for (let t of this.Event.getMatchingTags('request')) {
|
||||||
if (t && t.length == 2 && t[1].length == 64) {
|
if (t && t.length == 2 && t[1].length == 64) {
|
||||||
this.Request = t[1]
|
this.Request = t[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.BasicValidation()) {
|
||||||
|
throw new Error('failed to create vote');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VoteDirection = 'blackball' | 'ratify';
|
||||||
|
|
||||||
|
export class Votes {
|
||||||
|
Votes: Vote[];
|
||||||
|
Request:string;
|
||||||
|
Results(): VoteResults {
|
||||||
|
let ratifiers = new Map<string, Vote>();
|
||||||
|
let blackballers = new Map<string, Vote>();
|
||||||
|
for (let v of this.Votes) {
|
||||||
|
if ((v.VoteDirection == 'blackball')) {
|
||||||
|
blackballers.set(v.ID, v);
|
||||||
|
}
|
||||||
|
if ((v.VoteDirection == 'ratify')) {
|
||||||
|
ratifiers.set(v.ID, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let results: VoteResults = new VoteResults(
|
||||||
|
new VoteTally(blackballers),
|
||||||
|
new VoteTally(ratifiers)
|
||||||
|
);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
constructor(votes: Vote[], request?:string) {
|
||||||
|
this.Votes = []
|
||||||
|
for (let v of votes) {
|
||||||
|
if (!request) {
|
||||||
|
request = v.Request;
|
||||||
|
}
|
||||||
|
if (!this.Request) {
|
||||||
|
this.Request = request
|
||||||
|
}
|
||||||
|
if (v.Request == this.Request) {
|
||||||
|
this.Votes.push(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VoteDirection = "blackball" | "ratify"
|
export class VoteResults {
|
||||||
|
blackballers: VoteTally;
|
||||||
|
ratifiers: VoteTally;
|
||||||
|
Result(rocket: Rocket): VoteDirection | undefined {
|
||||||
|
let result: VoteDirection | undefined = undefined;
|
||||||
|
if (this.blackballers.TotalPercent(rocket) < 0.1 && this.ratifiers.TotalPercent(rocket) > 0.5) {
|
||||||
|
result = 'ratify';
|
||||||
|
}
|
||||||
|
if (this.blackballers.TotalPercent(rocket) >= 0.1) {
|
||||||
|
result = 'blackball';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
constructor(blackballers: VoteTally, ratifiers: VoteTally) {
|
||||||
|
this.blackballers = blackballers;
|
||||||
|
this.ratifiers = ratifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VoteTally {
|
||||||
|
Votes: Map<string, Vote>;
|
||||||
|
Direction: VoteDirection | undefined;
|
||||||
|
MeritRequest: string | undefined;
|
||||||
|
BasicValidation(): boolean {
|
||||||
|
let valid = true;
|
||||||
|
for (let [_, v] of this.Votes) {
|
||||||
|
if (!this.Direction) {
|
||||||
|
this.Direction = v.VoteDirection;
|
||||||
|
}
|
||||||
|
if (!this.MeritRequest) {
|
||||||
|
this.MeritRequest = v.Request;
|
||||||
|
}
|
||||||
|
if (v.VoteDirection != this.Direction || v.Request != this.MeritRequest) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
Total(rocket: Rocket): number {
|
||||||
|
let total = 0;
|
||||||
|
if (this.BasicValidation()) {
|
||||||
|
for (let [_, v] of this.Votes) {
|
||||||
|
total += rocket.VotePowerForPubkey(v.Pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
TotalPercent(rocket: Rocket): number {
|
||||||
|
let result = undefined;
|
||||||
|
let total = this.Total(rocket);
|
||||||
|
return total / rocket.TotalVotePower();
|
||||||
|
}
|
||||||
|
constructor(votes: Map<string, Vote>) {
|
||||||
|
this.Votes = votes;
|
||||||
|
this.Direction = undefined;
|
||||||
|
this.MeritRequest = undefined;
|
||||||
|
if (!this.BasicValidation()) {
|
||||||
|
throw new Error('invalid votes detected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,29 +2,144 @@ import { NDKEvent, type NDKTag } from '@nostr-dev-kit/ndk';
|
|||||||
|
|
||||||
export class Rocket {
|
export class Rocket {
|
||||||
Event: NDKEvent;
|
Event: NDKEvent;
|
||||||
Name():string {
|
Name(): string {
|
||||||
return this.Event.dTag!
|
return this.Event.dTag!;
|
||||||
}
|
}
|
||||||
VotePowerForPubkey(pubkey:string):number {
|
VotePowerForPubkey(pubkey: string): number {
|
||||||
let votepower = 0
|
let votepower = 0;
|
||||||
if (this.Event.pubkey == pubkey) {
|
if (this.Event.pubkey == pubkey) {
|
||||||
//todo: calculate votepower for pubkey based on approved merit requests
|
//todo: calculate votepower for pubkey based on approved merit requests
|
||||||
votepower++
|
votepower++;
|
||||||
}
|
}
|
||||||
return votepower
|
return votepower;
|
||||||
}
|
}
|
||||||
constructor(event:NDKEvent) {
|
TotalVotePower(): number {
|
||||||
|
//todo: calculate votepower for pubkey based on approved merit requests
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ApprovedMeritRequests(): Map<string, RocketAMR> {
|
||||||
|
let amr = new Map<string, RocketAMR>();
|
||||||
|
for (let m of this.Event.getMatchingTags('merit')) {
|
||||||
|
if (m && m.length == 2) {
|
||||||
|
let _amr = new RocketAMR(m[1]);
|
||||||
|
amr.set(_amr.ID, _amr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amr;
|
||||||
|
}
|
||||||
|
AppendAMR(amrProof: NDKEvent): NDKEvent | undefined {
|
||||||
|
//todo
|
||||||
|
let request: NDKEvent | undefined = undefined;
|
||||||
|
let votes: NDKEvent[] = [];
|
||||||
|
let _request = amrProof.getMatchingTags('request');
|
||||||
|
if (_request.length == 1) {
|
||||||
|
try {
|
||||||
|
request = JSON.parse(_request[0][1]);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
for (let v of amrProof.getMatchingTags('vote')) {
|
||||||
|
try {
|
||||||
|
votes.push(JSON.parse(v[1]));
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
//add the AMR to the rocket event, and also add a proof
|
||||||
|
}
|
||||||
|
UpsertProduct(id: string, price: number, maxSales?: number): NDKEvent {
|
||||||
|
let event = new NDKEvent(this.Event.ndk, this.Event.rawEvent());
|
||||||
|
event.created_at = Math.floor(new Date().getTime() / 1000);
|
||||||
|
let existingProducts = this.CurrentProducts();
|
||||||
|
let purchases = JSON.stringify([]);
|
||||||
|
let existingProduct = existingProducts.get(id);
|
||||||
|
if (existingProduct) {
|
||||||
|
purchases = existingProduct.PurchasesJSON();
|
||||||
|
}
|
||||||
|
event.tags.push([
|
||||||
|
'product',
|
||||||
|
`${id}:${price}:${event.created_at}:${maxSales}`,
|
||||||
|
'wss://relay.nostrocket.org',
|
||||||
|
purchases
|
||||||
|
]);
|
||||||
|
updateIgnitionAndParentTag(event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
CurrentProducts(): Map<string, RocketProduct> {
|
||||||
|
return getMapOfProductsFromRocket(this.Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(event: NDKEvent) {
|
||||||
this.Event = event;
|
this.Event = event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateIgnitionAndParentTag(event: NDKEvent) {
|
||||||
|
let existingIgnition = event.getMatchingTags('ignition');
|
||||||
|
//let existingParent = rocket.getMatchingTags("parent")
|
||||||
|
let existing = [];
|
||||||
|
for (let t of event.tags) {
|
||||||
|
existing.push(t);
|
||||||
|
}
|
||||||
|
event.tags = [];
|
||||||
|
for (let t of existing) {
|
||||||
|
if (t[0] !== 'ignition' && t[0] !== 'parent') {
|
||||||
|
event.tags.push(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (existingIgnition.length > 1) {
|
||||||
|
throw new Error('too many ignition tags!');
|
||||||
|
}
|
||||||
|
if (existingIgnition.length == 0) {
|
||||||
|
event.tags.push(['ignition', event.id]);
|
||||||
|
}
|
||||||
|
if (existingIgnition.length == 1) {
|
||||||
|
if (existingIgnition[0][1].length == 64) {
|
||||||
|
event.tags.push(existingIgnition[0]);
|
||||||
|
}
|
||||||
|
if (existingIgnition[0][1] == 'this') {
|
||||||
|
event.tags.push(['ignition', event.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.tags.push(['parent', event.id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RocketAMR {
|
||||||
|
ID: string;
|
||||||
|
Pubkey: string;
|
||||||
|
LeadTime: number;
|
||||||
|
LeadTimeUpdate: number;
|
||||||
|
Merits: number;
|
||||||
|
Valid(): boolean {
|
||||||
|
let valid = true;
|
||||||
|
if (!(this.ID.length == 64 && this.Pubkey.length == 64 && this.Merits)) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
constructor(meritString: string) {
|
||||||
|
let split = meritString.split(':');
|
||||||
|
if (split.length == 5) {
|
||||||
|
this.Pubkey = split[0];
|
||||||
|
this.ID = split[1];
|
||||||
|
this.LeadTime = parseInt(split[2], 10);
|
||||||
|
this.LeadTimeUpdate = parseInt(split[3], 10);
|
||||||
|
this.Merits = parseInt(split[4], 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class RocketProduct {
|
export class RocketProduct {
|
||||||
ID: string;
|
ID: string;
|
||||||
Price: number;
|
Price: number;
|
||||||
ValidAfter: number; //unix time
|
ValidAfter: number; //unix time
|
||||||
MaxPurchases: number;
|
MaxPurchases: number;
|
||||||
Purchases: Map<string, ProductPayment>;
|
Purchases: Map<string, ProductPayment>;
|
||||||
|
PurchasesJSON(): string {
|
||||||
|
let purchases = [];
|
||||||
|
for (let [_, p] of this.Purchases) {
|
||||||
|
purchases.push(`${p.ZapID}:${p.BuyerPubkey}:${p.WitnessedAt}`);
|
||||||
|
}
|
||||||
|
return JSON.stringify(purchases);
|
||||||
|
}
|
||||||
constructor(tag: NDKTag) {
|
constructor(tag: NDKTag) {
|
||||||
this.Purchases = new Map();
|
this.Purchases = new Map();
|
||||||
this.ID = tag[1].split(':')[0];
|
this.ID = tag[1].split(':')[0];
|
||||||
@@ -138,23 +253,23 @@ function getZapRequest(zapReceipt: NDKEvent): NDKEvent | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getZapAmount(zapRequest?: NDKEvent): number {
|
function getZapAmount(zapRequest?: NDKEvent): number {
|
||||||
return getNumberFromTag("amount", zapRequest)
|
return getNumberFromTag('amount', zapRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNumberFromTag(tag:string, event?: NDKEvent): number {
|
export function getNumberFromTag(tag: string, event?: NDKEvent): number {
|
||||||
let amountTag = event?.getMatchingTags(tag);
|
let amountTag = event?.getMatchingTags(tag);
|
||||||
if (amountTag && amountTag[0] && amountTag[0][1]) {
|
if (amountTag && amountTag[0] && amountTag[0][1]) {
|
||||||
try {
|
try {
|
||||||
let amount = parseInt(amountTag[0][1], 10);
|
let amount = parseInt(amountTag[0][1], 10);
|
||||||
return amount
|
return amount;
|
||||||
} catch {
|
} catch {
|
||||||
console.log("ERROR: could not find number in tag: ", tag, event)
|
console.log('ERROR: could not find number in tag: ', tag, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidUrl(string:string):boolean {
|
export function isValidUrl(string: string): boolean {
|
||||||
try {
|
try {
|
||||||
new URL(string);
|
new URL(string);
|
||||||
return true;
|
return true;
|
||||||
@@ -163,6 +278,6 @@ export function isValidUrl(string:string):boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RocketATagFilter(rocket:NDKEvent):string {
|
export function RocketATagFilter(rocket: NDKEvent): string {
|
||||||
return `31108:${rocket.pubkey}:${rocket.dTag}`
|
return `31108:${rocket.pubkey}:${rocket.dTag}`;
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
let meritRequestID = $page.params.merit;
|
let meritRequestID = $page.params.merit;
|
||||||
|
|
||||||
let meritRequest:MeritRequest | undefined;
|
let meritRequest:MeritRequest | undefined = undefined;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (meritRequestID.length == 64 && !meritRequest) {
|
if (meritRequestID.length == 64 && !meritRequest) {
|
||||||
|
|||||||
Reference in New Issue
Block a user