From 4f4b2c864d4977955d05142fa3e69616af0392a3 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Thu, 21 Oct 2021 19:11:55 -0700 Subject: [PATCH] fix(Transaction.get()): Adding support for MINT corner-case --- package-lock.json | 47 -------- src/transaction.js | 5 +- test/unit/fixtures/transaction-mock.js | 143 ++++++++++++++++++++++++- test/unit/transaction-unit.js | 47 ++++++++ 4 files changed, 191 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1aac330..90c8dec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8685,11 +8685,6 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", "dev": true, @@ -9524,11 +9519,6 @@ "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, "node_modules/npm/node_modules/performance-now": { "version": "2.1.0", "dev": true, @@ -9541,11 +9531,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", "dev": true, @@ -9754,18 +9739,6 @@ "node": ">=0.8" } }, - "node_modules/npm/node_modules/resolve": { - "version": "1.20.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", "dev": true, @@ -21067,10 +21040,6 @@ "bundled": true, "dev": true }, - "isarray": { - "version": "1.0.0", - "dev": true - }, "isexe": { "version": "2.0.0", "bundled": true, @@ -21682,10 +21651,6 @@ "bundled": true, "dev": true }, - "path-parse": { - "version": "1.0.7", - "dev": true - }, "performance-now": { "version": "2.1.0", "bundled": true, @@ -21696,10 +21661,6 @@ "bundled": true, "dev": true }, - "process-nextick-args": { - "version": "2.0.1", - "dev": true - }, "promise-all-reject-late": { "version": "1.0.1", "bundled": true, @@ -21854,14 +21815,6 @@ } } }, - "resolve": { - "version": "1.20.0", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, "retry": { "version": "0.12.0", "bundled": true, diff --git a/src/transaction.js b/src/transaction.js index 04e9ff5..679c663 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -127,11 +127,14 @@ class Transaction { tokenQty = inTokenData.qty // console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`) } + } else if (inTokenData.txType === 'MINT') { + // vout=1 (second output) recieves the newly minted tokens. + tokenQty = inTokenData.qty // } else { console.log( - 'Unexpected code path in Transaction.get(). Is this a MINT transaction?' + 'Unexpected code path in Transaction.get(). What is the txType?' ) console.log(inTokenData) throw new Error('Unexpected code path') diff --git a/test/unit/fixtures/transaction-mock.js b/test/unit/fixtures/transaction-mock.js index 3155d01..0e3f442 100644 --- a/test/unit/fixtures/transaction-mock.js +++ b/test/unit/fixtures/transaction-mock.js @@ -266,14 +266,117 @@ const genesisTestInputTx = { blocktime: 1534271330 } -genesisTestOpReturnData01 = { +const mintTestInputTx = { + txid: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa', + hash: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa', + version: 1, + size: 585, + locktime: 543613, + vin: [ + { + txid: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8', + vout: 1, + scriptSig: { + asm: '3045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2[ALL|FORKID] 02056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74', + hex: '483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74' + }, + sequence: 4294967294, + address: 'bitcoincash:qpaf9wltgmpjlg2vxwwu7zdw5y4z7m277ckxn8cufl', + value: 0.00000546, + tokenQtyStr: '43545.34534', + tokenQty: 43545.34534 + }, + { + txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34', + vout: 1, + scriptSig: { + asm: '3045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a[ALL|FORKID] 024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2', + hex: '483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2' + }, + sequence: 4294967294, + address: 'bitcoincash:qqf89zzwd0fqc3npkks997r5l7dpfjf9kgx2rqu500', + value: 0.00000546, + tokenQtyStr: '2.34123', + tokenQty: 2.34123 + }, + { + txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34', + vout: 3, + scriptSig: { + asm: '3044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae[ALL|FORKID] 02eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56', + hex: '473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56' + }, + sequence: 4294967294, + address: 'bitcoincash:qqt30r33k0jx3sxe34tmupaujpaljnglmvqgrrfp2x', + value: 0.00054848, + tokenQtyStr: '2.34123', + tokenQty: 2.34123 + } + ], + vout: [ + { + value: 0, + n: 0, + scriptPubKey: { + asm: 'OP_RETURN 5262419 1 1145980243 938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8 0000000103907f11', + hex: '6a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f11', + type: 'nulldata' + }, + tokenQty: null + }, + { + value: 0.00000546, + n: 1, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 059775ff94f65c04e8a6847e74eb9809d8cd779b OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: [ + 'bitcoincash:qqzewa0ljnm9cp8g56z8ua8tnqya3nthnvhv5hpu8y' + ] + }, + tokenQtyStr: '43547.68657', + tokenQty: 43547.68657 + }, + { + value: 0.00054808, + n: 2, + scriptPubKey: { + asm: 'OP_DUP OP_HASH160 0e330dc9009e1e07831f5a22d4ade8977ab674c8 OP_EQUALVERIFY OP_CHECKSIG', + hex: '76a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac', + reqSigs: 1, + type: 'pubkeyhash', + addresses: [ + 'bitcoincash:qq8rxrwfqz0pupurradz949dazth4dn5eqs3mhrucv' + ] + }, + tokenQty: null + } + ], + hex: '0100000003f8cda53b43b0ea49991a9bc6c74eb901d2a8b964bc7b8987d76789618ec18c93010000006b483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee010000006b483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee030000006a473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56feffffff030000000000000000376a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f1122020000000000001976a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac18d60000000000001976a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac7d4b0800', + blockhash: '00000000000000000140f0d813052da59c811a936494a8d8b2d60b215d19e3dc', + confirmations: 167007, + time: 1534391953, + blocktime: 1534391953, + isValidSLPTx: true, + tokenTxType: 'SEND', + tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8', + tokenTicker: 'Bubb2', + tokenName: 'the new bubbles!', + tokenDecimals: 5, + tokenUri: '', + tokenDocHash: '' +} + +const genesisTestOpReturnData01 = { tokenType: 1, txType: 'SEND', tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35', amounts: ['5000000', '5000000'] } -genesisTestOpReturnData02 = { +const genesisTestOpReturnData02 = { tokenType: 1, txType: 'GENESIS', ticker: '', @@ -286,6 +389,36 @@ genesisTestOpReturnData02 = { qty: '10000000' } +const mintTestOpReturnData01 = { + tokenType: 1, + txType: 'SEND', + tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8', + amounts: [ + '4354768657' + ] +} + +const mintTestOpReturnData02 = { + tokenType: 1, + txType: 'GENESIS', + ticker: 'Bubb2', + name: 'the new bubbles!', + tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8', + documentUri: '', + documentHash: '', + decimals: 5, + mintBatonVout: 2, + qty: '4354534534' +} + +const mintTestOpReturnData03 = { + tokenType: 1, + txType: 'MINT', + tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8', + mintBatonVout: 2, + qty: '234123' +} + module.exports = { nonSlpTxDetails, slpTxDetails, @@ -293,6 +426,10 @@ module.exports = { mockOpReturnData02, mockOpReturnData03, genesisTestInputTx, + mintTestInputTx, genesisTestOpReturnData01, - genesisTestOpReturnData02 + genesisTestOpReturnData02, + mintTestOpReturnData01, + mintTestOpReturnData02, + mintTestOpReturnData03 } diff --git a/test/unit/transaction-unit.js b/test/unit/transaction-unit.js index 749258e..a54de35 100644 --- a/test/unit/transaction-unit.js +++ b/test/unit/transaction-unit.js @@ -164,5 +164,52 @@ describe('#TransactionLib', () => { assert.equal(result.vin[0].tokenQty, 10000000) assert.equal(result.vin[1].tokenQty, null) }) + + it('should get input details when input is a mint tx', async () => { + // Mock dependencies + sandbox + .stub(bchjs.Transaction.rawTransaction, 'getTxData') + .resolves(mockData.mintTestInputTx) + sandbox + .stub(bchjs.Transaction.slpUtils, 'decodeOpReturn') + .onCall(0) + .resolves(mockData.mintTestOpReturnData01) + .onCall(1) + .resolves(mockData.mintTestOpReturnData02) + .onCall(2) + .resolves(mockData.mintTestOpReturnData02) + .onCall(3) + .resolves(mockData.mintTestOpReturnData03) + .onCall(4) + .resolves(mockData.mintTestOpReturnData03) + sandbox + .stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid') + .resolves(true) + + const txid = + '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa' + + const result = await bchjs.Transaction.get(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + // Assert that there are stanardized properties. + assert.property(result, 'txid') + assert.property(result, 'vin') + assert.property(result, 'vout') + assert.property(result.vout[0], 'value') + assert.property(result.vout[1].scriptPubKey, 'addresses') + + // Assert that added properties exist. + assert.property(result.vout[0], 'tokenQty') + assert.equal(result.vout[0].tokenQty, null) + assert.property(result.vin[0], 'address') + assert.property(result.vin[0], 'value') + assert.property(result.vin[0], 'tokenQty') + assert.property(result, 'isValidSLPTx') + assert.equal(result.isValidSLPTx, true) + + // Assert inputs values unique to a Mint input have the proper values. + assert.equal(result.vin[2].tokenQty, 2.34123) + }) }) })