diff --git a/web/cashtab/src/components/Send/Send.js b/web/cashtab/src/components/Send/Send.js --- a/web/cashtab/src/components/Send/Send.js +++ b/web/cashtab/src/components/Send/Send.js @@ -1,6 +1,15 @@ import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { WalletContext } from '@utils/context'; +import { + AntdFormWrapper, + SendBchInput, + FormItemWithQRCodeAddon, +} from '@components/Common/EnhancedInputs'; +import { + StyledCollapse, + AdvancedCollapse, +} from '@components/Common/StyledCollapse'; import { Form, message, @@ -10,21 +19,14 @@ Input, notification, } from 'antd'; +const { Panel } = Collapse; const { TextArea } = Input; import { Row, Col } from 'antd'; -import { - StyledCollapse, - AdvancedCollapse, -} from '@components/Common/StyledCollapse'; +import Paragraph from 'antd/lib/typography/Paragraph'; import PrimaryButton, { SecondaryButton, SmartButton, } from '@components/Common/PrimaryButton'; -import { - SendBchInput, - FormItemWithQRCodeAddon, - AntdFormWrapper, -} from '@components/Common/EnhancedInputs'; import useBCH from '@hooks/useBCH'; import useWindowDimensions from '@hooks/useWindowDimensions'; import { @@ -55,7 +57,6 @@ import Wallet from '@components/Wallet/Wallet'; import { TokenParamLabel } from '@components/Common/Atoms'; import { PlusSquareOutlined } from '@ant-design/icons'; -const { Panel } = Collapse; import styled from 'styled-components'; import { convertToEcashPrefix } from '@utils/cashMethods'; import { CopyToClipboard } from 'react-copy-to-clipboard'; @@ -186,6 +187,8 @@ return; } + let optionalOpReturnMsg = formData.opReturnMsg; + // Event("Category", "Action", "Label") // Track number of BCHA send transactions and whether users // are sending BCHA or USD @@ -236,6 +239,7 @@ cleanAddress, bchValue, currency.defaultFee, + optionalOpReturnMsg, ); sendXecNotification(link); } catch (e) { @@ -336,6 +340,15 @@ })); }; + const handleOpReturnMsgChange = e => { + const { value, name } = e.target; + + setFormData(p => ({ + ...p, + [name]: value, + })); + }; + const handleBchAmountChange = e => { const { value, name } = e.target; let bchValue = value; @@ -557,6 +570,47 @@ <ConvertAmount> {fiatPriceString !== '' && '='} {fiatPriceString} </ConvertAmount> + <div + style={{ + paddingTop: '32px', + }} + > + <AdvancedCollapse + style={{ + marginBottom: '24px', + }} + > + <Panel header="Advanced" key="1"> + <AntdFormWrapper> + <Form + size="small" + style={{ + width: 'auto', + }} + > + <Form.Item> + <Input + addonBefore="Message" + placeholder="Optional OP_RETURN Msg (max 150 chars)" + name="opReturnMsg" + onChange={e => + handleOpReturnMsgChange( + e, + ) + } + maxLength="150" + onKeyDown={e => + e.keyCode == 13 + ? e.preventDefault() + : '' + } + /> + </Form.Item> + </Form> + </AntdFormWrapper> + </Panel> + </AdvancedCollapse> + </div> <div style={{ paddingTop: '12px', diff --git a/web/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap b/web/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap --- a/web/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap +++ b/web/cashtab/src/components/Send/__tests__/__snapshots__/Send.test.js.snap @@ -30,7 +30,7 @@ } > <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -99,7 +99,7 @@ className="ant-input-group-addon" > <span - className="sc-gZMcBi kJTcOr" + className="sc-EHOje jPIGGt" onClick={[Function]} > <span @@ -140,7 +140,7 @@ </div> </div> <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -285,7 +285,7 @@ </span> </div> <span - className="sc-jzJRlG kQuQkS" + className="sc-iwsKbI bMOJU" disabled={false} onClick={[Function]} style={ @@ -320,6 +320,57 @@ $ NaN USD </div> + <div + style={ + Object { + "paddingTop": "32px", + } + } + > + <div + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" + role={null} + style={ + Object { + "marginBottom": "24px", + } + } + > + <div + className="ant-collapse-item" + > + <div + aria-expanded={false} + className="ant-collapse-header" + onClick={[Function]} + onKeyPress={[Function]} + role="button" + tabIndex={0} + > + <span + aria-label="right" + className="anticon anticon-right ant-collapse-arrow" + role="img" + > + <svg + aria-hidden="true" + data-icon="right" + fill="currentColor" + focusable="false" + height="1em" + viewBox="64 64 896 896" + width="1em" + > + <path + d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z" + /> + </svg> + </span> + Advanced + </div> + </div> + </div> + </div> <div style={ Object { @@ -328,7 +379,7 @@ } > <button - className="sc-dnqmqq fryMgW" + className="sc-fjdhpX eXuEIC" > Send </button> @@ -342,7 +393,7 @@ Signatures </div>, <div - className="ant-collapse ant-collapse-icon-position-left sc-gzVnrw fYpbQV" + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" role={null} style={ Object { @@ -417,7 +468,7 @@ } > <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -486,7 +537,7 @@ className="ant-input-group-addon" > <span - className="sc-gZMcBi kJTcOr" + className="sc-EHOje jPIGGt" onClick={[Function]} > <span @@ -527,7 +578,7 @@ </div> </div> <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -672,7 +723,7 @@ </span> </div> <span - className="sc-jzJRlG kQuQkS" + className="sc-iwsKbI bMOJU" disabled={false} onClick={[Function]} style={ @@ -707,6 +758,57 @@ $ NaN USD </div> + <div + style={ + Object { + "paddingTop": "32px", + } + } + > + <div + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" + role={null} + style={ + Object { + "marginBottom": "24px", + } + } + > + <div + className="ant-collapse-item" + > + <div + aria-expanded={false} + className="ant-collapse-header" + onClick={[Function]} + onKeyPress={[Function]} + role="button" + tabIndex={0} + > + <span + aria-label="right" + className="anticon anticon-right ant-collapse-arrow" + role="img" + > + <svg + aria-hidden="true" + data-icon="right" + fill="currentColor" + focusable="false" + height="1em" + viewBox="64 64 896 896" + width="1em" + > + <path + d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z" + /> + </svg> + </span> + Advanced + </div> + </div> + </div> + </div> <div style={ Object { @@ -715,7 +817,7 @@ } > <button - className="sc-dnqmqq fryMgW" + className="sc-fjdhpX eXuEIC" > Send </button> @@ -729,7 +831,7 @@ Signatures </div>, <div - className="ant-collapse ant-collapse-icon-position-left sc-gzVnrw fYpbQV" + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" role={null} style={ Object { @@ -811,7 +913,7 @@ } > <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -880,7 +982,7 @@ className="ant-input-group-addon" > <span - className="sc-gZMcBi kJTcOr" + className="sc-EHOje jPIGGt" onClick={[Function]} > <span @@ -921,7 +1023,7 @@ </div> </div> <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -1066,7 +1168,7 @@ </span> </div> <span - className="sc-jzJRlG kQuQkS" + className="sc-iwsKbI bMOJU" disabled={false} onClick={[Function]} style={ @@ -1101,6 +1203,57 @@ $ NaN USD </div> + <div + style={ + Object { + "paddingTop": "32px", + } + } + > + <div + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" + role={null} + style={ + Object { + "marginBottom": "24px", + } + } + > + <div + className="ant-collapse-item" + > + <div + aria-expanded={false} + className="ant-collapse-header" + onClick={[Function]} + onKeyPress={[Function]} + role="button" + tabIndex={0} + > + <span + aria-label="right" + className="anticon anticon-right ant-collapse-arrow" + role="img" + > + <svg + aria-hidden="true" + data-icon="right" + fill="currentColor" + focusable="false" + height="1em" + viewBox="64 64 896 896" + width="1em" + > + <path + d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z" + /> + </svg> + </span> + Advanced + </div> + </div> + </div> + </div> <div style={ Object { @@ -1109,7 +1262,7 @@ } > <button - className="sc-htoDjs jyAknT" + className="sc-jTzLTM iVNQiK" onClick={[Function]} > Send @@ -1124,7 +1277,7 @@ Signatures </div>, <div - className="ant-collapse ant-collapse-icon-position-left sc-gzVnrw fYpbQV" + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" role={null} style={ Object { @@ -1199,7 +1352,7 @@ } > <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -1268,7 +1421,7 @@ className="ant-input-group-addon" > <span - className="sc-gZMcBi kJTcOr" + className="sc-EHOje jPIGGt" onClick={[Function]} > <span @@ -1309,7 +1462,7 @@ </div> </div> <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -1454,7 +1607,7 @@ </span> </div> <span - className="sc-jzJRlG kQuQkS" + className="sc-iwsKbI bMOJU" disabled={false} onClick={[Function]} style={ @@ -1489,6 +1642,57 @@ $ NaN USD </div> + <div + style={ + Object { + "paddingTop": "32px", + } + } + > + <div + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" + role={null} + style={ + Object { + "marginBottom": "24px", + } + } + > + <div + className="ant-collapse-item" + > + <div + aria-expanded={false} + className="ant-collapse-header" + onClick={[Function]} + onKeyPress={[Function]} + role="button" + tabIndex={0} + > + <span + aria-label="right" + className="anticon anticon-right ant-collapse-arrow" + role="img" + > + <svg + aria-hidden="true" + data-icon="right" + fill="currentColor" + focusable="false" + height="1em" + viewBox="64 64 896 896" + width="1em" + > + <path + d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z" + /> + </svg> + </span> + Advanced + </div> + </div> + </div> + </div> <div style={ Object { @@ -1497,7 +1701,7 @@ } > <button - className="sc-dnqmqq fryMgW" + className="sc-fjdhpX eXuEIC" > Send </button> @@ -1511,7 +1715,7 @@ Signatures </div>, <div - className="ant-collapse ant-collapse-icon-position-left sc-gzVnrw fYpbQV" + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" role={null} style={ Object { @@ -1586,7 +1790,7 @@ } > <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -1655,7 +1859,7 @@ className="ant-input-group-addon" > <span - className="sc-gZMcBi kJTcOr" + className="sc-EHOje jPIGGt" onClick={[Function]} > <span @@ -1696,7 +1900,7 @@ </div> </div> <div - className="sc-jTzLTM fKDsMv" + className="sc-htoDjs ghcbdA" > <div className="ant-row ant-form-item" @@ -1841,7 +2045,7 @@ </span> </div> <span - className="sc-jzJRlG kQuQkS" + className="sc-iwsKbI bMOJU" disabled={false} onClick={[Function]} style={ @@ -1876,6 +2080,57 @@ $ NaN USD </div> + <div + style={ + Object { + "paddingTop": "32px", + } + } + > + <div + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" + role={null} + style={ + Object { + "marginBottom": "24px", + } + } + > + <div + className="ant-collapse-item" + > + <div + aria-expanded={false} + className="ant-collapse-header" + onClick={[Function]} + onKeyPress={[Function]} + role="button" + tabIndex={0} + > + <span + aria-label="right" + className="anticon anticon-right ant-collapse-arrow" + role="img" + > + <svg + aria-hidden="true" + data-icon="right" + fill="currentColor" + focusable="false" + height="1em" + viewBox="64 64 896 896" + width="1em" + > + <path + d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z" + /> + </svg> + </span> + Advanced + </div> + </div> + </div> + </div> <div style={ Object { @@ -1884,7 +2139,7 @@ } > <button - className="sc-dnqmqq fryMgW" + className="sc-fjdhpX eXuEIC" > Send </button> @@ -1898,7 +2153,7 @@ Signatures </div>, <div - className="ant-collapse ant-collapse-icon-position-left sc-gzVnrw fYpbQV" + className="ant-collapse ant-collapse-icon-position-left sc-VigVT idAASz" role={null} style={ Object { 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 @@ -902,6 +902,7 @@ destinationAddress, sendAmount, feeInSatsPerByte, + optionalOpReturnMsg, ) => { try { if (!sendAmount) { @@ -939,6 +940,23 @@ ); throw error; } + + // Start of building the OP_RETURN output. + // only build the OP_RETURN output if the user supplied it + if ( + typeof optionalOpReturnMsg !== 'undefined' && + optionalOpReturnMsg.trim() !== '' + ) { + const script = [ + BCH.Script.opcodes.OP_RETURN, + Buffer.from('6d02', 'hex'), + Buffer.from(optionalOpReturnMsg), + ]; + const data = BCH.Script.encode(script); + transactionBuilder.addOutput(data, 0); + } + // End of building the OP_RETURN output. + let originalAmount = new BigNumber(0); let txFee = 0; for (let i = 0; i < utxos.length; i++) {