From d5139f5789c96b6de37dfb2c52125824f7d7f8b9 Mon Sep 17 00:00:00 2001 From: Nishant Ghodke <64554492+iamcrazycoder@users.noreply.github.com> Date: Fri, 20 Oct 2023 09:05:08 +0530 Subject: [PATCH] refactor(sdk): update royalty structure (#85) * refactor: update royalty struct and related fns * docs: add comment to clarify a confusing line * fix: pass price as arg and use 8 fractional digits * refactor: move repeating expression to variable * refactor: move calculate royalty caller to parent scope * refactor: set existing royalty perc value * fix: pass dust validation if amount is equal to min val --- .../src/instant-trade/InstantTradeBuilder.ts | 35 ++++++++++++++++--- .../InstantTradeBuyerTxBuilder.ts | 11 ++++-- .../InstantTradeSellerTxBuilder.ts | 29 ++++++++------- packages/sdk/src/transactions/PSBTBuilder.ts | 2 +- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/packages/sdk/src/instant-trade/InstantTradeBuilder.ts b/packages/sdk/src/instant-trade/InstantTradeBuilder.ts index 0b8d5e2c..a2d5c833 100644 --- a/packages/sdk/src/instant-trade/InstantTradeBuilder.ts +++ b/packages/sdk/src/instant-trade/InstantTradeBuilder.ts @@ -7,12 +7,22 @@ export interface InstantTradeBuilderArgOptions inscriptionOutpoint?: string } +interface RoyaltyAttributes { + amount: number + percentage: number + receiver: string | null +} + export default class InstantTradeBuilder extends PSBTBuilder { protected inscriptionOutpoint?: string protected inscription?: Inscription protected price = 0 protected postage = 0 - protected royalty = 0 + protected royalty: RoyaltyAttributes = { + amount: 0, + percentage: 0, + receiver: null + } constructor({ address, @@ -40,11 +50,28 @@ export default class InstantTradeBuilder extends PSBTBuilder { setPrice(value: number) { this.validatePrice(value) - this.price = parseInt(value.toString()) + this.price = parseInt(value.toString()) // intentional re-parsing to number as value can be floating point } - setRoyalty(value: number) { - this.royalty = value + setRoyalty( + data: Omit & Partial> & { price: number } + ) { + if (data.amount < MINIMUM_AMOUNT_IN_SATS) return + + this.royalty = { + amount: data.amount, + receiver: data.receiver, + // percentage to be used only for display purposes + percentage: + data.percentage && data.percentage > 0 + ? data.percentage + : +new Intl.NumberFormat("en", { + maximumFractionDigits: 8, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + roundingMode: "trunc" + }).format(data.amount / data.price) + } } get data() { diff --git a/packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts b/packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts index 5942d96e..eab15d1f 100644 --- a/packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts +++ b/packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts @@ -57,13 +57,18 @@ export default class InstantTradeBuyerTxBuilder extends InstantTradeBuilder { } private decodePrice() { - this.validatePrice((this.sellerPSBT.data.globalMap.unsignedTx as any).tx.outs[0].value - this.postage) - this.setPrice((this.sellerPSBT.data.globalMap.unsignedTx as any).tx.outs[0].value - this.postage) + const price = (this.sellerPSBT.data.globalMap.unsignedTx as any).tx.outs[0].value - this.postage + this.validatePrice(price) + this.setPrice(price) } private decodeRoyalty() { const royaltyOutput = (this.sellerPSBT.data.globalMap.unsignedTx as any).tx.outs[1] - royaltyOutput && this.setRoyalty(royaltyOutput.value) + const scriptPayload = getScriptType(royaltyOutput.script, this.network).payload + const amount = royaltyOutput && royaltyOutput.value >= MINIMUM_AMOUNT_IN_SATS ? royaltyOutput.value : 0 + const receiver = scriptPayload ? scriptPayload.address : null + + royaltyOutput && receiver && this.setRoyalty({ amount, receiver, price: this.price + amount }) } private bindRefundableOutput() { diff --git a/packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts b/packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts index 9e5c5019..1fb3f6b3 100644 --- a/packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts +++ b/packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts @@ -50,15 +50,15 @@ export default class InstantTradeSellerTxBuilder extends InstantTradeBuilder { this.inputs = [input] } - private async generateSellerOutputs() { - const royalty = await this.calculateRoyalty() - const royaltyAmount = royalty && royalty.amount >= MINIMUM_AMOUNT_IN_SATS ? royalty.amount : 0 - this.outputs = [{ address: this.receiveAddress || this.address, value: this.price + this.postage - royaltyAmount }] + private generateSellerOutputs() { + this.outputs = [ + { address: this.receiveAddress || this.address, value: this.price + this.postage - this.royalty.amount } + ] - if (royalty && royaltyAmount) { + if (this.royalty.amount >= MINIMUM_AMOUNT_IN_SATS && this.royalty.receiver) { this.outputs.push({ - address: royalty.address, // creator address - value: royalty.amount // royalty in sats to be paid to original creator + address: this.royalty.receiver, // creator address + value: this.royalty.amount // royalty in sats to be paid to original creator }) } } @@ -75,10 +75,12 @@ export default class InstantTradeSellerTxBuilder extends InstantTradeBuilder { } const amount = Math.ceil(royalty.pct * this.price) - return { - address: royalty.address as string, - amount: amount >= MINIMUM_AMOUNT_IN_SATS ? amount : 0 - } + this.setRoyalty({ + price: this.price, + amount, + receiver: royalty.address as string, + percentage: royalty.pct + }) } private validateOwnership() { @@ -94,8 +96,11 @@ export default class InstantTradeSellerTxBuilder extends InstantTradeBuilder { this.utxo = await this.verifyAndFindInscriptionUTXO() this.validateOwnership() + + await this.calculateRoyalty() + await this.generatSellerInputs() - await this.generateSellerOutputs() + this.generateSellerOutputs() await this.prepare() } diff --git a/packages/sdk/src/transactions/PSBTBuilder.ts b/packages/sdk/src/transactions/PSBTBuilder.ts index 20b82045..02c047e3 100644 --- a/packages/sdk/src/transactions/PSBTBuilder.ts +++ b/packages/sdk/src/transactions/PSBTBuilder.ts @@ -239,7 +239,7 @@ export class PSBTBuilder extends FeeEstimator { injectedIndexes.push(injectable.injectionIndex) }) - if (this.changeAmount > MINIMUM_AMOUNT_IN_SATS) { + if (this.changeAmount >= MINIMUM_AMOUNT_IN_SATS) { this.psbt.addOutput({ address: this.changeAddress || this.address, value: this.changeAmount