Skip to content

Commit

Permalink
feat(inscriberV2): support delegates (#123)
Browse files Browse the repository at this point in the history
* feat(inscriberV2): support delegates

* check for empty string
  • Loading branch information
kevzzsk authored Jul 29, 2024
1 parent ec85938 commit 6edd246
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 54 deletions.
8 changes: 5 additions & 3 deletions packages/sdk/src/inscription/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export async function bulkMintFromCollection({
inscriptionList: EnvelopeOpts[]
}>(
(acc, insc) => {
const { nonce, mediaContent, mediaType, receiverAddress, postage, iid,signature } = insc
const { nonce, mediaContent, mediaType, delegateInscriptionId, receiverAddress, postage, iid, signature } = insc

const meta = buildMeta({
collectionGenesis,
Expand All @@ -152,6 +152,7 @@ export async function bulkMintFromCollection({
const inscriptionEnvelope: EnvelopeOpts = {
mediaContent,
mediaType,
delegateInscriptionId,
pointer: currentPointer === 0 ? undefined : currentPointer.toString(),
receiverAddress,
postage
Expand Down Expand Up @@ -271,8 +272,9 @@ export type BulkMintFromCollectionOptions = {

export type InscriptionsToMint = {
nonce: number
mediaContent: string
mediaType: string
mediaContent?: string
mediaType?: string
delegateInscriptionId?: string
receiverAddress: string
postage: number
iid: string
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/src/inscription/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export function trimTrailingZeroBytes(buffer: Buffer): Buffer {
trimmedBuffer = buffer.subarray(0, i + 1)
break
}
if (i === 0) {
// if all bytes are zero, return an empty buffer
trimmedBuffer = Buffer.alloc(0)
}
}
return trimmedBuffer
}
Expand Down
12 changes: 8 additions & 4 deletions packages/sdk/src/inscription/witness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,14 @@ export const buildEnvelope = function ({delegateInscriptionId,mediaContent,media
]

if (pointer) {
baseStackElements.push(
INSCRIPTION_FIELD_TAG.Pointer,
encodePointer(pointer)
)
const encodedPointer = encodePointer(pointer)
if (!encodedPointer.equals(Buffer.alloc(0))) {
// only push pointer tag if it is not 0
baseStackElements.push(
INSCRIPTION_FIELD_TAG.Pointer,
encodedPointer
)
}
}

if (delegateInscriptionId) {
Expand Down
86 changes: 42 additions & 44 deletions packages/sdk/src/transactions/InscriberV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { SkipStrictSatsCheckOptions, UTXOLimited } from "./types"

bitcoin.initEccLib(ecc)

type BuildWitnessParams = { xKey: string; inscriptions: EnvelopeOpts[]; metaInscriptions: EnvelopeOpts[] }

export class InscriberV2 extends PSBTBuilder {
protected taptreeVersion?: TaptreeVersion = "3"

Expand All @@ -35,16 +37,7 @@ export class InscriberV2 extends PSBTBuilder {
readonly metaInscriptions: EnvelopeOpts[]
readonly inscriptions: EnvelopeOpts[]

private witnessScripts: Record<
"recovery" | "inscriptions" | "metaInscriptions" | "inscriptionLegacy" | "metaInscriptionLegacy",
Buffer | null
> = {
inscriptions: null,
metaInscriptions: null,
inscriptionLegacy: null,
metaInscriptionLegacy: null,
recovery: null
}
private witnessScripts: ReturnType<typeof this.buildWitnessScripts>
private taprootTree!: Taptree

constructor({
Expand Down Expand Up @@ -77,6 +70,8 @@ export class InscriberV2 extends PSBTBuilder {
this.metaInscriptions = metaInscriptions ?? []
this.inscriptions = inscriptions ?? []
this.isStandard = isStandard ?? true

this.witnessScripts = this.buildWitnessScripts({ xKey: this.xKey, inscriptions, metaInscriptions })
}

get data() {
Expand Down Expand Up @@ -148,54 +143,57 @@ export class InscriberV2 extends PSBTBuilder {
}
}

buildWitness() {
this.witnessScripts = {
inscriptions: buildWitnessScriptV2({
xkey: this.xKey,
envelopes: this.inscriptions
}),
metaInscriptions: buildWitnessScriptV2({
xkey: this.xKey,
envelopes: this.metaInscriptions
}),
inscriptionLegacy: buildWitnessScript({
mediaContent: this.inscriptions[0].mediaContent!,
mediaType: this.inscriptions[0].mediaType!,
meta: false,
xkey: this.xKey
}),
metaInscriptionLegacy: buildWitnessScript({
mediaContent: this.inscriptions[0].mediaContent!,
mediaType: this.inscriptions[0].mediaType!,
meta: JSON.parse(this.metaInscriptions[0].mediaContent!),
xkey: this.xKey
}),
recovery: buildRecoverWitnessScript(this.xKey)
buildWitnessScripts({ xKey, inscriptions, metaInscriptions }: BuildWitnessParams) {
return {
inscriptions: () =>
buildWitnessScriptV2({
xkey: xKey,
envelopes: inscriptions
}),
metaInscriptions: () =>
buildWitnessScriptV2({
xkey: xKey,
envelopes: metaInscriptions
}),
inscriptionLegacy: () =>
buildWitnessScript({
mediaContent: inscriptions[0].mediaContent!,
mediaType: inscriptions[0].mediaType!,
meta: false,
xkey: xKey
}),
metaInscriptionLegacy: () =>
buildWitnessScript({
mediaContent: inscriptions[0].mediaContent!,
mediaType: inscriptions[0].mediaType!,
meta: JSON.parse(metaInscriptions[0].mediaContent!),
xkey: xKey
}),
recovery: () => buildRecoverWitnessScript(xKey)
}
}

buildTaprootTree() {
this.buildWitness()
switch (this.taptreeVersion) {
case "3":
// v3 allows for multiple/single inscription minting (without meta) and remains unique based on the meta (OIP-2 specs)
this.taprootTree = [
[{ output: this.witnessScripts.recovery! }, { output: this.witnessScripts.metaInscriptions! }],
{ output: this.witnessScripts.inscriptions! }
[{ output: this.witnessScripts.recovery() }, { output: this.witnessScripts.metaInscriptions() }],
{ output: this.witnessScripts.inscriptions() }
]
break
case "2":
// v2 allows for inscription only minting (without meta) and remains unique based on the meta (OIP-2 specs)
this.taprootTree = [
[{ output: this.witnessScripts.recovery! }, { output: this.witnessScripts.metaInscriptionLegacy! }],
{ output: this.witnessScripts.inscriptionLegacy! }
[{ output: this.witnessScripts.recovery() }, { output: this.witnessScripts.metaInscriptionLegacy() }],
{ output: this.witnessScripts.inscriptionLegacy() }
]
break
case "1":
// v1 allows for inscription (with meta) and recovery minting (OIP-2 specs)
this.taprootTree = [
{ output: this.witnessScripts.metaInscriptionLegacy! },
{ output: this.witnessScripts.recovery! }
{ output: this.witnessScripts.metaInscriptionLegacy() },
{ output: this.witnessScripts.recovery() }
]
break
default:
Expand All @@ -207,17 +205,17 @@ export class InscriberV2 extends PSBTBuilder {
switch (this.taptreeVersion) {
case "3":
return {
output: this.witnessScripts.inscriptions!,
output: this.witnessScripts.inscriptions(),
redeemVersion: 192
}
case "2":
return {
output: this.witnessScripts.inscriptionLegacy!,
output: this.witnessScripts.inscriptionLegacy(),
redeemVersion: 192
}
case "1":
return {
output: this.witnessScripts.metaInscriptionLegacy!,
output: this.witnessScripts.metaInscriptionLegacy(),
redeemVersion: 192
}
default:
Expand All @@ -227,7 +225,7 @@ export class InscriberV2 extends PSBTBuilder {

getRecoveryRedeemScript(): bitcoin.payments.Payment["redeem"] {
return {
output: this.witnessScripts.recovery!,
output: this.witnessScripts.recovery(),
redeemVersion: 192
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,12 @@ export function getDummyP2TRInput(): UTXO {
}

export const splitInscriptionId = (inscriptionId: string) => {
const [txId, index] = inscriptionId.split(":")
const [txId, index] = inscriptionId.split("i")
if (txId.length !== 64) {
throw new OrditSDKError(`Invalid inscriptionId: ${inscriptionId}`)
}
const indexNum = parseInt(index, 10)
if (Number.isNaN(indexNum) || indexNum < 0) {
const indexNum = Number(index)
if (Number.isNaN(indexNum) || indexNum < 0 || index !== "") {
throw new OrditSDKError(`Invalid inscriptionId: ${inscriptionId}`)
}

Expand Down

0 comments on commit 6edd246

Please sign in to comment.