mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-21 16:51:59 -07:00
feat(decodeOpReturn2): Added slp-parser lib to create alternate decodeOpReturn
This commit is contained in:
Generated
+16
@@ -10130,6 +10130,22 @@
|
||||
"is-fullwidth-code-point": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"slp-mdm": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/slp-mdm/-/slp-mdm-0.0.6.tgz",
|
||||
"integrity": "sha512-fbjlIg/o8OtzgK2JydC6POJp3Qup/rLgy4yB5hoLgxWRlERyJyE29ScwS3r9TTwPxe12qK55pyivAdNOZZXL0A==",
|
||||
"requires": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"slp-parser": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/slp-parser/-/slp-parser-0.0.4.tgz",
|
||||
"integrity": "sha512-AvbslJumkzGfMGWNvuE2pWx2nyHEk/VgQ7l119kDKIFRTuRUWOkyOULLauw5laGRQsBRThg6NCx/TsR3grX6GA==",
|
||||
"requires": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
"repl.history": "^0.1.4",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"satoshi-bitcoin": "^1.0.4",
|
||||
"slp-mdm": "0.0.6",
|
||||
"slp-parser": "0.0.4",
|
||||
"socket.io": "^2.1.1",
|
||||
"socket.io-client": "^2.1.1",
|
||||
"touch": "^3.1.0",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const axios = require("axios")
|
||||
const slpParser = require("slp-parser")
|
||||
|
||||
const Script = require("../script")
|
||||
const scriptLib = new Script()
|
||||
@@ -11,6 +12,7 @@ class Utils {
|
||||
constructor(config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.slpParser = slpParser
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
@@ -939,6 +941,78 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.decodeOpReturn2() decodeOpReturn2() - Read the OP_RETURN data from an SLP transaction.
|
||||
* @apiName decodeOpReturn2
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Retrieves transactions data from a txid and decodes the SLP OP_RETURN data.
|
||||
*
|
||||
* Similar to decodeOpReturn(), except decodeOpReturn2() uses the slp-parser
|
||||
* library maintained by JT Freeman. Outputs have slightly different format.
|
||||
*
|
||||
* Throws an error if given a non-SLP txid.
|
||||
*
|
||||
*/
|
||||
// Reimplementation of decodeOpReturn() using slp-parser.
|
||||
async decodeOpReturn2(txid) {
|
||||
try {
|
||||
// Validate the txid input.
|
||||
if (!txid || txid === "" || typeof txid !== "string")
|
||||
throw new Error(`txid string must be included.`)
|
||||
|
||||
// Retrieve the transaction object from the full node.
|
||||
const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const txDetails = response.data
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
// SLP spec expects OP_RETURN to be the first output of the transaction.
|
||||
const opReturn = txDetails.vout[0].scriptPubKey.hex
|
||||
// console.log(`opReturn hex: ${opReturn}`)
|
||||
|
||||
const parsedData = _this.slpParser.parseSLP(Buffer.from(opReturn, "hex"))
|
||||
// console.log(`parsedData: ${JSON.stringify(parsedData, null, 2)}`)
|
||||
|
||||
// Convert Buffer data to hex strings or utf8 strings.
|
||||
let tokenData = {}
|
||||
if (parsedData.transactionType === "SEND") {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
tokenId: parsedData.data.tokenId.toString("hex"),
|
||||
amounts: parsedData.data.amounts
|
||||
}
|
||||
} else if (parsedData.transactionType === "GENESIS") {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
ticker: parsedData.data.ticker.toString(),
|
||||
name: parsedData.data.name.toString(),
|
||||
tokenId: txid,
|
||||
documentUri: parsedData.data.documentUri.toString(),
|
||||
documentHash: parsedData.data.documentHash.toString(),
|
||||
decimals: parsedData.data.decimals,
|
||||
mintBatonVout: parsedData.data.mintBatonVout,
|
||||
qty: parsedData.data.qty
|
||||
}
|
||||
} else if (parsedData.transactionType === "MINT") {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
tokenId: parsedData.data.tokenId.toString("hex"),
|
||||
mintBatonVout: parsedData.data.mintBatonVout,
|
||||
qty: parsedData.data.qty
|
||||
}
|
||||
}
|
||||
// console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
|
||||
return tokenData
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.isTokenUtxo() isTokenUtxo() - Determine if UTXO belongs to an SLP transaction.
|
||||
* @apiName isTokenUtxo
|
||||
|
||||
@@ -75,6 +75,156 @@ describe(`#SLP`, () => {
|
||||
"spendData"
|
||||
])
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
||||
const txid =
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"transactionType",
|
||||
"ticker",
|
||||
"name",
|
||||
"documentUrl",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"mintBatonVout",
|
||||
"initialQty",
|
||||
"tokensSentTo",
|
||||
"batonHolder"
|
||||
])
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a MINT txid", async () => {
|
||||
const txid =
|
||||
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"transactionType",
|
||||
"tokenId",
|
||||
"mintBatonVout",
|
||||
"batonStillExists",
|
||||
"quantity",
|
||||
"tokensSentTo",
|
||||
"batonHolder"
|
||||
])
|
||||
})
|
||||
|
||||
it("should throw an error for a non-SLP transaction", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "Not an OP_RETURN")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeOpReturn2", () => {
|
||||
it("should decode the OP_RETURN for a SEND txid", async () => {
|
||||
const txid =
|
||||
"266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
)
|
||||
|
||||
// Verify outputs
|
||||
assert.equal(result.amounts.length, 2)
|
||||
assert.equal(result.amounts[0], "100000000")
|
||||
assert.equal(result.amounts[1], "99883300000000")
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
||||
const txid =
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"ticker",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
)
|
||||
assert.equal(result.txType, "GENESIS")
|
||||
assert.equal(result.ticker, "TOK-CH")
|
||||
assert.equal(result.name, "TokyoCash")
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a MINT txid", async () => {
|
||||
const txid =
|
||||
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
})
|
||||
|
||||
it("should throw an error for a non-SLP transaction", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn2(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "scriptpubkey not op_return")
|
||||
}
|
||||
})
|
||||
|
||||
// Note: This TX is interpreted as valid by the original decodeOpReturn().
|
||||
// Fixing this issue and related issues was the reason for creating the
|
||||
// decodeOpReturn2() method using the slp-parser library.
|
||||
it("should throw error for invalid SLP transaction", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "amount string size not 8 bytes")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokenUtxoDetails", () => {
|
||||
|
||||
@@ -944,6 +944,93 @@ const mockDualOpData = {
|
||||
]
|
||||
}
|
||||
|
||||
const mockInvalidSlpSend = {
|
||||
txid: "a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415",
|
||||
hash: "a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415",
|
||||
version: 2,
|
||||
size: 473,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: "3ad621d46ddb7bdccb6e5e7b6505ee639d9327a2b2bdaa2937b8e3aa55c4f2a7",
|
||||
vout: 0,
|
||||
scriptSig: {
|
||||
asm:
|
||||
"3045022100f962fdc585261007f114f0470828bbe9ac6197cefc4d0897fe4a7dd1d4cb2f5402202e104b617a1c14fc293c0ace9d4fd5e1cfa819a68b4ff976b4c3c199feda5227[ALL|FORKID] 0351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fb",
|
||||
hex:
|
||||
"483045022100f962fdc585261007f114f0470828bbe9ac6197cefc4d0897fe4a7dd1d4cb2f5402202e104b617a1c14fc293c0ace9d4fd5e1cfa819a68b4ff976b4c3c199feda522741210351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fb"
|
||||
},
|
||||
sequence: 4294967295
|
||||
},
|
||||
{
|
||||
txid: "a31c3167686f892d835727bc46b74bb11a46d74a8a6b08dc6cd82abb6e987b43",
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
"3044022027dcd4ef752819ba4e61b892039ea0cb8d3ab0ffaeb78384dce9cf43dd76967e0220594fdf41e3d26cd207b6df939e3d655f6e09b01f05948edeb096aa644e1b6ec4[ALL|FORKID] 0351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fb",
|
||||
hex:
|
||||
"473044022027dcd4ef752819ba4e61b892039ea0cb8d3ab0ffaeb78384dce9cf43dd76967e0220594fdf41e3d26cd207b6df939e3d655f6e09b01f05948edeb096aa644e1b6ec441210351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fb"
|
||||
},
|
||||
sequence: 4294967295
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_RETURN 5262419 1 1145980243 091c80cee60cc3a6dd7b8c6c04cf0cf2d8103ba2d75daa105dcf1aaa53551fe8 1 fffffffffffffffe",
|
||||
hex:
|
||||
"6a04534c500001010453454e4420091c80cee60cc3a6dd7b8c6c04cf0cf2d8103ba2d75daa105dcf1aaa53551fe8010108fffffffffffffffe",
|
||||
type: "nulldata"
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 c0c53d84b5420c9bfe4015d1ae69017c3f1ddef8 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914c0c53d84b5420c9bfe4015d1ae69017c3f1ddef888ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bitcoincash:qrqv20vyk4pqexl7gq2artnfq97r78w7lqj5548mny"]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 b505afc357a7e911b207332f13e8e674a72099c3 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914b505afc357a7e911b207332f13e8e674a72099c388ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bitcoincash:qz6stt7r27n7jydjquej7ylgue62wgyecvs9zm4gff"]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00044091,
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
"OP_DUP OP_HASH160 b505afc357a7e911b207332f13e8e674a72099c3 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
hex: "76a914b505afc357a7e911b207332f13e8e674a72099c388ac",
|
||||
reqSigs: 1,
|
||||
type: "pubkeyhash",
|
||||
addresses: ["bitcoincash:qz6stt7r27n7jydjquej7ylgue62wgyecvs9zm4gff"]
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
"0200000002a7f2c455aae3b83729aabdb2a227939d63ee05657b5e6ecbdc7bdb6dd421d63a000000006b483045022100f962fdc585261007f114f0470828bbe9ac6197cefc4d0897fe4a7dd1d4cb2f5402202e104b617a1c14fc293c0ace9d4fd5e1cfa819a68b4ff976b4c3c199feda522741210351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fbffffffff437b986ebb2ad86cdc086b8a4ad7461ab14bb746bc2757832d896f6867311ca3010000006a473044022027dcd4ef752819ba4e61b892039ea0cb8d3ab0ffaeb78384dce9cf43dd76967e0220594fdf41e3d26cd207b6df939e3d655f6e09b01f05948edeb096aa644e1b6ec441210351c450ded2d7747dcad69982c9d954f3f785bab018d89fa09723bba7397e91fbffffffff040000000000000000396a04534c500001010453454e4420091c80cee60cc3a6dd7b8c6c04cf0cf2d8103ba2d75daa105dcf1aaa53551fe8010108fffffffffffffffe22020000000000001976a914c0c53d84b5420c9bfe4015d1ae69017c3f1ddef888ac22020000000000001976a914b505afc357a7e911b207332f13e8e674a72099c388ac3bac0000000000001976a914b505afc357a7e911b207332f13e8e674a72099c388ac00000000",
|
||||
blockhash: "000000000000000000915bd33a7241f34800b190f7cf51f90b42b2b05d2b7ed8",
|
||||
confirmations: 90327,
|
||||
time: 1535577007,
|
||||
blocktime: 1535577007
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockList,
|
||||
mockToken,
|
||||
@@ -966,5 +1053,6 @@ module.exports = {
|
||||
txDetailsSLPSendAlt,
|
||||
mockTxDetails,
|
||||
mockDualValidation,
|
||||
mockDualOpData
|
||||
mockDualOpData,
|
||||
mockInvalidSlpSend
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ describe("#SLP TokenType1", () => {
|
||||
5000
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result.script: `, result.script)
|
||||
console.log(`result.script: `, result.script)
|
||||
console.log(`result.script: `, result.script.toString("hex"))
|
||||
|
||||
// This transaction failed due to a floating point error. This is expressed
|
||||
// by the script[6] being length 2 (incorrect) instead of 8 (correct).
|
||||
|
||||
@@ -525,6 +525,187 @@ describe("#SLP Utils", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeOpReturn2", () => {
|
||||
it("should throw an error for a non-string input", async () => {
|
||||
try {
|
||||
const txid = 53423 // Not a string.
|
||||
|
||||
await slp.Utils.decodeOpReturn2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result.")
|
||||
} catch (err) {
|
||||
//console.log(`err: ${util.inspect(err)}`)
|
||||
assert2.include(err.message, `txid string must be included`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw an error for non-SLP transaction", async () => {
|
||||
try {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.nonSLPTxDetailsWithoutOpReturn })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
|
||||
await slp.Utils.decodeOpReturn2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result.")
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
assert2.include(err.message, `scriptpubkey not op_return`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw an error for non-SLP transaction with OP_RETURN", async () => {
|
||||
try {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.nonSLPTxDetailsWithOpReturn })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"2ff74c48a5d657cf45f699601990bffbbe7a2a516d5480674cbf6c6a4497908f"
|
||||
|
||||
await slp.Utils.decodeOpReturn2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result.")
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
assert2.include(err.message, `SLP not in first chunk`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should decode a genesis transaction", async () => {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.txDetailsSLPGenesis })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90"
|
||||
|
||||
const result = await slp.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"ticker",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
})
|
||||
|
||||
it("should decode a mint transaction", async () => {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit")
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.txDetailsSLPMint })
|
||||
|
||||
const txid =
|
||||
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
|
||||
const result = await slp.Utils.decodeOpReturn2(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
})
|
||||
|
||||
it("should decode a send transaction", async () => {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit")
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.txDetailsSLPSend })
|
||||
|
||||
const txid =
|
||||
"4f922565af664b6fdf0a1ba3924487344be721b3d8815c62cafc8a51e04a8afa"
|
||||
|
||||
const result = await slp.Utils.decodeOpReturn2(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
|
||||
})
|
||||
|
||||
it("should properly decode a Genesis transaction with no minting baton", async () => {
|
||||
// Mock the call to the REST API.
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.txDetailsSLPGenesisNoBaton })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
|
||||
const data = await slp.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert2.equal(data.mintBatonVout, 0)
|
||||
})
|
||||
|
||||
it("should decode a send transaction with alternate encoding", async () => {
|
||||
// Mock the call to rest.bitcoin.com
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.txDetailsSLPSendAlt })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"d94357179775425ebc59c93173bd6dc9854095f090a2eb9dcfe9797398bc8eae"
|
||||
|
||||
const data = await slp.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert2.hasAnyKeys(data, [
|
||||
"transactionType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"amounts"
|
||||
])
|
||||
})
|
||||
|
||||
// Note: This TX is interpreted as valid by the original decodeOpReturn().
|
||||
// Fixing this issue and related issues was the reason for creating the
|
||||
// decodeOpReturn2() method using the slp-parser library.
|
||||
it("should throw error for invalid SLP transaction", async () => {
|
||||
try {
|
||||
// Mock the call to rest.bitcoin.com
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.mockInvalidSlpSend })
|
||||
}
|
||||
|
||||
const txid =
|
||||
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
|
||||
|
||||
await slp.Utils.decodeOpReturn2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert2.include(err.message, "amount string size not 8 bytes")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#isTokenUtxo", () => {
|
||||
it("should throw error if input is not an array.", async () => {
|
||||
try {
|
||||
@@ -1277,4 +1458,14 @@ describe("#SLP Utils", () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
// describe("#decodeOpReturn2", () => {
|
||||
// it("should do something", async () => {
|
||||
// const txid =
|
||||
// "4f922565af664b6fdf0a1ba3924487344be721b3d8815c62cafc8a51e04a8afa"
|
||||
//
|
||||
// await slp.Utils.decodeOpReturn2(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user