diff --git a/web/cashtab/src/hooks/__tests__/useBCH.test.js b/web/cashtab/src/hooks/__tests__/useBCH.test.js --- a/web/cashtab/src/hooks/__tests__/useBCH.test.js +++ b/web/cashtab/src/hooks/__tests__/useBCH.test.js @@ -672,4 +672,74 @@ expectedPubKey, ); }); + + it(`parseXecSendValue() correctly parses the value for a valid one to one send XEC transaction`, () => { + const { parseXecSendValue } = useBCH(); + expect(parseXecSendValue(false, '550', null)).toStrictEqual( + new BigNumber(550), + ); + }); + + it(`parseXecSendValue() correctly parses the value for a valid one to many send XEC transaction`, () => { + const { parseXecSendValue } = useBCH(); + const destinationAddressAndValueArray = [ + 'ecash:qrmz0egsqxj35x5jmzf8szrszdeu72fx0uxgwk3r48,6', + 'ecash:qq9h6d0a5q65fgywv4ry64x04ep906mdku8f0gxfgx,6', + 'ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,6', + ]; + expect( + parseXecSendValue(true, null, destinationAddressAndValueArray), + ).toStrictEqual(new BigNumber(18)); + }); + + it(`parseXecSendValue() correctly throws error when singleSendValue is invalid for a one to one send XEC transaction`, () => { + const { parseXecSendValue } = useBCH(); + let errorThrown; + try { + parseXecSendValue(false, null, 550); + } catch (err) { + errorThrown = err; + } + expect(errorThrown.message).toStrictEqual('Invalid singleSendValue'); + }); + + it(`parseXecSendValue() correctly throws error when destinationAddressAndValueArray is invalid for a one to many send XEC transaction`, () => { + const { parseXecSendValue } = useBCH(); + let errorThrown; + try { + parseXecSendValue(true, null, null); + } catch (err) { + errorThrown = err; + } + expect(errorThrown.message).toStrictEqual( + 'Invalid destinationAddressAndValueArray', + ); + }); + + it(`parseXecSendValue() correctly throws error when the total value for a one to one send XEC transaction is below dust`, () => { + const { parseXecSendValue } = useBCH(); + let errorThrown; + try { + parseXecSendValue(false, '4.5', null); + } catch (err) { + errorThrown = err; + } + expect(errorThrown.message).toStrictEqual('dust'); + }); + + it(`parseXecSendValue() correctly throws error when the total value for a one to many send XEC transaction is below dust`, () => { + const { parseXecSendValue } = useBCH(); + const destinationAddressAndValueArray = [ + 'ecash:qrmz0egsqxj35x5jmzf8szrszdeu72fx0uxgwk3r48,2', + 'ecash:qq9h6d0a5q65fgywv4ry64x04ep906mdku8f0gxfgx,2', + 'ecash:qzvydd4n3lm3xv62cx078nu9rg0e3srmqq0knykfed,1', + ]; + let errorThrown; + try { + parseXecSendValue(true, null, destinationAddressAndValueArray); + } catch (err) { + errorThrown = err; + } + expect(errorThrown.message).toStrictEqual('dust'); + }); }); diff --git a/web/cashtab/src/hooks/useBCH.js b/web/cashtab/src/hooks/useBCH.js --- a/web/cashtab/src/hooks/useBCH.js +++ b/web/cashtab/src/hooks/useBCH.js @@ -1395,6 +1395,67 @@ return encryptedEj; }; + /* + * Parse the total value of a send XEC tx and checks whether it is more than dust + * One to many: isOneToMany is true, singleSendValue is null + * One to one: isOneToMany is false, destinationAddressAndValueArray is null + * Returns the aggregate send value in BigNumber format + */ + const parseXecSendValue = ( + isOneToMany, + singleSendValue, + destinationAddressAndValueArray, + ) => { + let value = new BigNumber(0); + + try { + if (isOneToMany) { + // this is a one to many XEC transaction + if ( + !destinationAddressAndValueArray || + !destinationAddressAndValueArray.length + ) { + throw new Error('Invalid destinationAddressAndValueArray'); + } + const arrayLength = destinationAddressAndValueArray.length; + for (let i = 0; i < arrayLength; i++) { + // add the total value being sent in this array of recipients + // each array row is: 'eCash address, send value' + value = BigNumber.sum( + value, + new BigNumber( + destinationAddressAndValueArray[i].split(',')[1], + ), + ); + } + } else { + // this is a one to one XEC transaction then check singleSendValue + // note: one to many transactions won't be sending a singleSendValue param + + if (!singleSendValue) { + throw new Error('Invalid singleSendValue'); + } + + value = new BigNumber(singleSendValue); + } + // If user is attempting to send an aggregate value that is less than minimum accepted by the backend + if ( + value.lt( + new BigNumber( + fromSmallestDenomination(currency.dustSats).toString(), + ), + ) + ) { + // Throw the same error given by the backend attempting to broadcast such a tx + throw new Error('dust'); + } + } catch (err) { + console.log('Error in parseXecSendValue: ' + err); + throw err; + } + return value; + }; + const sendXec = async ( BCH, wallet, @@ -1730,5 +1791,6 @@ handleEncryptedOpReturn, getRecipientPublicKey, burnEtoken, + parseXecSendValue, }; }