diff --git a/cashtab/src/components/Alias/Alias.js b/cashtab/src/components/Alias/Alias.js --- a/cashtab/src/components/Alias/Alias.js +++ b/cashtab/src/components/Alias/Alias.js @@ -68,9 +68,10 @@ isAliasServerOnline, } = ContextValue; const walletState = getWalletState(wallet); - const { balances, nonSlpUtxos } = walletState; + const { balances } = walletState; const [formData, setFormData] = useState({ aliasName: '', + aliasAddress: '', }); const [isValidAliasInput, setIsValidAliasInput] = useState(false); // tracks whether to activate the registration button const [aliasValidationError, setAliasValidationError] = useState(false); @@ -97,6 +98,13 @@ } passLoadingStatus(true); + // Set address of active wallet to default alias registration address + // Use formdata approach as we will later add a form field for aliasAddress + setFormData(formData => ({ + ...formData, + aliasAddress: wallet.Path1899.cashAddress, + })); + // check whether the address is attached to an onchain alias on page load const walletHasAlias = isAddressRegistered( wallet, @@ -151,6 +159,7 @@ // note: input already validated via handleAliasNameInput() const aliasInput = formData.aliasName; + const aliasAddress = formData.aliasAddress; // check if the user is trying to essentially register chicken.xec.xec const doubleExtensionInput = isAliasFormat(aliasInput); @@ -184,16 +193,16 @@ `Alias ${aliasInput} is available. Broadcasting registration transaction.`, ); try { - const link = await registerNewAlias( + const result = await registerNewAlias( chronik, wallet, - nonSlpUtxos, currency.defaultFee, aliasInput, - fromSatoshisToXec(registrationFee), + aliasAddress, + registrationFee, ); - registerAliasNotification(link, aliasInput); + registerAliasNotification(result.explorerLink, aliasInput); // allow alias server to process the pending alias const delay = ms => new Promise(res => setTimeout(res, ms)); diff --git a/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap b/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap --- a/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap +++ b/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances 1`] = ` Array [ diff --git a/cashtab/src/components/Send/__tests__/__snapshots__/SendToken.test.js.snap b/cashtab/src/components/Send/__tests__/__snapshots__/SendToken.test.js.snap --- a/cashtab/src/components/Send/__tests__/__snapshots__/SendToken.test.js.snap +++ b/cashtab/src/components/Send/__tests__/__snapshots__/SendToken.test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances and tokens 1`] = `null`; diff --git a/cashtab/src/utils/__mocks__/registerNewAliasMocks.js b/cashtab/src/utils/__mocks__/registerNewAliasMocks.js new file mode 100644 --- /dev/null +++ b/cashtab/src/utils/__mocks__/registerNewAliasMocks.js @@ -0,0 +1,608 @@ +// @generated + +export const aliasRegisteringWallet = { + mnemonic: + 'cheese purpose sphere member afford orbit aisle bundle shoe save delay poverty', + name: '[burned]aliasRegTest', + Path245: { + publicKey: + '033a8335572ad5877fb4691d702dc276e965e3dfc61b7ddb1266e56ee9e63b07c7', + hash160: '260ad4f88031bf90191db87956a141a4caee41b9', + cashAddress: 'ecash:qqnq448csqcmlyqerku8j44pgxjv4mjphyvf4q7ku5', + fundingWif: 'L2z9MWRYBdajS1JUvry8ef3H4dMoJiQpL7H9gh9QY9uN4tTW5sty', + }, + Path145: { + publicKey: + '03bb8d0f9b479bbbf17025f1c58c34c9831ad4ac16f1707fb3e19bf4a990eed517', + hash160: '7774bdf6dc5f88dcbafc9876ddda68d6ef9f5079', + cashAddress: 'ecash:qpmhf00km30c3h96ljv8dhw6drtwl86s0ysn32vngq', + fundingWif: 'Kwhw5NivkPBigRCsRFeab2W62yWHH3aNAK8PBAeK4cW13Sk3NM98', + }, + Path1899: { + publicKey: + '036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + hash160: '20edc8389101aed204b9c17b7d64a00ead0e8cfc', + cashAddress: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + fundingWif: 'L3NFW2e1T92cF6YZydoEtpmYSm1hhmUzJ9fXgBAzF8ts4Eugno2D', + }, + state: { + balances: { + totalBalanceInSatoshis: '10000000', + totalBalance: '100000', + }, + slpUtxos: [], + nonSlpUtxos: [ + { + outpoint: { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + outIdx: 0, + }, + blockHeight: 790294, + isCoinbase: false, + value: '10000000', + network: 'XEC', + address: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + }, + ], + tokens: [], + parsedTxHistory: [ + { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + version: 2, + inputs: [ + { + prevOut: { + txid: '88fec8beeda59c72b06b6d5d9531a03e4ecb46a0097501565361900f9dcc280a', + outIdx: 1, + }, + inputScript: + '47304402206bb74db30b624d62b51e00f1f4a309ad7c037c55c45ac38425a63e4b168e92ad022034e464b5f6136bb63345a32e40aa0c3224fcfb6ad4bb7449094b84f36a331e294121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '8849259', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '1c0b5e632601d041a4423e05aa9824c8d368eb01c8a9aaefc506233879349404', + outIdx: 3, + }, + inputScript: + '4730440220097633057fd28fb098c11012e63e05850b4f172f37dd58373c14ef80fdc790cb02203f0d5f44b92f3e659c605faac2c6743eacf223f695d1ce7cfd07796ff0a241694121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '5000', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '179f65e21f4bb3ee3bf9d0433b7a6df7ed6e5a795b2c1aea47902e1fb0e39fe3', + outIdx: 1, + }, + inputScript: + '473044022062f6dcddca0d477dedd0024cabf0b4e22f2b213231f385e0b68e9e5f41eb04e602201597c7df3495bab6093612d2628b8c30554c27a24d452bc11e3a51fd37727f264121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '1100674', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '9da7445bb061944175710efcb5a22118aceb6c23c8bc82d4afeddddd410ea2b5', + outIdx: 2, + }, + inputScript: + '47304402207d591fe5f8f6d71e120634be09674e36074122c3291c00c18e6807397ecac323022021e7e9c2c0fb724e99a74e0dd5dba453d292a1cd32f55e18a33fcf515b50e9784121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '9998848', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '10000000', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + }, + { + value: '9952434', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + }, + ], + lockTime: 0, + block: { + height: 790294, + hash: '0000000000000000084fe051052cbbe8778135f254076b3e20e9f08387654b2f', + timestamp: '1683047794', + }, + timeFirstSeen: '1683047404', + size: 666, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: true, + xecAmount: '100000', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qplkmuz3rx480u6vc4xgc0qxnza42p0e7vll6p90wr', + aliasFlag: false, + }, + }, + ], + }, +}; +export const aliasRegisteringWalletAfterTx = { + mnemonic: + 'cheese purpose sphere member afford orbit aisle bundle shoe save delay poverty', + name: '[burned]aliasRegTest', + Path245: { + publicKey: + '033a8335572ad5877fb4691d702dc276e965e3dfc61b7ddb1266e56ee9e63b07c7', + hash160: '260ad4f88031bf90191db87956a141a4caee41b9', + cashAddress: 'ecash:qqnq448csqcmlyqerku8j44pgxjv4mjphyvf4q7ku5', + fundingWif: 'L2z9MWRYBdajS1JUvry8ef3H4dMoJiQpL7H9gh9QY9uN4tTW5sty', + }, + Path145: { + publicKey: + '03bb8d0f9b479bbbf17025f1c58c34c9831ad4ac16f1707fb3e19bf4a990eed517', + hash160: '7774bdf6dc5f88dcbafc9876ddda68d6ef9f5079', + cashAddress: 'ecash:qpmhf00km30c3h96ljv8dhw6drtwl86s0ysn32vngq', + fundingWif: 'Kwhw5NivkPBigRCsRFeab2W62yWHH3aNAK8PBAeK4cW13Sk3NM98', + }, + Path1899: { + publicKey: + '036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + hash160: '20edc8389101aed204b9c17b7d64a00ead0e8cfc', + cashAddress: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + fundingWif: 'L3NFW2e1T92cF6YZydoEtpmYSm1hhmUzJ9fXgBAzF8ts4Eugno2D', + }, + state: { + balances: { + totalBalanceInSatoshis: '9998994', + totalBalance: '99989.94', + }, + slpUtxos: [], + nonSlpUtxos: [ + { + outpoint: { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + outIdx: 2, + }, + blockHeight: 790297, + isCoinbase: false, + value: '9998994', + network: 'XEC', + address: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + }, + ], + tokens: [], + parsedTxHistory: [ + { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + version: 2, + inputs: [ + { + prevOut: { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + outIdx: 0, + }, + inputScript: + '483045022100dd79c2a3e8773e7d4963ad3f6f03b54aca569e8e383c5cdc285afa601ee50829022058dfcdc905ec8f45d7418644ccfdf45cd8db41aade2d57d455c50e1a181cf7bb4121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + value: '10000000', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '0', + outputScript: + '6a042e78656300086e65777465737431150020edc8389101aed204b9c17b7d64a00ead0e8cfc', + }, + { + value: '551', + outputScript: + '76a914638568e36d0b5d7d49a6e99854caa27d9772b09388ac', + }, + { + value: '9998994', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + }, + ], + lockTime: 0, + block: { + height: 790297, + hash: '000000000000000016920644c8c4abcf1681a6ca9068e532410554e901848d41', + timestamp: '1683049955', + }, + timeFirstSeen: '1683049080', + size: 273, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: false, + xecAmount: '5.51', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + aliasFlag: true, + }, + }, + { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + version: 2, + inputs: [ + { + prevOut: { + txid: '88fec8beeda59c72b06b6d5d9531a03e4ecb46a0097501565361900f9dcc280a', + outIdx: 1, + }, + inputScript: + '47304402206bb74db30b624d62b51e00f1f4a309ad7c037c55c45ac38425a63e4b168e92ad022034e464b5f6136bb63345a32e40aa0c3224fcfb6ad4bb7449094b84f36a331e294121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '8849259', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '1c0b5e632601d041a4423e05aa9824c8d368eb01c8a9aaefc506233879349404', + outIdx: 3, + }, + inputScript: + '4730440220097633057fd28fb098c11012e63e05850b4f172f37dd58373c14ef80fdc790cb02203f0d5f44b92f3e659c605faac2c6743eacf223f695d1ce7cfd07796ff0a241694121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '5000', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '179f65e21f4bb3ee3bf9d0433b7a6df7ed6e5a795b2c1aea47902e1fb0e39fe3', + outIdx: 1, + }, + inputScript: + '473044022062f6dcddca0d477dedd0024cabf0b4e22f2b213231f385e0b68e9e5f41eb04e602201597c7df3495bab6093612d2628b8c30554c27a24d452bc11e3a51fd37727f264121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '1100674', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '9da7445bb061944175710efcb5a22118aceb6c23c8bc82d4afeddddd410ea2b5', + outIdx: 2, + }, + inputScript: + '47304402207d591fe5f8f6d71e120634be09674e36074122c3291c00c18e6807397ecac323022021e7e9c2c0fb724e99a74e0dd5dba453d292a1cd32f55e18a33fcf515b50e9784121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '9998848', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '10000000', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + spentBy: { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + outIdx: 0, + }, + }, + { + value: '9952434', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + }, + ], + lockTime: 0, + block: { + height: 790294, + hash: '0000000000000000084fe051052cbbe8778135f254076b3e20e9f08387654b2f', + timestamp: '1683047794', + }, + timeFirstSeen: '1683047404', + size: 666, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: true, + xecAmount: '100000', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qplkmuz3rx480u6vc4xgc0qxnza42p0e7vll6p90wr', + aliasFlag: false, + }, + }, + ], + }, +}; +export const aliasRegisteringWalletAfterTwoTxs = { + mnemonic: + 'cheese purpose sphere member afford orbit aisle bundle shoe save delay poverty', + name: '[burned]aliasRegTest', + Path245: { + publicKey: + '033a8335572ad5877fb4691d702dc276e965e3dfc61b7ddb1266e56ee9e63b07c7', + hash160: '260ad4f88031bf90191db87956a141a4caee41b9', + cashAddress: 'ecash:qqnq448csqcmlyqerku8j44pgxjv4mjphyvf4q7ku5', + fundingWif: 'L2z9MWRYBdajS1JUvry8ef3H4dMoJiQpL7H9gh9QY9uN4tTW5sty', + }, + Path145: { + publicKey: + '03bb8d0f9b479bbbf17025f1c58c34c9831ad4ac16f1707fb3e19bf4a990eed517', + hash160: '7774bdf6dc5f88dcbafc9876ddda68d6ef9f5079', + cashAddress: 'ecash:qpmhf00km30c3h96ljv8dhw6drtwl86s0ysn32vngq', + fundingWif: 'Kwhw5NivkPBigRCsRFeab2W62yWHH3aNAK8PBAeK4cW13Sk3NM98', + }, + Path1899: { + publicKey: + '036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + hash160: '20edc8389101aed204b9c17b7d64a00ead0e8cfc', + cashAddress: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + fundingWif: 'L3NFW2e1T92cF6YZydoEtpmYSm1hhmUzJ9fXgBAzF8ts4Eugno2D', + }, + state: { + balances: { + totalBalanceInSatoshis: '9997988', + totalBalance: '99979.88', + }, + slpUtxos: [], + nonSlpUtxos: [ + { + outpoint: { + txid: '912582a1dc11b568f14f8ebae15cbb0ce53bdb973e137e7dc7c9b261327e6cab', + outIdx: 2, + }, + blockHeight: 790312, + isCoinbase: false, + value: '9997988', + network: 'XEC', + address: 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + }, + ], + tokens: [], + parsedTxHistory: [ + { + txid: '912582a1dc11b568f14f8ebae15cbb0ce53bdb973e137e7dc7c9b261327e6cab', + version: 2, + inputs: [ + { + prevOut: { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + outIdx: 2, + }, + inputScript: + '47304402205cf1941bd0ed8c49319189973feebd14e8d7faf6c5a3cdc6c16f676bd62c63ac022068c10726326e37f960433a92894609f7f0b65946d8104038110e2104d973c8e24121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + value: '9998994', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '0', + outputScript: + '6a042e78656300157477656e74796f6e6562797465616c696173726567150020edc8389101aed204b9c17b7d64a00ead0e8cfc', + }, + { + value: '551', + outputScript: + '76a914638568e36d0b5d7d49a6e99854caa27d9772b09388ac', + }, + { + value: '9997988', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + }, + ], + lockTime: 0, + block: { + height: 790312, + hash: '0000000000000000170185a5ef34ce2d9eaa9eebc540dadac15eb154c8c7aedd', + timestamp: '1683063775', + }, + timeFirstSeen: '1683063315', + size: 285, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: false, + xecAmount: '5.51', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + aliasFlag: true, + }, + }, + { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + version: 2, + inputs: [ + { + prevOut: { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + outIdx: 0, + }, + inputScript: + '483045022100dd79c2a3e8773e7d4963ad3f6f03b54aca569e8e383c5cdc285afa601ee50829022058dfcdc905ec8f45d7418644ccfdf45cd8db41aade2d57d455c50e1a181cf7bb4121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + value: '10000000', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '0', + outputScript: + '6a042e78656300086e65777465737431150020edc8389101aed204b9c17b7d64a00ead0e8cfc', + }, + { + value: '551', + outputScript: + '76a914638568e36d0b5d7d49a6e99854caa27d9772b09388ac', + }, + { + value: '9998994', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + spentBy: { + txid: '912582a1dc11b568f14f8ebae15cbb0ce53bdb973e137e7dc7c9b261327e6cab', + outIdx: 0, + }, + }, + ], + lockTime: 0, + block: { + height: 790297, + hash: '000000000000000016920644c8c4abcf1681a6ca9068e532410554e901848d41', + timestamp: '1683049955', + }, + timeFirstSeen: '1683049080', + size: 273, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: false, + xecAmount: '5.51', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + aliasFlag: true, + }, + }, + { + txid: '879e64ba90c09d957f6b7043776cd5c171ee2c7c82e728bd1fe97899f42d9c04', + version: 2, + inputs: [ + { + prevOut: { + txid: '88fec8beeda59c72b06b6d5d9531a03e4ecb46a0097501565361900f9dcc280a', + outIdx: 1, + }, + inputScript: + '47304402206bb74db30b624d62b51e00f1f4a309ad7c037c55c45ac38425a63e4b168e92ad022034e464b5f6136bb63345a32e40aa0c3224fcfb6ad4bb7449094b84f36a331e294121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '8849259', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '1c0b5e632601d041a4423e05aa9824c8d368eb01c8a9aaefc506233879349404', + outIdx: 3, + }, + inputScript: + '4730440220097633057fd28fb098c11012e63e05850b4f172f37dd58373c14ef80fdc790cb02203f0d5f44b92f3e659c605faac2c6743eacf223f695d1ce7cfd07796ff0a241694121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '5000', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '179f65e21f4bb3ee3bf9d0433b7a6df7ed6e5a795b2c1aea47902e1fb0e39fe3', + outIdx: 1, + }, + inputScript: + '473044022062f6dcddca0d477dedd0024cabf0b4e22f2b213231f385e0b68e9e5f41eb04e602201597c7df3495bab6093612d2628b8c30554c27a24d452bc11e3a51fd37727f264121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '1100674', + sequenceNo: 4294967295, + }, + { + prevOut: { + txid: '9da7445bb061944175710efcb5a22118aceb6c23c8bc82d4afeddddd410ea2b5', + outIdx: 2, + }, + inputScript: + '47304402207d591fe5f8f6d71e120634be09674e36074122c3291c00c18e6807397ecac323022021e7e9c2c0fb724e99a74e0dd5dba453d292a1cd32f55e18a33fcf515b50e9784121020d867a730bb6b55078d4eaf36fbf06d2a3867f81c20ad54925bcdd02ec914cbb', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + value: '9998848', + sequenceNo: 4294967295, + }, + ], + outputs: [ + { + value: '10000000', + outputScript: + '76a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac', + spentBy: { + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + outIdx: 0, + }, + }, + { + value: '9952434', + outputScript: + '76a9147f6df05119aa77f34cc54c8c3c0698bb5505f9f388ac', + }, + ], + lockTime: 0, + block: { + height: 790294, + hash: '0000000000000000084fe051052cbbe8778135f254076b3e20e9f08387654b2f', + timestamp: '1683047794', + }, + timeFirstSeen: '1683047404', + size: 666, + isCoinbase: false, + network: 'XEC', + parsed: { + incoming: true, + xecAmount: '100000', + isEtokenTx: false, + airdropFlag: false, + airdropTokenId: '', + opReturnMessage: '', + isCashtabMessage: false, + isEncryptedMessage: false, + decryptionSuccess: false, + replyAddress: + 'ecash:qplkmuz3rx480u6vc4xgc0qxnza42p0e7vll6p90wr', + aliasFlag: false, + }, + }, + ], + }, +}; diff --git a/cashtab/src/utils/__tests__/transactions.test.js b/cashtab/src/utils/__tests__/transactions.test.js --- a/cashtab/src/utils/__tests__/transactions.test.js +++ b/cashtab/src/utils/__tests__/transactions.test.js @@ -1,5 +1,10 @@ /* eslint-disable no-native-reassign */ import sendBCHMock from '../__mocks__/sendBCH'; +import { + aliasRegisteringWallet, + aliasRegisteringWalletAfterTx, + aliasRegisteringWalletAfterTwoTxs, +} from '../__mocks__/registerNewAliasMocks'; import createTokenMock from '../__mocks__/createToken'; import { burnTokenWallet } from '../__mocks__/burnToken'; import { currency } from '../../components/Common/Ticker'; @@ -11,6 +16,7 @@ burnToken, createToken, getRecipientPublicKey, + registerNewAlias, } from 'utils/transactions'; describe('Cashtab transaction broadcasting functions', () => { @@ -99,6 +105,89 @@ ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); }); + it('Broadcasts a v0 alias registration tx for an 8-byte alias to a p2pkh address', async () => { + const chronik = new ChronikClient( + 'https://FakeChronikUrlToEnsureMocksOnly.com', + ); + + const mockTxid = + '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0'; + + chronik.broadcastTx = jest.fn().mockResolvedValue({ txid: mockTxid }); + + const expectedResult = { + explorerLink: + 'https://explorer.e.cash/tx/1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + rawTxHex: + '0200000001049c2df49978e91fbd28e7827c2cee71c1d56c7743706b7f959dc090ba649e87000000006b483045022100dd79c2a3e8773e7d4963ad3f6f03b54aca569e8e383c5cdc285afa601ee50829022058dfcdc905ec8f45d7418644ccfdf45cd8db41aade2d57d455c50e1a181cf7bb4121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6ffffffff030000000000000000266a042e78656300086e65777465737431150020edc8389101aed204b9c17b7d64a00ead0e8cfc27020000000000001976a914638568e36d0b5d7d49a6e99854caa27d9772b09388ac92929800000000001976a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac00000000', + txid: '1272c4a9bf5829c9dba1efb252e753ed20e3cdd49b6e75a778befc7a87eaf7d0', + }; + expect( + await registerNewAlias( + chronik, + aliasRegisteringWallet, + currency.defaultFee, + 'newtest1', + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + 551, + ), + ).toStrictEqual(expectedResult); + }); + it('Broadcasts a v0 alias registration tx for a 21-byte alias to a p2pkh address', async () => { + const chronik = new ChronikClient( + 'https://FakeChronikUrlToEnsureMocksOnly.com', + ); + + const mockTxid = + '912582a1dc11b568f14f8ebae15cbb0ce53bdb973e137e7dc7c9b261327e6cab'; + + chronik.broadcastTx = jest.fn().mockResolvedValue({ txid: mockTxid }); + + const expectedResult = { + explorerLink: `${currency.blockExplorerUrl}/tx/${mockTxid}`, + txid: mockTxid, + rawTxHex: + '0200000001d0f7ea877afcbe78a7756e9bd4cde320ed53e752b2efa1dbc92958bfa9c47212020000006a47304402205cf1941bd0ed8c49319189973feebd14e8d7faf6c5a3cdc6c16f676bd62c63ac022068c10726326e37f960433a92894609f7f0b65946d8104038110e2104d973c8e24121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6ffffffff030000000000000000336a042e78656300157477656e74796f6e6562797465616c696173726567150020edc8389101aed204b9c17b7d64a00ead0e8cfc27020000000000001976a914638568e36d0b5d7d49a6e99854caa27d9772b09388aca48e9800000000001976a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac00000000', + }; + expect( + await registerNewAlias( + chronik, + aliasRegisteringWalletAfterTx, + currency.defaultFee, + 'twentyonebytealiasreg', + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + 551, + ), + ).toStrictEqual(expectedResult); + }); + it('Broadcasts a v0 alias registration tx for a 16-byte alias to a p2pkh address', async () => { + const chronik = new ChronikClient( + 'https://FakeChronikUrlToEnsureMocksOnly.com', + ); + + const mockTxid = + '8783d7064ce22e8390c9fa94ef9a4d5bb0184e401ef5a9fbf60b68294e275c80'; + + chronik.broadcastTx = jest.fn().mockResolvedValue({ txid: mockTxid }); + + const expectedResult = { + explorerLink: `${currency.blockExplorerUrl}/tx/${mockTxid}`, + txid: mockTxid, + rawTxHex: + '0200000001ab6c7e3261b2c9c77d7e133e97db3be50cbb5ce1ba8e4ff168b511dca1822591020000006b483045022100d0bd27e798ac38de8b4c654c6670386c68d8bfac4bf5fe26a185d8250bd7ae7e02206acfe247b95ee9879080e6e413d7f28734aa498046e7363a638a537fc657c50e4121036ea648569566fa0843b914f67e54ebcfa6921208acd6408d2881488809403ac6ffffffff0300000000000000002e6a042e78656300107768796e6f7474687265657465737473150020edc8389101aed204b9c17b7d64a00ead0e8cfc27020000000000001976a914638568e36d0b5d7d49a6e99854caa27d9772b09388acb68a9800000000001976a91420edc8389101aed204b9c17b7d64a00ead0e8cfc88ac00000000', + }; + expect( + await registerNewAlias( + chronik, + aliasRegisteringWalletAfterTwoTxs, + currency.defaultFee, + 'whynotthreetests', + 'ecash:qqswmjpcjyq6a5syh8qhklty5q826r5vlsh7a7uqtq', + 551, + ), + ).toStrictEqual(expectedResult); + }); + it(`Throws error if called trying to send one base unit ${currency.ticker} more than available in utxo set`, async () => { const chronik = new ChronikClient( 'https://FakeChronikUrlToEnsureMocksOnly.com', diff --git a/cashtab/src/utils/transactions.js b/cashtab/src/utils/transactions.js --- a/cashtab/src/utils/transactions.js +++ b/cashtab/src/utils/transactions.js @@ -12,6 +12,8 @@ getChangeAddressFromInputUtxos, toHash160, getMessageByteSize, + generateAliasOpReturnScript, + fromSatoshisToXec, } from 'utils/cashMethods'; import ecies from 'ecies-lite'; import * as utxolib from '@bitgo/utxo-lib'; @@ -328,72 +330,60 @@ export const registerNewAlias = async ( chronik, wallet, - utxos, feeInSatsPerByte, aliasName, - registrationFee, + aliasAddress, + registrationFeeSats, ) => { try { + // Instantiate new txBuilder let txBuilder = utxolib.bitgo.createTransactionBuilderForNetwork( utxolib.networks.ecash, ); - const satoshisToSend = fromXecToSatoshis(registrationFee); + // Create this transaction with nonSlpUtxos + const utxos = wallet.state.nonSlpUtxos; - // Throw validation error if fromXecToSatoshis returns false - if (!satoshisToSend) { - throw new Error(`Invalid alias registration fee`); - } + // Build opReturnData for alias tx per spec + const opReturnData = generateAliasOpReturnScript( + aliasName, + aliasAddress, + ); - // Start of building the OP_RETURN output. - // only build the OP_RETURN output if the user supplied it - if ( - aliasName && - typeof aliasName !== 'undefined' && - aliasName.trim() !== '' - ) { - const opReturnData = generateOpReturnScript( - aliasName, - false, // encryption use - false, // airdrop use - null, // airdrop use - null, // encrypted use - true, // alias registration flag - ); - txBuilder.addOutput(opReturnData, 0); - } + // Add opReturn as output with 0 satoshis of XEC spent + txBuilder.addOutput(opReturnData, 0); // generate the tx inputs and add to txBuilder instance // returns the updated txBuilder, txFee, totalInputUtxoValue and inputUtxos + // Note that txBuilder is intentionally modified by this call let txInputObj = generateTxInput( - false, // not one to many + false, // not a one to many tx utxos, txBuilder, - null, // one to many array - satoshisToSend, + null, // no one-to-many array + registrationFeeSats, feeInSatsPerByte, ); + // Get the change address const changeAddress = getChangeAddressFromInputUtxos( txInputObj.inputUtxos, wallet, ); - txBuilder = txInputObj.txBuilder; // update the local txBuilder with the generated tx inputs // generate the tx outputs and add to txBuilder instance // returns the updated txBuilder - const txOutputObj = generateTxOutput( - false, // not one to many - registrationFee, - satoshisToSend, + txBuilder = generateTxOutput( + false, // not a one-to-many tx + fromSatoshisToXec(registrationFeeSats), // TODO fix this oversight param req in generateTxOutput + registrationFeeSats, txInputObj.totalInputUtxoValue, currency.aliasSettings.aliasPaymentAddress, - null, // one to many address array + null, // no one-to-many address array changeAddress, txInputObj.txFee, txBuilder, ); - txBuilder = txOutputObj; // update the local txBuilder with the generated tx outputs // sign the collated inputUtxos and build the raw tx hex // returns the raw tx hex string @@ -417,8 +407,9 @@ throw err; } + const explorerLink = `${currency.blockExplorerUrl}/tx/${broadcastResponse.txid}`; // return the explorer link for the broadcasted tx - return `${currency.blockExplorerUrl}/tx/${broadcastResponse.txid}`; + return { explorerLink, txid: broadcastResponse.txid, rawTxHex }; } catch (err) { if (err.error === 'insufficient priority (code 66)') { err.code = SEND_XEC_ERRORS.INSUFFICIENT_PRIORITY;