diff --git a/src/lib/event_helpers/rockets.ts b/src/lib/event_helpers/rockets.ts index 074b6d1..9497096 100644 --- a/src/lib/event_helpers/rockets.ts +++ b/src/lib/event_helpers/rockets.ts @@ -1,5 +1,5 @@ import { getAuthorizedZapper } from '@/helpers'; -import { BitcoinTipTag, txs } from '@/stores/bitcoin'; +import { BitcoinTipTag, txo, txs } from '@/stores/bitcoin'; import { NDKEvent, type NDKTag } from '@nostr-dev-kit/ndk'; import validate from 'bitcoin-address-validation'; import { sha256 } from 'js-sha256'; @@ -47,7 +47,6 @@ export class Rocket { } UpsertMeritTransfer(request: MeritPurchase): NDKEvent | undefined { let event: NDKEvent | undefined = undefined; - let fatal = false; if (this.PendingAMRAuctionsMap().get(request.auction.ID())) { this.PrepareForUpdate(); let _event = new NDKEvent(this.Event.ndk, this.Event.rawEvent()); @@ -62,7 +61,7 @@ export class Rocket { _event.tags.push(t); } } - _event.tags.push(['proof_raw', `txid:${request.txid}`]); + _event.tags.push(['proof_raw', `txid:${request.tx.ID}`]); let modifiedMerits: Map = new Map(); for (let id of request.auction.AMRIDs) { @@ -86,8 +85,29 @@ export class Rocket { } _event.tags.push([ 'swap', - `${request.auction.Merits}:${request.sats}:${Math.floor(new Date().getTime() / 1000)}` + `${request.auction.Merits}:${request.tx.Amount}:${Math.floor(new Date().getTime() / 1000)}` ]); + let existingAssociation = this.BitcoinAssociations().get(request.tx.From); + if ( + !existingAssociation || + (existingAssociation && existingAssociation.Pubkey != request.buyer) + ) { + return event; + } + if (request.tx.Change) { + let existingAssociations = this.BitcoinAssociations(); + _event.removeTag('address'); + for (let [_, ba] of existingAssociations) { + if (ba.Address != request.tx.From) { + _event.tags.push(ba.Tag()); + } + if (ba.Address == request.tx.From) { + ba.Address = request.tx.Change; + _event.tags.push(ba.Tag()); + } + } + } + updateIgnitionAndParentTag(_event); updateBitcoinTip(_event); event = _event; @@ -863,6 +883,9 @@ export class BitcoinAssociation { Address: string | undefined; Event: NDKEvent; Balance: number; + Tag(): NDKTag { + return ['address', `${this.Pubkey}:${this.Address}`]; + } Validate(): boolean { let valid = true; if (this.Pubkey.length != 64) { @@ -954,19 +977,17 @@ export class Product { export class MeritPurchase { auction: AMRAuction; buyer: string; - txid: string; - sats: number; + tx: txo; rocket: Rocket; Validate(): boolean { //todo: at least validate the utxo format return true; } - constructor(rocket: Rocket, auction: AMRAuction, buyer: string, txid: string, sats: number) { + constructor(rocket: Rocket, auction: AMRAuction, buyer: string, tx: txo) { this.rocket = rocket; this.auction = auction; this.buyer = buyer; - this.txid = txid; - this.sats = sats; + this.tx = tx; } } diff --git a/src/lib/stores/bitcoin.ts b/src/lib/stores/bitcoin.ts index 3746612..69008bb 100644 --- a/src/lib/stores/bitcoin.ts +++ b/src/lib/stores/bitcoin.ts @@ -134,6 +134,7 @@ export class txs { let amount = 0; let height = tx.status.block_height ? tx.status.block_height : 0; let txid = tx.txid; + let change: string[] = []; for (let vout of tx.vout) { let address = vout.scriptpubkey_address; if (address && address.trim() == this.Address) { @@ -141,8 +142,11 @@ export class txs { if (value) { amount += parseInt(value, 10); } + } else { + change.push(address); } } + for (let vin of tx.vin) { let address = vin.prevout.scriptpubkey_address; if (address && validate(address)) { @@ -152,9 +156,12 @@ export class txs { t.From = address; t.To = this.Address; t.ID = txid; + if (change.length == 1) { + t.Change = change[0]; + } possibles.set(address, t); } else { - console.log(156, vin) + console.log(156, vin); } } } @@ -174,5 +181,6 @@ export class txo { To: string; Amount: number; Height: number; + Change: string; constructor() {} } diff --git a/src/routes/buymerits/+page.svelte b/src/routes/buymerits/+page.svelte index ea33790..582fad2 100644 --- a/src/routes/buymerits/+page.svelte +++ b/src/routes/buymerits/+page.svelte @@ -7,7 +7,7 @@ import { currentUser } from '@/stores/session'; import { NDKEvent } from '@nostr-dev-kit/ndk'; import { Avatar } from '@nostr-dev-kit/ndk-svelte-components'; - import { onDestroy } from 'svelte'; + import { onDestroy, onMount } from 'svelte'; import { derived } from 'svelte/store'; import AssociateBitcoinAddress from '../../components/AssociateBitcoinAddress.svelte'; import Heading from '../../components/Heading.svelte'; @@ -89,7 +89,7 @@ for (let [address, txo] of txs.From()) { for (let [_, ba] of r.BitcoinAssociations()) { if (ba.Address == txo.From) { - return new MeritPurchase(r, amrAuction, ba.Pubkey, txo.ID, txo.Amount); + return new MeritPurchase(r, amrAuction, ba.Pubkey, txo); } } }