diff --git a/web/cashtab/src/components/Common/CustomIcons.js b/web/cashtab/src/components/Common/CustomIcons.js --- a/web/cashtab/src/components/Common/CustomIcons.js +++ b/web/cashtab/src/components/Common/CustomIcons.js @@ -23,7 +23,14 @@ preview={false} /> ); - +export const MessageSignedNotificationIcon = () => ( + +); export const ThemedCopyOutlined = styled(CopyOutlined)` color: ${props => props.theme.icons.outlined} !important; `; diff --git a/web/cashtab/src/components/Common/StyledCollapse.js b/web/cashtab/src/components/Common/StyledCollapse.js --- a/web/cashtab/src/components/Common/StyledCollapse.js +++ b/web/cashtab/src/components/Common/StyledCollapse.js @@ -51,3 +51,36 @@ } `} `; + +export const AdvancedCollapse = styled(Collapse)` + ${({ disabled = false, ...props }) => + disabled === true + ? ` + background: ${props.theme.buttons.secondary.background} !important; + .ant-collapse-header { + font-size: 18px; + font-weight: normal; + color: ${props.theme.buttons.secondary.color} !important; + svg { + color: ${props.theme.buttons.secondary.color} !important; + } + } + .ant-collapse-arrow { + font-size: 18px; + } + ` + : ` + background: ${props.theme.primary} !important; + .ant-collapse-header { + font-size: 18px; + font-weight: bold; + color: ${props.theme.contrast} !important; + svg { + color: ${props.theme.contrast} !important; + } + } + .ant-collapse-arrow { + font-size: 18px; + } + `} +`; diff --git a/web/cashtab/src/components/Configure/Configure.js b/web/cashtab/src/components/Configure/Configure.js --- a/web/cashtab/src/components/Configure/Configure.js +++ b/web/cashtab/src/components/Configure/Configure.js @@ -1,7 +1,7 @@ /* eslint-disable react-hooks/exhaustive-deps */ import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; -import { Collapse, Form, Input, Modal, Alert } from 'antd'; +import { Collapse, Form, Input, Modal, Alert, notification } from 'antd'; import { PlusSquareOutlined, WalletFilled, @@ -9,7 +9,10 @@ LockOutlined, } from '@ant-design/icons'; import { WalletContext } from '@utils/context'; -import { StyledCollapse } from '@components/Common/StyledCollapse'; +import { + StyledCollapse, + AdvancedCollapse, +} from '@components/Common/StyledCollapse'; import { AntdFormWrapper, CurrencySelectDropdown, @@ -28,6 +31,12 @@ import { Event } from '@utils/GoogleAnalytics'; import ApiError from '@components/Common/ApiError'; import { formatSavedBalance } from '@utils/validation'; +import WalletLabel from '@components/Common/WalletLabel.js'; +import Wallet from '@components/Wallet/Wallet'; +import { TokenParamLabel } from '@components/Common/Atoms'; +import Paragraph from 'antd/lib/typography/Paragraph'; +import { MessageSignedNotificationIcon } from '@components/Common/CustomIcons'; +import useBCH from '@hooks/useBCH'; const { Panel } = Collapse; @@ -210,10 +219,15 @@ margin: 60px 0 50px; `; -const Configure = () => { +const Configure = ({ jestBCH, passLoadingStatus }) => { const ContextValue = React.useContext(WalletContext); const { wallet, apiError } = ContextValue; - + const { getBCH, getRestUrl, sendBch, calcFee, signPkMessage } = useBCH(); + const BCH = jestBCH ? jestBCH : getBCH(); + // Modal settings + const [showConfirmMsgToSign, setShowConfirmMsgToSign] = useState(false); + const [msgToSign, setMsgToSign] = useState(''); + const [signMessageIsValid, setSignMessageIsValid] = useState(null); const { addNewSavedWallet, activateWallet, @@ -433,6 +447,49 @@ setConfirmationOfWalletToBeDeleted(value); }; + const handleSignMsgChange = e => { + const { value } = e.target; + // validation + if (value && value.length && value.length < 150) { + setMsgToSign(value); + setSignMessageIsValid(true); + } else { + setSignMessageIsValid(false); + } + }; + + const signMessageByPk = async () => { + try { + const messageSignature = await signPkMessage( + BCH, + wallet.Path1899.fundingWif, + msgToSign, + ); + + notification.success({ + message: 'Success', + description: ( + Message Signature: {messageSignature} + ), + icon: , + style: { width: '100%' }, + }); + } catch (err) { + let message; + if (!e.error && !e.message) { + message = e.message || e.error || JSON.stringify(e); + } + notification.error({ + message: 'Error', + description: message, + duration: 5, + }); + throw err; + } + // Hide the modal + setShowConfirmMsgToSign(false); + }; + return ( {walletToBeRenamed !== null && ( @@ -663,6 +720,64 @@ } /> + + setShowConfirmMsgToSign(false)} + > + Message: {msgToSign} +
+
+ + + +
+ + handleSignMsgChange(e)} + validateStatus={ + signMessageIsValid === null || + signMessageIsValid + ? '' + : 'error' + } + help={ + signMessageIsValid === null || + signMessageIsValid + ? '' + : 'Message must be between 1 and 150 characters' + } + maxLength="150" + /> + +
+
+ setShowConfirmMsgToSign(true)} + disabled={!signMessageIsValid} + > + +  Sign Message + +
+
[ You need some XEC in your wallet to create tokens. ,
0 @@ -60,7 +60,7 @@
,

You need at least @@ -83,14 +83,14 @@ exports[`Wallet with BCH balances and tokens 1`] = ` Array [

You need some XEC in your wallet to create tokens.
,
0 @@ -140,7 +140,7 @@
,

You need at least @@ -163,14 +163,14 @@ exports[`Wallet with BCH balances and tokens and state field 1`] = ` Array [

0.06047469 XEC
,
$ NaN @@ -226,10 +226,10 @@ onClick={[Function]} >
identicon of tokenId bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba
6.001 @@ -261,14 +261,14 @@ exports[`Wallet without BCH balance 1`] = ` Array [
You need some XEC in your wallet to create tokens.
,
0 @@ -318,7 +318,7 @@
,

You need at least @@ -341,14 +341,14 @@ exports[`Without wallet defined 1`] = ` Array [

You need some XEC in your wallet to create tokens.
,
0 @@ -398,7 +398,7 @@
,

You need at least 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 @@ -860,6 +860,19 @@ return link; }; + const signPkMessage = async (BCH, pk, message) => { + try { + let signature = await BCH.BitcoinCash.signMessageWithPrivKey( + pk, + message, + ); + return signature; + } catch (err) { + console.log(`useBCH.signPkMessage() error: `, err); + throw err; + } + }; + const sendBch = async ( BCH, wallet, @@ -1033,6 +1046,7 @@ parseTokenInfoForTxHistory, getTxData, getRestUrl, + signPkMessage, sendBch, sendToken, createToken,