Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711122
D12367.id36037.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Subscribers
None
D12367.id36037.diff
View Options
diff --git a/web/cashtab/src/components/Airdrop/Airdrop.js b/web/cashtab/src/components/Airdrop/Airdrop.js
--- a/web/cashtab/src/components/Airdrop/Airdrop.js
+++ b/web/cashtab/src/components/Airdrop/Airdrop.js
@@ -26,6 +26,7 @@
convertToEcashPrefix,
convertEcashtoEtokenAddr,
} from 'utils/cashMethods';
+import { getMintAddress } from 'utils/chronik';
import {
isValidTokenId,
isValidXecAirdrop,
@@ -255,6 +256,7 @@
// extract the eToken mint address
let genesisTx;
try {
+ // bch-api approach
genesisTx = await bchObj.RawTransactions.getRawTransaction(
formData.tokenId,
true,
@@ -270,12 +272,43 @@
passLoadingStatus(false);
return;
}
+
+ // Chronik approach
+ let mintEtokenAddressChronik;
+ try {
+ mintEtokenAddressChronik = await getMintAddress(
+ chronik,
+ bchObj,
+ formData.tokenId,
+ );
+ } catch (err) {
+ console.log(`Error in getMintAddress`, err);
+ errorNotification(
+ null,
+ 'Unable to retrieve minting address for eToken ID: ' +
+ formData.tokenId,
+ 'getMintAddress Error',
+ );
+ setIsAirdropCalcModalVisible(false);
+ passLoadingStatus(false);
+ return;
+ }
+
+ // bch-api address conversion
const mintEcashAddress = convertToEcashPrefix(
genesisTx.vout[1].scriptPubKey.addresses[0],
); //vout[0] is always the OP_RETURN output
const mintEtokenAddress =
convertEcashtoEtokenAddr(mintEcashAddress);
+ // Compare
+ if (mintEtokenAddressChronik === mintEtokenAddress) {
+ console.log(
+ `Chronik and bch-api got the same minting address`,
+ mintEtokenAddressChronik,
+ );
+ }
+
// remove the mint address from the recipients list
airdropList.delete(mintEtokenAddress);
}
diff --git a/web/cashtab/src/utils/__mocks__/chronikMintTxs.js b/web/cashtab/src/utils/__mocks__/chronikMintTxs.js
new file mode 100644
--- /dev/null
+++ b/web/cashtab/src/utils/__mocks__/chronikMintTxs.js
@@ -0,0 +1,251 @@
+export const mintingTxTabCash = {
+ txid: '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e',
+ version: 2,
+ inputs: [
+ {
+ prevOut: {
+ txid: 'be38b0488679e25823b7a72b925ac695a7b486e7f78122994b913f3079b0b939',
+ outIdx: 2,
+ },
+ inputScript:
+ '483045022100e28006843eb071ec6d8dd105284f2ca625a28f4dc85418910b59a5ab13fc6c2002205921fb12b541d1cd1a63e7e012aca5735df3398525f64bac04337d21029413614121034509251caa5f01e2787c436949eb94d71dcc451bcde5791ae5b7109255f5f0a3',
+ outputScript: '76a914b8d9512d2adf8b4e70c45c26b6b00d75c28eaa9688ac',
+ value: '91048',
+ sequenceNo: 4294967295,
+ slpBurn: {
+ token: {
+ amount: '0',
+ isMintBaton: false,
+ },
+ tokenId:
+ 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba',
+ },
+ },
+ ],
+ outputs: [
+ {
+ value: '0',
+ outputScript:
+ '6a04534c500001010747454e455349530354424307746162636173681768747470733a2f2f636173687461626170702e636f6d2f4c0001000102080000000000000064',
+ },
+ {
+ value: '546',
+ outputScript: '76a914b8d9512d2adf8b4e70c45c26b6b00d75c28eaa9688ac',
+ slpToken: {
+ amount: '100',
+ isMintBaton: false,
+ },
+ spentBy: {
+ txid: '618d0dd8c0c5fa5a34c6515c865dd72bb76f8311cd6ee9aef153bab20dabc0e6',
+ outIdx: 1,
+ },
+ },
+ {
+ value: '546',
+ outputScript: '76a914b8d9512d2adf8b4e70c45c26b6b00d75c28eaa9688ac',
+ slpToken: {
+ amount: '0',
+ isMintBaton: true,
+ },
+ },
+ {
+ value: '89406',
+ outputScript: '76a914b8d9512d2adf8b4e70c45c26b6b00d75c28eaa9688ac',
+ spentBy: {
+ txid: '618d0dd8c0c5fa5a34c6515c865dd72bb76f8311cd6ee9aef153bab20dabc0e6',
+ outIdx: 0,
+ },
+ },
+ ],
+ lockTime: 0,
+ slpTxData: {
+ slpMeta: {
+ tokenType: 'FUNGIBLE',
+ txType: 'GENESIS',
+ tokenId:
+ '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e',
+ },
+ genesisInfo: {
+ tokenTicker: 'TBC',
+ tokenName: 'tabcash',
+ tokenDocumentUrl: 'https://cashtabapp.com/',
+ tokenDocumentHash: '',
+ decimals: 0,
+ },
+ },
+ block: {
+ height: 674143,
+ hash: '000000000000000034c77993a35c74fe2dddace27198681ca1e89e928d0c2fff',
+ timestamp: '1613859311',
+ },
+ timeFirstSeen: '0',
+ size: 336,
+ isCoinbase: false,
+ network: 'XEC',
+};
+export const mintingHash160TabCash = 'b8d9512d2adf8b4e70c45c26b6b00d75c28eaa96';
+export const mintingAddressBchFormatTabCash =
+ 'bitcoincash:qzudj5fd9t0cknnsc3wzdd4sp46u9r42jcnqnwfss0';
+export const mintingAddressTabCash =
+ 'etoken:qzudj5fd9t0cknnsc3wzdd4sp46u9r42jcynw8ydj0';
+
+export const mintingTxPoW = {
+ txid: 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a',
+ version: 2,
+ inputs: [
+ {
+ prevOut: {
+ txid: '33938d6bd403e4ffef94de3e9e2ba487f095dcba3544ac8fad4a93808cea0116',
+ outIdx: 1,
+ },
+ inputScript:
+ '483045022100dad1d237b541b4a4d29197dbb01fa9755c2e17bbafb42855f38442b428f0df6b02205772d3fb00b7a053b07169e1534770c091fce42b9e1d63199f46ff89856b3fc6412102ceb4a6eca1eec20ff8e7780326932e8d8295489628c7f2ec9acf8f37f639235e',
+ outputScript: '76a91485bab3680833cd9b3cc60953344fa740a2235bbd88ac',
+ value: '49998867',
+ sequenceNo: 4294967295,
+ },
+ ],
+ outputs: [
+ {
+ value: '0',
+ outputScript:
+ '6a04534c500001010747454e4553495303504f571850726f6f666f6657726974696e672e636f6d20546f6b656e2168747470733a2f2f7777772e70726f6f666f6677726974696e672e636f6d2f32364c0001004c000800000000000f4240',
+ },
+ {
+ value: '546',
+ outputScript: '76a91485bab3680833cd9b3cc60953344fa740a2235bbd88ac',
+ slpToken: {
+ amount: '1000000',
+ isMintBaton: false,
+ },
+ spentBy: {
+ txid: '69238630eb9e6a9864bf6970ff5d326800cea41a819feebecfe1a6f0ed651f5c',
+ outIdx: 1,
+ },
+ },
+ {
+ value: '49997563',
+ outputScript: '76a91485bab3680833cd9b3cc60953344fa740a2235bbd88ac',
+ spentBy: {
+ txid: '3c665488929f852d93a5dfb6e4b4df7bc8f7a25fb4a2480d39e3de7a30437f69',
+ outIdx: 0,
+ },
+ },
+ ],
+ lockTime: 0,
+ slpTxData: {
+ slpMeta: {
+ tokenType: 'FUNGIBLE',
+ txType: 'GENESIS',
+ tokenId:
+ 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a',
+ },
+ genesisInfo: {
+ tokenTicker: 'POW',
+ tokenName: 'ProofofWriting.com Token',
+ tokenDocumentUrl: 'https://www.proofofwriting.com/26',
+ tokenDocumentHash: '',
+ decimals: 0,
+ },
+ },
+ block: {
+ height: 685949,
+ hash: '0000000000000000436e71d5291d2fb067decc838dcb85a99ff6da1d28b89fad',
+ timestamp: '1620712051',
+ },
+ timeFirstSeen: '0',
+ size: 329,
+ isCoinbase: false,
+ network: 'XEC',
+};
+export const mintingHash160PoW = '85bab3680833cd9b3cc60953344fa740a2235bbd';
+export const mintingAddressBchFormatPoW =
+ 'bitcoincash:qzzm4vmgpqeumxeuccy4xdz05aq2yg6mh52phz3zy5';
+export const mintingAddressPoW =
+ 'etoken:qzzm4vmgpqeumxeuccy4xdz05aq2yg6mh5aj2tulx5';
+
+export const mintingTxAlita = {
+ txid: '54dc2ecd5251f8dfda4c4f15ce05272116b01326076240e2b9cc0104d33b1484',
+ version: 2,
+ inputs: [
+ {
+ prevOut: {
+ txid: '72eeff7b43dc066164d92e4c3fece47af3a40e89d46e893df1647cd29dd9f1e3',
+ outIdx: 0,
+ },
+ inputScript:
+ '473044022075166617aa473e86c72f34a5576029eb8766a035b481864ebc75759155efcce00220147e2d7e662123bd728fac700f109a245a0278959f65fc402a1e912e0a5732004121034cdb43b7a1277c4d818dc177aaea4e0bed5d464d240839d5488a278b716facd5',
+ outputScript: '76a914f5f740bc76e56b77bcab8b4d7f888167f416fc6888ac',
+ value: '1000',
+ sequenceNo: 4294967295,
+ },
+ {
+ prevOut: {
+ txid: '46b6f61ca026e243d55668bf304df6a21e1fcb2113943cc6bd1fdeceaae85612',
+ outIdx: 2,
+ },
+ inputScript:
+ '4830450221009e98db4b91441190bb7e4745b9f249201d0b54c81c0a816af5f3491ffb21a7e902205a4d1347a5a9133c14e4f55319af00f1df836eba6552f30b44640e9373f4cabf4121034cdb43b7a1277c4d818dc177aaea4e0bed5d464d240839d5488a278b716facd5',
+ outputScript: '76a914f5f740bc76e56b77bcab8b4d7f888167f416fc6888ac',
+ value: '750918004',
+ sequenceNo: 4294967295,
+ },
+ ],
+ outputs: [
+ {
+ value: '0',
+ outputScript:
+ '6a04534c500001010747454e4553495305416c69746105416c6974610a616c6974612e636173684c0001044c00080000befe6f672000',
+ },
+ {
+ value: '546',
+ outputScript: '76a914f5f740bc76e56b77bcab8b4d7f888167f416fc6888ac',
+ slpToken: {
+ amount: '210000000000000',
+ isMintBaton: false,
+ },
+ spentBy: {
+ txid: '2c336374c05f1c8f278d2a1d5f3195a17fe1bc50189ff67c9769a6afcd908ea9',
+ outIdx: 1,
+ },
+ },
+ {
+ value: '750917637',
+ outputScript: '76a914f5f740bc76e56b77bcab8b4d7f888167f416fc6888ac',
+ spentBy: {
+ txid: 'ca70157d5cf6275e0a36adbc3fabf671e3987f343cb35ec4ee7ed5c8d37b3233',
+ outIdx: 0,
+ },
+ },
+ ],
+ lockTime: 0,
+ slpTxData: {
+ slpMeta: {
+ tokenType: 'FUNGIBLE',
+ txType: 'GENESIS',
+ tokenId:
+ '54dc2ecd5251f8dfda4c4f15ce05272116b01326076240e2b9cc0104d33b1484',
+ },
+ genesisInfo: {
+ tokenTicker: 'Alita',
+ tokenName: 'Alita',
+ tokenDocumentUrl: 'alita.cash',
+ tokenDocumentHash: '',
+ decimals: 4,
+ },
+ },
+ block: {
+ height: 756373,
+ hash: '00000000000000000d62f1b66c08f0976bcdec2f08face2892ae4474b50100d9',
+ timestamp: '1662611972',
+ },
+ timeFirstSeen: '1662611666',
+ size: 436,
+ isCoinbase: false,
+ network: 'XEC',
+};
+export const mintingHash160Alita = 'f5f740bc76e56b77bcab8b4d7f888167f416fc68';
+export const mintingAddressBchFormatAlita =
+ 'bitcoincash:qr6lws9uwmjkkaau4w956lugs9nlg9hudqf8w5lusm';
+export const mintingAddressAlita =
+ 'etoken:qr6lws9uwmjkkaau4w956lugs9nlg9hudq75najpjm';
diff --git a/web/cashtab/src/utils/__tests__/chronik.test.js b/web/cashtab/src/utils/__tests__/chronik.test.js
--- a/web/cashtab/src/utils/__tests__/chronik.test.js
+++ b/web/cashtab/src/utils/__tests__/chronik.test.js
@@ -9,6 +9,7 @@
flattenChronikTxHistory,
sortAndTrimChronikTxHistory,
parseChronikTx,
+ getMintAddress,
} from 'utils/chronik';
import {
mockChronikUtxos,
@@ -54,6 +55,20 @@
mockTokenBurnWithDecimalsTx,
mockReceivedEtokenTx,
} from '../__mocks__/chronikTxHistory';
+import {
+ mintingTxTabCash,
+ mintingAddressTabCash,
+ mintingAddressBchFormatTabCash,
+ mintingHash160TabCash,
+ mintingTxPoW,
+ mintingAddressPoW,
+ mintingAddressBchFormatPoW,
+ mintingHash160PoW,
+ mintingTxAlita,
+ mintingAddressAlita,
+ mintingAddressBchFormatAlita,
+ mintingHash160Alita,
+} from '../__mocks__/chronikMintTxs';
import { ChronikClient } from 'chronik-client';
import { when } from 'jest-when';
import BCHJS from '@psf/bch-js';
@@ -733,3 +748,98 @@
replyAddress: 'ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6',
});
});
+
+it(`getMintAddress successfully parses chronik.tx response to determine mint address for TabCash token`, async () => {
+ // Initialize chronik
+ const chronik = new ChronikClient(
+ 'https://FakeChronikUrlToEnsureMocksOnly.com',
+ );
+ const BCH = new BCHJS({
+ restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com',
+ });
+ /*
+ Mock the API response from chronik.tx('tokenId') called
+ in returnGetTokenInfoChronikPromise -- for each tokenId used
+ */
+ chronik.tx = jest.fn();
+
+ when(chronik.tx)
+ .calledWith(mintingTxTabCash.txid)
+ .mockResolvedValue(mintingTxTabCash);
+
+ // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment
+ BCH.Address.hash160ToCash = jest
+ .fn()
+ .mockReturnValue(mintingAddressBchFormatTabCash);
+
+ expect(await getMintAddress(chronik, BCH, mintingTxTabCash.txid)).toBe(
+ mintingAddressTabCash,
+ );
+
+ // spy on mintingHash160
+ expect(BCH.Address.hash160ToCash).toHaveBeenCalledWith(
+ mintingHash160TabCash,
+ );
+});
+
+it(`getMintAddress successfully parses chronik.tx response to determine mint address for PoW token`, async () => {
+ // Initialize chronik
+ const chronik = new ChronikClient(
+ 'https://FakeChronikUrlToEnsureMocksOnly.com',
+ );
+ const BCH = new BCHJS({
+ restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com',
+ });
+ /*
+ Mock the API response from chronik.tx('tokenId') called
+ in returnGetTokenInfoChronikPromise -- for each tokenId used
+ */
+ chronik.tx = jest.fn();
+
+ when(chronik.tx)
+ .calledWith(mintingTxPoW.txid)
+ .mockResolvedValue(mintingTxPoW);
+
+ // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment
+ BCH.Address.hash160ToCash = jest
+ .fn()
+ .mockReturnValue(mintingAddressBchFormatPoW);
+
+ expect(await getMintAddress(chronik, BCH, mintingTxPoW.txid)).toBe(
+ mintingAddressPoW,
+ );
+
+ // spy on mintingHash160
+ expect(BCH.Address.hash160ToCash).toHaveBeenCalledWith(mintingHash160PoW);
+});
+
+it(`getMintAddress successfully parses chronik.tx response to determine mint address for Alita token`, async () => {
+ // Initialize chronik
+ const chronik = new ChronikClient(
+ 'https://FakeChronikUrlToEnsureMocksOnly.com',
+ );
+ const BCH = new BCHJS({
+ restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com',
+ });
+ /*
+ Mock the API response from chronik.tx('tokenId') called
+ in returnGetTokenInfoChronikPromise -- for each tokenId used
+ */
+ chronik.tx = jest.fn();
+
+ when(chronik.tx)
+ .calledWith(mintingTxAlita.txid)
+ .mockResolvedValue(mintingTxAlita);
+
+ // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment
+ BCH.Address.hash160ToCash = jest
+ .fn()
+ .mockReturnValue(mintingAddressBchFormatAlita);
+
+ expect(await getMintAddress(chronik, BCH, mintingTxAlita.txid)).toBe(
+ mintingAddressAlita,
+ );
+
+ // spy on mintingHash160
+ expect(BCH.Address.hash160ToCash).toHaveBeenCalledWith(mintingHash160Alita);
+});
diff --git a/web/cashtab/src/utils/chronik.js b/web/cashtab/src/utils/chronik.js
--- a/web/cashtab/src/utils/chronik.js
+++ b/web/cashtab/src/utils/chronik.js
@@ -6,6 +6,8 @@
convertToEncryptStruct,
getHashArrayFromWallet,
getUtxoWif,
+ convertEcashtoEtokenAddr,
+ convertToEcashPrefix,
} from 'utils/cashMethods';
import ecies from 'ecies-lite';
import wif from 'wif';
@@ -902,3 +904,44 @@
txHistoryNewTokensToCache,
};
};
+
+export const getMintAddress = async (chronik, BCH, tokenId) => {
+ let genesisTx;
+ let mintingHash160;
+ try {
+ genesisTx = await chronik.tx(tokenId);
+ // get the minting address chronik
+ // iterate over the inputs
+ const { outputs } = genesisTx;
+ for (let i = 0; i < outputs.length; i += 1) {
+ const thisOutput = outputs[i];
+ // Check to see if this output has eTokens
+ if (
+ thisOutput &&
+ thisOutput.slpToken &&
+ typeof thisOutput.slpToken !== 'undefined' &&
+ thisOutput.slpToken.amount &&
+ Number(thisOutput.slpToken.amount) > 0
+ ) {
+ // then this is the minting address
+ const thisOutputHash160 = thisOutput.outputScript;
+ mintingHash160 = thisOutputHash160.substring(
+ thisOutputHash160.indexOf('76a914') + '76a914'.length,
+ thisOutputHash160.lastIndexOf('88ac'),
+ );
+ }
+ }
+ const mintingAdressBchFormat =
+ BCH.Address.hash160ToCash(mintingHash160);
+ const mintEcashAddressChronik = convertToEcashPrefix(
+ mintingAdressBchFormat,
+ );
+ const mintEtokenAddressChronik = convertEcashtoEtokenAddr(
+ mintEcashAddressChronik,
+ );
+ return mintEtokenAddressChronik;
+ } catch (err) {
+ console.log(`Error in getMintAddress`, err);
+ return err;
+ }
+};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 10:34 (1 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5571928
Default Alt Text
D12367.id36037.diff (17 KB)
Attached To
D12367: [Cashtab] [airdrop chronik for mint address p1] Get minting address with chronik and compare to bch-api result
Event Timeline
Log In to Comment