Shibescribe your own Doginal
  • Installing Dogecoin Core
  • Shibescribe
  • RPC CONFIG
  • ShibeScribe from your own Node
  • code
  • dogecoin core
  • Download Doginals
  • Visual Studio Code
Powered by GitBook
On this page

code

Bulk

#!/bin/bash

#check that 3 arguments are passed in otherwise exit
if [ "$#" -ne 3 ]; then
    echo "Illegal number of parameters"
    echo "Usage: bulk-mint.sh <max_count> <target_address> <token_name>"
    exit 1
fi

count=0
max_count=$1
target_address=$2
token_name=$3
while [ $count -lt $max_count ]; do
    echo "Current count: $count"
    node . drc-20 mint "$target_address" "$token_name" 1000 12
    remaining=$((max_count - count))
    echo "Counts left: $remaining"
    sleep 200  # Sleep for 3,5 minutes
    ((count++))
done

Doginals.js

const dogecore = require('bitcore-lib-doge')
const axios = require('axios')
const fs = require('fs')
const dotenv = require('dotenv')
const mime = require('mime-types')
const express = require('express')
const { PrivateKey, Address, Transaction, Script, Opcode } = dogecore
const { Hash, Signature } = dogecore.crypto
const protobuf = require('protobufjs')
const Long = require('long')

const API_URL = 'https://dogetest-explorer.dogelayer.org/api/v2/'
const MAX_SCRIPT_ELEMENT_SIZE = 520
const DRC20_P = 1

const DRC20_OP_MAP = {
  deploy: 1,
  mint: 2,
  transfer: 3
}

dotenv.config()

if (process.env.FEE_PER_KB) {
  Transaction.FEE_PER_KB = parseInt(process.env.FEE_PER_KB)
} else {
  Transaction.FEE_PER_KB = 100000000
}

const WALLET_PATH = process.env.WALLET || '.wallet.json'

const CONTENT_TYPE = 'application/x-protobuf'
// const CONTENT_TYPE = "text/plain;charset=utf-8"

// var proto_type_drc
var proto_type_drc20

function buffer2hex (buffer) {
  // buffer is an ArrayBuffer
  return [...new Uint8Array(buffer)]
    .map(x => x.toString(16).padStart(2, '0'))
    .join('')
}

async function main () {
  var root = await protobuf.load('drc.proto')

  // proto_type_drc = root.lookupType('drc.drc')
  proto_type_drc20 = root.lookupType('drc.drc20')

  if (process.env.TESTNET == 'true') {
    dogecore.Networks.defaultNetwork = dogecore.Networks.testnet
  } else {
    throw new Error('Only support testnet.')
  }

  let cmd = process.argv[2]

  if (fs.existsSync('pending-txs.json')) {
    console.log('found pending-txs.json. rebroadcasting...')
    const txs = JSON.parse(fs.readFileSync('pending-txs.json'))
    await broadcastAll(
      txs.map(tx => new Transaction(tx)),
      false
    )
    return
  }

  if (cmd == 'mint') {
    await mint()
  } else if (cmd == 'wallet') {
    await wallet()
  } else if (cmd == 'server') {
    await server()
  } else if (cmd == 'drc-20') {
    await doge20()
  } else {
    throw new Error(`unknown command: ${cmd}`)
  }
}

async function doge20 () {
  let subcmd = process.argv[3]

  if (subcmd === 'mint') {
    await doge20Transfer('mint')
  } else if (subcmd === 'transfer') {
    await doge20Transfer()
  } else if (subcmd === 'deploy') {
    await doge20Deploy()
  } else {
    throw new Error(`unknown subcommand: ${subcmd}`)
  }
}

async function doge20Deploy () {
  const argAddress = process.argv[4]
  const argTicker = process.argv[5]
  const argMax = process.argv[6]
  const argLimit = process.argv[7]

  // const doge20Tx = {
  //   p: 'drc-20',
  //   op: 'deploy',
  //   tick: `${argTicker.toLowerCase()}`,
  //   max: `${argMax}`,
  //   lim: `${argLimit}`
  // }

  // const parsedDoge20Tx = JSON.stringify(doge20Tx)

  // // encode the doge20Tx as hex string
  // const encodedDoge20Tx = Buffer.from(parsedDoge20Tx).toString('hex')
  const op = 'deploy'
  const doge20Tx = proto_type_drc20.create({
    p: DRC20_P,
    op: DRC20_OP_MAP[op],
    tick: `${argTicker.toLowerCase()}`,
    max: Long.fromString(argMax, true),
    lim: Long.fromString(argLimit, true)
  })
  const encodedDoge20Tx = proto_type_drc20.encode(doge20Tx).finish()

  console.log('Deploying drc-20 token...')
  await mint(argAddress, CONTENT_TYPE, buffer2hex(encodedDoge20Tx))
}

async function doge20Transfer (op = 'transfer') {
  const argAddress = process.argv[4]
  const argTicker = process.argv[5]
  const argAmount = process.argv[6]
  const argRepeat = Number(process.argv[7]) || 1

  // const doge20Tx = {
  //   p: 'drc-20',
  //   op,
  //   tick: `${argTicker.toLowerCase()}`,
  //   amt: `${argAmount}`
  // }

  // const parsedDoge20Tx = JSON.stringify(doge20Tx)

  // // encode the doge20Tx as hex string
  // const encodedDoge20Tx = Buffer.from(parsedDoge20Tx).toString('hex')

  const doge20Tx = proto_type_drc20.create({
    p: DRC20_P,
    op: DRC20_OP_MAP[op],
    tick: `${argTicker.toLowerCase()}`,
    amt: Long.fromString(argAmount, true)
  })
  const encodedDoge20Tx = proto_type_drc20.encode(doge20Tx).finish()

  for (let i = 0; i < argRepeat; i++) {
    console.log('Minting drc-20 token...', i + 1, 'of', argRepeat, 'times')
    await mint(argAddress, CONTENT_TYPE, buffer2hex(encodedDoge20Tx))
  }
}

async function wallet () {
  let subcmd = process.argv[3]

  if (subcmd == 'new') {
    walletNew()
  } else if (subcmd == 'sync') {
    await walletSync()
  } else if (subcmd == 'balance') {
    walletBalance()
  } else if (subcmd == 'send') {
    await walletSend()
  } else if (subcmd == 'split') {
    await walletSplit()
  } else {
    throw new Error(`unknown subcommand: ${subcmd}`)
  }
}

function walletNew () {
  if (!fs.existsSync(WALLET_PATH)) {
    const privateKey = new PrivateKey()
    const privkey = privateKey.toWIF()
    const address = privateKey.toAddress().toString()
    const json = { privkey, address, utxos: [] }
    fs.writeFileSync(WALLET_PATH, JSON.stringify(json, 0, 2))
    console.log('address', address)
  } else {
    throw new Error('wallet already exists')
  }
}

async function walletSync () {
  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))
  console.log('syncing utxos with dogelayer.org api')

  let response = await axios.get(API_URL + 'utxo/' + wallet.address)
  wallet.utxos = response.data.map(output => {
    return {
      txid: output.txid,
      vout: output.vout,
      script: Script.buildPublicKeyHashOut(wallet.address).toHex(),
      satoshis: Number(output.value)
    }
  })

  fs.writeFileSync(WALLET_PATH, JSON.stringify(wallet, 0, 2))
  let balance = wallet.utxos.reduce((acc, curr) => acc + curr.satoshis, 0)
  console.log('balance', balance)
}

function walletBalance () {
  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))
  let balance = wallet.utxos.reduce((acc, curr) => acc + curr.satoshis, 0)
  console.log(wallet.address, balance)
}

async function walletSend () {
  const argAddress = process.argv[4]
  const argAmount = process.argv[5]

  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))

  let balance = wallet.utxos.reduce((acc, curr) => acc + curr.satoshis, 0)
  if (balance == 0) throw new Error('no funds to send')

  let receiver = new Address(argAddress)
  let amount = parseInt(argAmount)

  let tx = new Transaction()
  if (amount) {
    tx.to(receiver, amount)
    fund(wallet, tx)
  } else {
    tx.from(wallet.utxos)
    tx.change(receiver)
    tx.sign(wallet.privkey)
  }

  await broadcast(tx, true)
  console.log('tx hash: ', tx.hash)
}

async function walletSplit () {
  let splits = parseInt(process.argv[4])

  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))

  let balance = wallet.utxos.reduce((acc, curr) => acc + curr.satoshis, 0)
  if (balance == 0) throw new Error('no funds to split')

  let tx = new Transaction()
  tx.from(wallet.utxos)
  for (let i = 0; i < splits - 1; i++) {
    tx.to(wallet.address, Math.floor(balance / splits))
  }
  tx.change(wallet.address)
  tx.sign(wallet.privkey)

  await broadcast(tx, true)

  console.log(tx.hash)
}

async function mint (paramAddress, paramContentTypeOrFilename, paramHexData) {
  const argAddress = paramAddress || process.argv[3]
  const argContentTypeOrFilename = paramContentTypeOrFilename || process.argv[4]
  const argHexData = paramHexData || process.argv[5]

  let address = new Address(argAddress)
  let contentType
  let data

  if (fs.existsSync(argContentTypeOrFilename)) {
    contentType = mime.contentType(mime.lookup(argContentTypeOrFilename))
    data = fs.readFileSync(argContentTypeOrFilename)
  } else {
    contentType = argContentTypeOrFilename
    if (!/^[a-fA-F0-9]*$/.test(argHexData)) throw new Error('data must be hex')
    data = Buffer.from(argHexData, 'hex')
  }

  if (data.length == 0) {
    throw new Error('no data to mint')
  }

  if (contentType.length > MAX_SCRIPT_ELEMENT_SIZE) {
    throw new Error('content type too long')
  }

  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))

  let txs = inscribe(wallet, address, contentType, data)

  await broadcastAll(txs, false)
}

async function broadcastAll (txs, retry) {
  for (let i = 0; i < txs.length; i++) {
    console.log(`broadcasting tx ${i + 1} of ${txs.length}`)

    try {
      await broadcast(txs[i], retry)
    } catch (e) {
      console.log('broadcast failed', e?.response.data)
      if (
        e?.response?.data.error?.message?.includes('bad-txns-inputs-spent') ||
        e?.response?.data.error?.message?.includes('already in block chain')
      ) {
        console.log('tx already sent, skipping')
        continue
      }
      console.log('saving pending txs to pending-txs.json')
      console.log('to reattempt broadcast, re-run the command')
      fs.writeFileSync(
        'pending-txs.json',
        JSON.stringify(txs.slice(i).map(tx => tx.toString()))
      )
      process.exit(1)
    }
  }

  try {
    fs.unlinkSync('pending-txs.json')
  } catch (err) {
    // ignore
  }

  if (txs.length > 1) {
    console.log('inscription txid:', txs[1].hash)
  }
}

function bufferToChunk (b, type) {
  b = Buffer.from(b, type)
  return {
    buf: b.length ? b : undefined,
    len: b.length,
    opcodenum: b.length <= 75 ? b.length : b.length <= 255 ? 76 : 77
  }
}

function numberToChunk (n) {
  return {
    buf:
      n <= 16
        ? undefined
        : n < 128
        ? Buffer.from([n])
        : Buffer.from([n % 256, n / 256]),
    len: n <= 16 ? 0 : n < 128 ? 1 : 2,
    opcodenum: n == 0 ? 0 : n <= 16 ? 80 + n : n < 128 ? 1 : 2
  }
}

function opcodeToChunk (op) {
  return { opcodenum: op }
}

const MAX_CHUNK_LEN = 240
const MAX_PAYLOAD_LEN = 1500

function inscribe (wallet, address, contentType, data) {
  let txs = []

  let privateKey = new PrivateKey(wallet.privkey)
  let publicKey = privateKey.toPublicKey()

  let parts = []
  while (data.length) {
    let part = data.slice(0, Math.min(MAX_CHUNK_LEN, data.length))
    data = data.slice(part.length)
    parts.push(part)
  }

  let inscription = new Script()
  inscription.chunks.push(bufferToChunk('ord'))
  inscription.chunks.push(numberToChunk(parts.length))
  inscription.chunks.push(bufferToChunk(contentType))
  parts.forEach((part, n) => {
    inscription.chunks.push(numberToChunk(parts.length - n - 1))
    inscription.chunks.push(bufferToChunk(part))
  })

  let p2shInput
  let lastLock
  let lastPartial

  while (inscription.chunks.length) {
    let partial = new Script()

    if (txs.length == 0) {
      partial.chunks.push(inscription.chunks.shift())
    }

    while (
      partial.toBuffer().length <= MAX_PAYLOAD_LEN &&
      inscription.chunks.length
    ) {
      partial.chunks.push(inscription.chunks.shift())
      partial.chunks.push(inscription.chunks.shift())
    }

    if (partial.toBuffer().length > MAX_PAYLOAD_LEN) {
      inscription.chunks.unshift(partial.chunks.pop())
      inscription.chunks.unshift(partial.chunks.pop())
    }

    let lock = new Script()
    lock.chunks.push(bufferToChunk(publicKey.toBuffer()))
    lock.chunks.push(opcodeToChunk(Opcode.OP_CHECKSIGVERIFY))
    partial.chunks.forEach(() => {
      lock.chunks.push(opcodeToChunk(Opcode.OP_DROP))
    })
    lock.chunks.push(opcodeToChunk(Opcode.OP_TRUE))

    let lockhash = Hash.ripemd160(Hash.sha256(lock.toBuffer()))

    let p2sh = new Script()
    p2sh.chunks.push(opcodeToChunk(Opcode.OP_HASH160))
    p2sh.chunks.push(bufferToChunk(lockhash))
    p2sh.chunks.push(opcodeToChunk(Opcode.OP_EQUAL))

    let p2shOutput = new Transaction.Output({
      script: p2sh,
      satoshis: 100000
    })

    let tx = new Transaction()
    if (p2shInput) tx.addInput(p2shInput)
    tx.addOutput(p2shOutput)
    fund(wallet, tx)

    if (p2shInput) {
      let signature = Transaction.sighash.sign(
        tx,
        privateKey,
        Signature.SIGHASH_ALL,
        0,
        lastLock
      )
      let txsignature = Buffer.concat([
        signature.toBuffer(),
        Buffer.from([Signature.SIGHASH_ALL])
      ])

      let unlock = new Script()
      unlock.chunks = unlock.chunks.concat(lastPartial.chunks)
      unlock.chunks.push(bufferToChunk(txsignature))
      unlock.chunks.push(bufferToChunk(lastLock.toBuffer()))
      tx.inputs[0].setScript(unlock)
    }

    updateWallet(wallet, tx)
    txs.push(tx)

    p2shInput = new Transaction.Input({
      prevTxId: tx.hash,
      outputIndex: 0,
      output: tx.outputs[0],
      script: ''
    })

    p2shInput.clearSignatures = () => {}
    p2shInput.getSignatures = () => {}

    lastLock = lock
    lastPartial = partial
  }

  let tx = new Transaction()
  tx.addInput(p2shInput)
  tx.to(address, 100000)
  fund(wallet, tx)

  let signature = Transaction.sighash.sign(
    tx,
    privateKey,
    Signature.SIGHASH_ALL,
    0,
    lastLock
  )
  let txsignature = Buffer.concat([
    signature.toBuffer(),
    Buffer.from([Signature.SIGHASH_ALL])
  ])

  let unlock = new Script()
  unlock.chunks = unlock.chunks.concat(lastPartial.chunks)
  unlock.chunks.push(bufferToChunk(txsignature))
  unlock.chunks.push(bufferToChunk(lastLock.toBuffer()))
  tx.inputs[0].setScript(unlock)

  updateWallet(wallet, tx)
  txs.push(tx)

  return txs
}

function fund (wallet, tx) {
  tx.change(wallet.address)
  delete tx._fee

  for (const utxo of wallet.utxos) {
    // console.log("get fee:",tx.getFee())
    if (utxo.satoshis <= 1000000) {
      continue
    }
    if (
      tx.inputs.length &&
      tx.outputs.length &&
      tx.inputAmount >= tx.outputAmount + tx.getFee()
    ) {
      break
    }

    delete tx._fee
    tx.from(utxo)

    tx.change(wallet.address)
    tx.sign(wallet.privkey)
  }

  if (tx.inputAmount < tx.outputAmount + tx.getFee()) {
    throw new Error('not enough funds')
  }
}

function updateWallet (wallet, tx) {
  wallet.utxos = wallet.utxos.filter(utxo => {
    for (const input of tx.inputs) {
      if (
        input.prevTxId.toString('hex') == utxo.txid &&
        input.outputIndex == utxo.vout
      ) {
        return false
      }
    }
    return true
  })

  tx.outputs.forEach((output, vout) => {
    if (output.script.toAddress().toString() == wallet.address) {
      wallet.utxos.push({
        txid: tx.hash,
        vout,
        script: output.script.toHex(),
        satoshis: output.satoshis
      })
    }
  })
}

async function broadcast_dogelayer_api (tx) {
  try {
    const response = await axios.post(API_URL + 'sendtx/', tx.toString())
    console.log(response.data)
  } catch (e) {
    console.log(e)
    return
  }

  let wallet = JSON.parse(fs.readFileSync(WALLET_PATH))
  updateWallet(wallet, tx)
  fs.writeFileSync(WALLET_PATH, JSON.stringify(wallet, 0, 2))
}

async function broadcast (tx, retry = 0) {
  return broadcast_dogelayer_api(tx)
}

function chunkToNumber (chunk) {
  if (chunk.opcodenum == 0) return 0
  if (chunk.opcodenum == 1) return chunk.buf[0]
  if (chunk.opcodenum == 2) return chunk.buf[1] * 255 + chunk.buf[0]
  if (chunk.opcodenum > 80 && chunk.opcodenum <= 96) return chunk.opcodenum - 80
  return undefined
}

async function getAddressTxs (address) {
  let { data } = await axios.get(
    API_URL + '/address/' + address + '?details=txs'
  )
  txs = data.transactions
  return txs
}

function findSpendTx (txs, txid, n) {
  for (tx of txs) {
    for (vin of tx.vin) {
      if (vin.txid == txid && vin.n == n) {
        return tx.txid
      }
    }
  }
  return null
}

async function extract (txid) {
  let resp = await axios.get(API_URL + 'tx/' + txid)
  let transaction = resp.data
  let script = Script.fromHex(transaction.vin[0].hex)
  let chunks = script.chunks

  let prefix = chunks.shift().buf.toString('utf-8')
  if (prefix != 'ord') {
    throw new Error('not a doginal')
  }

  let pieces = chunkToNumber(chunks.shift())

  let contentType = chunks.shift().buf.toString('utf-8')

  let data = Buffer.alloc(0)
  let remaining = pieces

  // TODO: optimise finding all tx in series
  while (remaining && chunks.length) {
    let n = chunkToNumber(chunks.shift())

    if (n !== remaining - 1) {
      const txs = await getAddressTxs(transaction.vout[0].addresses[0])
      txid = findSpendTx(txs, transaction.txid, 0)
      console.log('next tx: ', txid)
      resp = await axios.get(API_URL + 'tx/' + txid)
      transaction = resp.data
      script = Script.fromHex(transaction.vin[0].hex)
      chunks = script.chunks
      continue
    }

    data = Buffer.concat([data, chunks.shift().buf])
    remaining -= 1
  }

  return {
    contentType,
    data
  }
}

function server () {
  const app = express()
  const port = process.env.SERVER_PORT
    ? parseInt(process.env.SERVER_PORT)
    : 3000

  app.get('/tx/:txid', (req, res) => {
    extract(req.params.txid)
      .then(result => {
        res.setHeader('content-type', result.contentType)
        res.send(result.data)
      })
      .catch(e => res.send(e.message))
  })

  app.listen(port, () => {
    console.log(`Listening on port ${port}`)
    console.log()
    console.log(`Example:`)
    console.log(
      `http://localhost:${port}/tx/b201783a8e5c8f98f40b250c28f666d16db105ae663efa70132a9eddc6f2e804`
    )
  })
}

main().catch(e => {
  let reason =
    e.response &&
    e.response.data &&
    e.response.data.error &&
    e.response.data.error.message
  console.error(reason ? e.message + ':' + reason : e.message)
})

drc

syntax = "proto3";
package drc;
option go_package = "drc/drc";

message drc {
    uint32 p = 1;
}

message drc20 {
    uint32 p = 1;
    uint32 op = 2;
    string tick = 3;
    uint64 max = 4;
    uint64 lim = 5;
    uint64 amt = 6;
}

packagle lock

{
  "name": "doginals",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "doginals",
      "version": "1.0.0",
      "license": "MIT",
      "dependencies": {
        "axios": "^1.3.4",
        "bitcore-lib-doge": "^8.25.46",
        "dotenv": "^16.0.3",
        "express": "^4.18.2",
        "long": "^5.2.3",
        "mime-types": "^2.1.35",
        "protobufjs": "~7.2.5"
      },
      "bin": {
        "doginals": "doginals.js"
      }
    },
    "node_modules/@protobufjs/aspromise": {
      "version": "1.1.2",
      "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
    },
    "node_modules/@protobufjs/base64": {
      "version": "1.1.2",
      "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz",
      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
    },
    "node_modules/@protobufjs/codegen": {
      "version": "2.0.4",
      "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.4.tgz",
      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
    },
    "node_modules/@protobufjs/eventemitter": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
    },
    "node_modules/@protobufjs/fetch": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.0.tgz",
      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
      "dependencies": {
        "@protobufjs/aspromise": "^1.1.1",
        "@protobufjs/inquire": "^1.1.0"
      }
    },
    "node_modules/@protobufjs/float": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz",
      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
    },
    "node_modules/@protobufjs/inquire": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@protobufjs/inquire/-/inquire-1.1.0.tgz",
      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
    },
    "node_modules/@protobufjs/path": {
      "version": "1.1.2",
      "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz",
      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
    },
    "node_modules/@protobufjs/pool": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz",
      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
    },
    "node_modules/@protobufjs/utf8": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.0.tgz",
      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
    },
    "node_modules/@types/node": {
      "version": "20.10.4",
      "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.10.4.tgz",
      "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==",
      "dependencies": {
        "undici-types": "~5.26.4"
      }
    },
    "node_modules/accepts": {
      "version": "1.3.8",
      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
      "dependencies": {
        "mime-types": "~2.1.34",
        "negotiator": "0.6.3"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/array-flatten": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
    },
    "node_modules/asynckit": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
    },
    "node_modules/axios": {
      "version": "1.3.4",
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
      "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
      "dependencies": {
        "follow-redirects": "^1.15.0",
        "form-data": "^4.0.0",
        "proxy-from-env": "^1.1.0"
      }
    },
    "node_modules/base-x": {
      "version": "3.0.9",
      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
      "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      }
    },
    "node_modules/bitcore-lib-doge": {
      "version": "8.25.46",
      "resolved": "https://registry.npmjs.org/bitcore-lib-doge/-/bitcore-lib-doge-8.25.46.tgz",
      "integrity": "sha512-J0ib5q0iCbw7A0Mx6sRYnzB9biOn23bK7tFOV0tzDNx45MlZEU6Le6lQ8lOy2aBZjBYFyXejCAKisQ5X/HnpeA==",
      "dependencies": {
        "bn.js": "=4.11.8",
        "bs58": "^4.0.1",
        "buffer-compare": "=1.1.1",
        "elliptic": "^6.5.3",
        "inherits": "=2.0.1",
        "lodash": "^4.17.20",
        "scryptsy": "2.1.0"
      }
    },
    "node_modules/bn.js": {
      "version": "4.11.8",
      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
      "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
    },
    "node_modules/body-parser": {
      "version": "1.20.1",
      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
      "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
      "dependencies": {
        "bytes": "3.1.2",
        "content-type": "~1.0.4",
        "debug": "2.6.9",
        "depd": "2.0.0",
        "destroy": "1.2.0",
        "http-errors": "2.0.0",
        "iconv-lite": "0.4.24",
        "on-finished": "2.4.1",
        "qs": "6.11.0",
        "raw-body": "2.5.1",
        "type-is": "~1.6.18",
        "unpipe": "1.0.0"
      },
      "engines": {
        "node": ">= 0.8",
        "npm": "1.2.8000 || >= 1.4.16"
      }
    },
    "node_modules/brorand": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
      "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="
    },
    "node_modules/bs58": {
      "version": "4.0.1",
      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
      "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
      "dependencies": {
        "base-x": "^3.0.2"
      }
    },
    "node_modules/buffer-compare": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
      "integrity": "sha512-O6NvNiHZMd3mlIeMDjP6t/gPG75OqGPeiRZXoMQZJ6iy9GofCls4Ijs5YkPZZwoysizLiedhticmdyx/GyHghA=="
    },
    "node_modules/bytes": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/call-bind": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
      "dependencies": {
        "function-bind": "^1.1.1",
        "get-intrinsic": "^1.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/combined-stream": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
      "dependencies": {
        "delayed-stream": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/content-disposition": {
      "version": "0.5.4",
      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
      "dependencies": {
        "safe-buffer": "5.2.1"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/content-type": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/cookie": {
      "version": "0.5.0",
      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/cookie-signature": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
    },
    "node_modules/debug": {
      "version": "2.6.9",
      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
      "dependencies": {
        "ms": "2.0.0"
      }
    },
    "node_modules/delayed-stream": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/depd": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/destroy": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
      "engines": {
        "node": ">= 0.8",
        "npm": "1.2.8000 || >= 1.4.16"
      }
    },
    "node_modules/dotenv": {
      "version": "16.0.3",
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
      "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/ee-first": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
    },
    "node_modules/elliptic": {
      "version": "6.5.4",
      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
      "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
      "dependencies": {
        "bn.js": "^4.11.9",
        "brorand": "^1.1.0",
        "hash.js": "^1.0.0",
        "hmac-drbg": "^1.0.1",
        "inherits": "^2.0.4",
        "minimalistic-assert": "^1.0.1",
        "minimalistic-crypto-utils": "^1.0.1"
      }
    },
    "node_modules/elliptic/node_modules/bn.js": {
      "version": "4.12.0",
      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
      "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
    },
    "node_modules/elliptic/node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    },
    "node_modules/encodeurl": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/escape-html": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
    },
    "node_modules/etag": {
      "version": "1.8.1",
      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/express": {
      "version": "4.18.2",
      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
      "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
      "dependencies": {
        "accepts": "~1.3.8",
        "array-flatten": "1.1.1",
        "body-parser": "1.20.1",
        "content-disposition": "0.5.4",
        "content-type": "~1.0.4",
        "cookie": "0.5.0",
        "cookie-signature": "1.0.6",
        "debug": "2.6.9",
        "depd": "2.0.0",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "finalhandler": "1.2.0",
        "fresh": "0.5.2",
        "http-errors": "2.0.0",
        "merge-descriptors": "1.0.1",
        "methods": "~1.1.2",
        "on-finished": "2.4.1",
        "parseurl": "~1.3.3",
        "path-to-regexp": "0.1.7",
        "proxy-addr": "~2.0.7",
        "qs": "6.11.0",
        "range-parser": "~1.2.1",
        "safe-buffer": "5.2.1",
        "send": "0.18.0",
        "serve-static": "1.15.0",
        "setprototypeof": "1.2.0",
        "statuses": "2.0.1",
        "type-is": "~1.6.18",
        "utils-merge": "1.0.1",
        "vary": "~1.1.2"
      },
      "engines": {
        "node": ">= 0.10.0"
      }
    },
    "node_modules/finalhandler": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
      "dependencies": {
        "debug": "2.6.9",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "on-finished": "2.4.1",
        "parseurl": "~1.3.3",
        "statuses": "2.0.1",
        "unpipe": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/follow-redirects": {
      "version": "1.15.2",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
      "funding": [
        {
          "type": "individual",
          "url": "https://github.com/sponsors/RubenVerborgh"
        }
      ],
      "engines": {
        "node": ">=4.0"
      },
      "peerDependenciesMeta": {
        "debug": {
          "optional": true
        }
      }
    },
    "node_modules/form-data": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
      "dependencies": {
        "asynckit": "^0.4.0",
        "combined-stream": "^1.0.8",
        "mime-types": "^2.1.12"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/forwarded": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/fresh": {
      "version": "0.5.2",
      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
    },
    "node_modules/get-intrinsic": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
      "dependencies": {
        "function-bind": "^1.1.1",
        "has": "^1.0.3",
        "has-symbols": "^1.0.3"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
      "dependencies": {
        "function-bind": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4.0"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hash.js": {
      "version": "1.1.7",
      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
      "dependencies": {
        "inherits": "^2.0.3",
        "minimalistic-assert": "^1.0.1"
      }
    },
    "node_modules/hash.js/node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    },
    "node_modules/hmac-drbg": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
      "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
      "dependencies": {
        "hash.js": "^1.0.3",
        "minimalistic-assert": "^1.0.0",
        "minimalistic-crypto-utils": "^1.0.1"
      }
    },
    "node_modules/http-errors": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
      "dependencies": {
        "depd": "2.0.0",
        "inherits": "2.0.4",
        "setprototypeof": "1.2.0",
        "statuses": "2.0.1",
        "toidentifier": "1.0.1"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/http-errors/node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    },
    "node_modules/iconv-lite": {
      "version": "0.4.24",
      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
      "dependencies": {
        "safer-buffer": ">= 2.1.2 < 3"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/inherits": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
      "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA=="
    },
    "node_modules/ipaddr.js": {
      "version": "1.9.1",
      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
      "engines": {
        "node": ">= 0.10"
      }
    },
    "node_modules/lodash": {
      "version": "4.17.21",
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
    },
    "node_modules/long": {
      "version": "5.2.3",
      "resolved": "https://registry.npmmirror.com/long/-/long-5.2.3.tgz",
      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
    },
    "node_modules/media-typer": {
      "version": "0.3.0",
      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/merge-descriptors": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
      "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
    },
    "node_modules/methods": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
      "bin": {
        "mime": "cli.js"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/mime-db": {
      "version": "1.52.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.35",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
      "dependencies": {
        "mime-db": "1.52.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/minimalistic-assert": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
    },
    "node_modules/minimalistic-crypto-utils": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
      "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="
    },
    "node_modules/ms": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
    },
    "node_modules/negotiator": {
      "version": "0.6.3",
      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/object-inspect": {
      "version": "1.12.3",
      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/on-finished": {
      "version": "2.4.1",
      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
      "dependencies": {
        "ee-first": "1.1.1"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/parseurl": {
      "version": "1.3.3",
      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/path-to-regexp": {
      "version": "0.1.7",
      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
    },
    "node_modules/protobufjs": {
      "version": "7.2.5",
      "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.2.5.tgz",
      "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==",
      "hasInstallScript": true,
      "dependencies": {
        "@protobufjs/aspromise": "^1.1.2",
        "@protobufjs/base64": "^1.1.2",
        "@protobufjs/codegen": "^2.0.4",
        "@protobufjs/eventemitter": "^1.1.0",
        "@protobufjs/fetch": "^1.1.0",
        "@protobufjs/float": "^1.0.2",
        "@protobufjs/inquire": "^1.1.0",
        "@protobufjs/path": "^1.1.2",
        "@protobufjs/pool": "^1.1.0",
        "@protobufjs/utf8": "^1.1.0",
        "@types/node": ">=13.7.0",
        "long": "^5.0.0"
      },
      "engines": {
        "node": ">=12.0.0"
      }
    },
    "node_modules/proxy-addr": {
      "version": "2.0.7",
      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
      "dependencies": {
        "forwarded": "0.2.0",
        "ipaddr.js": "1.9.1"
      },
      "engines": {
        "node": ">= 0.10"
      }
    },
    "node_modules/proxy-from-env": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
    },
    "node_modules/qs": {
      "version": "6.11.0",
      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
      "dependencies": {
        "side-channel": "^1.0.4"
      },
      "engines": {
        "node": ">=0.6"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/range-parser": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/raw-body": {
      "version": "2.5.1",
      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
      "dependencies": {
        "bytes": "3.1.2",
        "http-errors": "2.0.0",
        "iconv-lite": "0.4.24",
        "unpipe": "1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/safe-buffer": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ]
    },
    "node_modules/safer-buffer": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
    },
    "node_modules/scryptsy": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz",
      "integrity": "sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w=="
    },
    "node_modules/send": {
      "version": "0.18.0",
      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
      "dependencies": {
        "debug": "2.6.9",
        "depd": "2.0.0",
        "destroy": "1.2.0",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "fresh": "0.5.2",
        "http-errors": "2.0.0",
        "mime": "1.6.0",
        "ms": "2.1.3",
        "on-finished": "2.4.1",
        "range-parser": "~1.2.1",
        "statuses": "2.0.1"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/send/node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
    },
    "node_modules/serve-static": {
      "version": "1.15.0",
      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
      "dependencies": {
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "parseurl": "~1.3.3",
        "send": "0.18.0"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/setprototypeof": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
    },
    "node_modules/side-channel": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
      "dependencies": {
        "call-bind": "^1.0.0",
        "get-intrinsic": "^1.0.2",
        "object-inspect": "^1.9.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/statuses": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/toidentifier": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
      "engines": {
        "node": ">=0.6"
      }
    },
    "node_modules/type-is": {
      "version": "1.6.18",
      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
      "dependencies": {
        "media-typer": "0.3.0",
        "mime-types": "~2.1.24"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/undici-types": {
      "version": "5.26.5",
      "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
    },
    "node_modules/unpipe": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/utils-merge": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
      "engines": {
        "node": ">= 0.4.0"
      }
    },
    "node_modules/vary": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
      "engines": {
        "node": ">= 0.8"
      }
    }
  }
}

{
  "name": "doginals",
  "version": "1.0.0",
  "description": "A minter and protocol for inscriptions on Dogecoin",
  "main": "doginals.js",
  "author": "apezord",
  "license": "MIT",
  "bin": {
    "doginals": "doginals.js"
  },
  "dependencies": {
    "axios": "^1.3.4",
    "bitcore-lib-doge": "^8.25.46",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "long": "^5.2.3",
    "mime-types": "^2.1.35",
    "protobufjs": "~7.2.5"
  }
}

script decode

const dogecore = require('bitcore-lib-doge')
const { PrivateKey, Address, Transaction, Script, Opcode } = dogecore


var script_hex = "5a0047304402205f332933f0cd494279687552a66bdeac0a013cccf29f886a9dcdec7fc97d636f022037669b7e28d7bddbc4f32bbba39aed0eaaac03544b8c4b6b0a1f9b9203c851ca014c855121038f426d53820987467278a02af8b4fe4dd78988151fe7d07ebe65bc4ab7ca058351ae036f726418746578742f706c61696e3b636861727365743d7574662d383e7b22616d74223a2233353030303030303030222c226f70223a226d696e74222c2270223a226472632d3230222c227469636b223a22444f4745504144227d75757575"

s = Script(script_hex)

console.log(s.toString())
console.log("\n")


script_hex = "5121038f426d53820987467278a02af8b4fe4dd78988151fe7d07ebe65bc4ab7ca058351ae036f726418746578742f706c61696e3b636861727365743d7574662d383e7b22616d74223a2233353030303030303030222c226f70223a226d696e74222c2270223a226472632d3230222c227469636b223a22444f4745504144227d75757575"

s = Script(script_hex)

console.log(s.toString())
PreviousShibeScribe from your own Node

Last updated 1 year ago