Skip to content

Commit

Permalink
refactor(sdk): update royalty structure (#85)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
iamcrazycoder authored Oct 20, 2023
1 parent 0f6cd96 commit d5139f5
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 20 deletions.
35 changes: 31 additions & 4 deletions packages/sdk/src/instant-trade/InstantTradeBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<RoyaltyAttributes, "percentage"> & Partial<Pick<RoyaltyAttributes, "percentage">> & { 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() {
Expand Down
11 changes: 8 additions & 3 deletions packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
29 changes: 17 additions & 12 deletions packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}
}
Expand All @@ -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() {
Expand All @@ -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()
}
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/transactions/PSBTBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d5139f5

Please sign in to comment.