Skip to content

Commit

Permalink
feat(sdk): add sats and ownership check (#71)
Browse files Browse the repository at this point in the history
* restore: add flag to skip strict sats check

originally added in #65

* refactor: set decodeMetadata to false as default

* fix: use genesis txid to get inscription utxo

* fix: use different approach to get inscription utxo in buyer flow

* feat: add validation for ownership in seller flow

* fix: update legacy input size

* fix: don't fetch more utxos only when its external request

* feat: add customAmount to work w/ skipStrictSatsCheck
  • Loading branch information
iamcrazycoder authored Sep 27, 2023
1 parent 75adfb4 commit 10adba4
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 17 deletions.
8 changes: 4 additions & 4 deletions packages/sdk/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class OrditApi {
network = "testnet",
type = "spendable",
rarity = ["common"],
decodeMetadata = true,
decodeMetadata = false,
sort = "desc"
}: FetchUnspentUTXOsOptions): Promise<FetchUnspentUTXOsResponse> {
if (!address) {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class OrditApi {
ordinals = true,
hex = false,
witness = true,
decodeMetadata = true
decodeMetadata = false
}: FetchTxOptions): Promise<FetchTxResponse> {
if (!txId) {
throw new Error("Invalid txId")
Expand Down Expand Up @@ -118,7 +118,7 @@ export class OrditApi {
}
}

static async fetchInscriptions({ outpoint, network = "testnet", decodeMetadata = true }: GetInscriptionsOptions) {
static async fetchInscriptions({ outpoint, network = "testnet", decodeMetadata = false }: GetInscriptionsOptions) {
if (!outpoint) {
throw new Error("Invalid options provided.")
}
Expand All @@ -139,7 +139,7 @@ export class OrditApi {
return inscriptions
}

static async fetchInscription({ id, network = "testnet", decodeMetadata = true }: FetchInscriptionOptions) {
static async fetchInscription({ id, network = "testnet", decodeMetadata = false }: FetchInscriptionOptions) {
if (!id) {
throw new Error("Invalid options provided.")
}
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/fee/FeeEstimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export default class FeeEstimator {
return { input: 64, output: 32, txHeader: 10, witness: 105 }

case "legacy":
return { input: 149, output: 34, txHeader: 10, witness: 0 }
return { input: 148, output: 34, txHeader: 10, witness: 0 }

default:
throw new Error("Invalid type")
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/instant-trade/InstantTradeBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default class InstantTradeBuilder extends PSBTBuilder {
throw new Error("Inscription not found")
}

const utxo = await this.datasource.getInscriptionUTXO(this.inscription.outpoint)
const utxo = await this.datasource.getInscriptionUTXO(this.inscription.genesis)
if (!utxo) {
throw new Error(`Unable to find UTXO: ${this.inscription.outpoint}`)
}
Expand Down
15 changes: 14 additions & 1 deletion packages/sdk/src/instant-trade/InstantTradeBuyerTxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,20 @@ export default class InstantTradeBuyerTxBuilder extends InstantTradeBuilder {
}

async isEligible() {
const [utxos] = await Promise.all([this.findUTXOs(), this.verifyAndFindInscriptionUTXO()])
if (!this.inscriptionOutpoint) {
throw new Error("decode seller PSBT to check eligiblity")
}

const [utxos, [inscription]] = await Promise.all([
this.findUTXOs(),
this.datasource.getInscriptions({ outpoint: this.inscriptionOutpoint })
])
if (!inscription) {
throw new Error("Inscription no longer available for trade")
}
const inscriptionUTXO = await this.datasource.getInscriptionUTXO(inscription.id)
this.postage = inscriptionUTXO.sats

const sortedUTXOs = utxos.sort((a, b) => a.sats - b.sats)
const [refundableUTXOOne, refundableUTXOTwo, ...restUTXOs] = sortedUTXOs
const refundables = [refundableUTXOOne, refundableUTXOTwo].reduce((acc, curr) => (acc += curr.sats), 0)
Expand Down
7 changes: 7 additions & 0 deletions packages/sdk/src/instant-trade/InstantTradeSellerTxBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,19 @@ export default class InstantTradeSellerTxBuilder extends InstantTradeBuilder {
}
}

private validateOwnership() {
if (this.inscription?.owner !== this.address) {
throw new Error(`Inscription does not belong to the address: ${this.address}`)
}
}

async build() {
if (isNaN(this.price) || this.price < MINIMUM_AMOUNT_IN_SATS) {
throw new Error("Invalid price")
}

this.utxo = await this.verifyAndFindInscriptionUTXO()
this.validateOwnership()
await this.generatSellerInputs()
await this.generateSellerOutputs()

Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/modules/JsonRpcDatasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default class JsonRpcDatasource extends BaseDatasource {
ordinals = true,
hex = false,
witness = true,
decodeMetadata = true
decodeMetadata = false
}: FetchTxOptions) {
if (!txId) {
throw new Error("Invalid request")
Expand Down Expand Up @@ -128,7 +128,7 @@ export default class JsonRpcDatasource extends BaseDatasource {
address, // TODO rename interface
type = "spendable",
rarity = ["common"],
decodeMetadata = true,
decodeMetadata = false,
sort = "desc",
limit = 50,
next = null
Expand Down
14 changes: 9 additions & 5 deletions packages/sdk/src/transactions/Inscriber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { Network } from "../config/types"
import { NestedObject } from "../utils/types"
import { PSBTBuilder } from "./PSBTBuilder"
import { UTXOLimited } from "./types"
import { SkipStrictSatsCheckOptions, UTXOLimited } from "./types"

bitcoin.initEccLib(ecc)

Expand Down Expand Up @@ -241,12 +241,12 @@ export class Inscriber extends PSBTBuilder {
await this.calculateNetworkFeeUsingPreviewMode()
}

async isReady() {
async isReady({ skipStrictSatsCheck, customAmount }: SkipStrictSatsCheckOptions = {}) {
this.isBuilt()

if (!this.ready) {
try {
await this.fetchAndSelectSuitableUnspent()
await this.fetchAndSelectSuitableUnspent({ skipStrictSatsCheck, customAmount })
} catch (error) {
return false
}
Expand All @@ -255,11 +255,15 @@ export class Inscriber extends PSBTBuilder {
return this.ready
}

async fetchAndSelectSuitableUnspent() {
async fetchAndSelectSuitableUnspent({ skipStrictSatsCheck, customAmount }: SkipStrictSatsCheckOptions = {}) {
this.restrictUsageInPreviewMode()
this.isBuilt()

const amount = this.recovery ? this.outputAmount - this.fee : this.outputAmount + this.fee
const amount = this.recovery
? this.outputAmount - this.fee
: skipStrictSatsCheck && customAmount && !isNaN(customAmount)
? customAmount
: this.outputAmount + this.fee
const [utxo] = await this.retrieveSelectedUTXOs(this.commitAddress!, amount)
this.suitableUnspent = utxo
this.ready = true
Expand Down
8 changes: 5 additions & 3 deletions packages/sdk/src/transactions/PSBTBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,14 @@ export class PSBTBuilder extends FeeEstimator {
private async retrieveUTXOs(address?: string, amount?: number) {
if (!this.autoAdjustment && !address) return

amount = amount && amount > 0 ? amount : this.changeAmount < 0 ? this.changeAmount * -1 : this.outputAmount
const amountToRequest =
amount && amount > 0 ? amount : this.changeAmount < 0 ? this.changeAmount * -1 : this.outputAmount

if (this.getRetrievedUTXOsValue() > amount) return
if (amount && this.getRetrievedUTXOsValue() > amount) return

const utxos = await this.datasource.getSpendables({
address: address || this.address,
value: convertSatoshisToBTC(amount),
value: convertSatoshisToBTC(amountToRequest),
filter: this.getReservedUTXOs()
})

Expand All @@ -329,6 +330,7 @@ export class PSBTBuilder extends FeeEstimator {
protected async retrieveSelectedUTXOs(address: string, amount: number) {
await this.retrieveUTXOs(address, amount)
const selectedUTXOs = this.utxos.find((utxo) => utxo.sats >= amount)

this.utxos = selectedUTXOs ? [selectedUTXOs] : []

return this.utxos
Expand Down
5 changes: 5 additions & 0 deletions packages/sdk/src/transactions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,8 @@ export interface Output {
address: string
value: number
}

export interface SkipStrictSatsCheckOptions {
skipStrictSatsCheck?: boolean
customAmount?: number
}

0 comments on commit 10adba4

Please sign in to comment.