diff --git a/app/actions/TrezorActions.js b/app/actions/TrezorActions.js
index b43a067f00..23b365ad5c 100644
--- a/app/actions/TrezorActions.js
+++ b/app/actions/TrezorActions.js
@@ -8,6 +8,7 @@ import {
accountPath,
addressPath
} from "helpers/trezor";
+import { putUint16, rawHashToHex } from "helpers/byteActions";
import { publishTransactionAttempt } from "./ControlActions";
import * as cfgConstants from "constants/config";
import {
@@ -24,6 +25,7 @@ import {
SIGNMESSAGE_SUCCESS
} from "./ControlActions";
import { getAmountFromTxInputs, getTxFromInputs } from "./TransactionActions";
+import { blake256 } from "walletCrypto";
const session = require("trezor-connect").default;
const {
@@ -40,6 +42,15 @@ const NOBACKUP = "no-backup";
const TRANSPORT_ERROR = "transport-error";
const TRANSPORT_START = "transport-start";
const BOOTLOADER_MODE = "bootloader";
+const testVotingKey = "PtWTXsGfk2YeqcmrRty77EsynNBtxWLLbsVEeTS8bKAGFoYF3qTNq";
+const testVotingAddr = "TsmfmUitQApgnNxQypdGd2x36djCCpDpERU";
+const SERTYPE_NOWITNESS = 1;
+const OP_SSGEN_STR = "bb";
+const OP_SSRTX_STR = "bc";
+const OP_TGEN_STR = "c3";
+const STAKE_REVOCATION = "SSRTX";
+const STAKE_GENERATION = "SSGen";
+const TREASURY_GENERATION = "TGen";
let setListeners = false;
@@ -441,8 +452,38 @@ const checkTrezorIsDcrwallet = () => async (dispatch, getState) => {
if (addrValidResp.index !== 0) throw "Wallet replied with wrong index.";
};
+// setStakeInputTypes adds a field to input that denotes stake spends. SSRTX
+function setStakeInputTypes(inputs, refTxs) {
+ const refs = {};
+ refTxs.forEach((ref) => (refs[ref.hash] = ref.bin_outputs));
+ // Search reference txs for the script that will be signed and determine if
+ // spending a stake output by comparing the first opcode to SSRTX or SSGEN
+ // opcodes.
+ for (let i = 0; i < inputs.length; i++) {
+ const input = inputs[i];
+ const bin_outputs = refs[input.prev_hash];
+ if (!bin_outputs) continue;
+ let s = bin_outputs[input.prev_index].script_pubkey;
+ if (s.length < 2) {
+ continue;
+ }
+ s = s.slice(0, 2);
+ switch (s) {
+ case OP_SSGEN_STR:
+ input.decred_staking_spend = STAKE_GENERATION;
+ break;
+ case OP_SSRTX_STR:
+ input.decred_staking_spend = STAKE_REVOCATION;
+ break;
+ case OP_TGEN_STR:
+ input.decred_staking_spend = TREASURY_GENERATION;
+ break;
+ }
+ }
+}
+
export const signTransactionAttemptTrezor =
- (rawUnsigTx, constructTxResponse) => async (dispatch, getState) => {
+ (rawUnsigTx, changeIndexes) => async (dispatch, getState) => {
dispatch({ type: SIGNTX_ATTEMPT });
const {
@@ -451,11 +492,9 @@ export const signTransactionAttemptTrezor =
} = getState();
const chainParams = selectors.chainParams(getState());
- debug && console.log("construct tx response", constructTxResponse);
+ debug && console.log("construct tx response", rawUnsigTx);
try {
- const changeIndex = constructTxResponse.changeIndex;
-
const decodedUnsigTxResp = wallet.decodeRawTransaction(
Buffer.from(rawUnsigTx, "hex"),
chainParams
@@ -472,13 +511,17 @@ export const signTransactionAttemptTrezor =
chainParams,
txCompletedInputs,
inputTxs,
- changeIndex
+ changeIndexes
);
const refTxs = await Promise.all(
inputTxs.map((inpTx) => walletTxToRefTx(walletService, inpTx))
);
+ // Determine if this is paying from a stakegen or revocation, which are
+ // special cases.
+ setStakeInputTypes(inputs, refTxs);
+
const payload = await deviceRun(dispatch, getState, async () => {
await dispatch(checkTrezorIsDcrwallet());
@@ -494,6 +537,7 @@ export const signTransactionAttemptTrezor =
dispatch({ type: SIGNTX_SUCCESS });
dispatch(publishTransactionAttempt(hexToBytes(signedRaw)));
+ return signedRaw;
} catch (error) {
dispatch({ error, type: SIGNTX_FAILED });
}
@@ -546,6 +590,7 @@ export const signMessageAttemptTrezor =
getSignMessageSignature: payload.signature,
type: SIGNMESSAGE_SUCCESS
});
+ return payload.signature;
} catch (error) {
dispatch({ error, type: SIGNMESSAGE_FAILED });
}
@@ -960,3 +1005,350 @@ export const getWalletCreationMasterPubKey =
throw error;
}
};
+
+export const TRZ_PURCHASETICKET_ATTEMPT = "TRZ_PURCHASETICKET_ATTEMPT";
+export const TRZ_PURCHASETICKET_FAILED = "TRZ_PURCHASETICKET_FAILED";
+export const TRZ_PURCHASETICKET_SUCCESS = "TRZ_PURCHASETICKET_SUCCESS";
+
+// ticketInOuts creates inputs and outputs for use with a trezor signature
+// request of a ticket.
+async function ticketInsOuts(
+ getState,
+ decodedTicket,
+ decodedInp,
+ refTxs,
+ votingAddr
+) {
+ const {
+ grpc: { walletService }
+ } = getState();
+ const chainParams = selectors.chainParams(getState());
+ const ticketOutN = decodedTicket.inputs[0].outputIndex;
+ const inAddr = decodedInp.outputs[ticketOutN].decodedScript.address;
+ let addrValidResp = await wallet.validateAddress(walletService, inAddr);
+ const inAddr_n = addressPath(
+ addrValidResp.index,
+ 1,
+ WALLET_ACCOUNT,
+ chainParams.HDCoinType
+ );
+ const commitAddr = decodedTicket.outputs[1].decodedScript.address;
+ addrValidResp = await wallet.validateAddress(walletService, commitAddr);
+ const commitAddr_n = addressPath(
+ addrValidResp.index,
+ 1,
+ WALLET_ACCOUNT,
+ chainParams.HDCoinType
+ );
+ const inputAmt = decodedTicket.inputs[0].valueIn.toString();
+ const ticketInput = {
+ address_n: inAddr_n,
+ prev_hash: decodedTicket.inputs[0].prevTxId,
+ prev_index: ticketOutN,
+ amount: inputAmt
+ };
+ const sstxsubmission = {
+ script_type: "PAYTOADDRESS",
+ address: votingAddr,
+ amount: decodedTicket.outputs[0].value.toString()
+ };
+ const ticketsstxcommitment = {
+ script_type: "PAYTOADDRESS",
+ address_n: commitAddr_n,
+ amount: inputAmt
+ };
+ const ticketsstxchange = {
+ script_type: "PAYTOADDRESS",
+ address: decodedTicket.outputs[2].decodedScript.address,
+ amount: "0"
+ };
+ const inputs = [ticketInput];
+ const outputs = [sstxsubmission, ticketsstxcommitment, ticketsstxchange];
+ return { inputs, outputs };
+}
+
+export const purchaseTicketsAttempt =
+ (accountNum, numTickets, vsp) => async (dispatch, getState) => {
+ dispatch({ type: TRZ_PURCHASETICKET_ATTEMPT });
+
+ if (noDevice(getState)) {
+ dispatch({
+ error: "Device not connected",
+ type: TRZ_PURCHASETICKET_FAILED
+ });
+ return;
+ }
+
+ const {
+ grpc: { walletService }
+ } = getState();
+ const chainParams = selectors.chainParams(getState());
+
+ try {
+ // TODO: Enable on mainnet. The following todo on crypto magic must be
+ // implemented first. Revocation logic and a re-fee payment method must be
+ // added.
+ if (chainParams.trezorCoinName != "Decred Testnet")
+ throw "can only be used on testnet";
+ // TODO: Fill this with deterministic crypto magic.
+ const votingKey = testVotingKey;
+ const votingAddr = testVotingAddr;
+ const res = await wallet.purchaseTickets(
+ walletService,
+ accountNum,
+ numTickets,
+ false,
+ vsp,
+ {}
+ );
+ const splitTx = res.splitTx;
+ const decodedInp = await wallet.decodeTransactionLocal(
+ splitTx,
+ chainParams
+ );
+ const changeIndexes = [];
+ for (let i = 0; i < decodedInp.outputs.length; i++) {
+ changeIndexes.push(i);
+ }
+ const signedSplitTx = await signTransactionAttemptTrezor(
+ splitTx,
+ changeIndexes
+ )(dispatch, getState);
+ if (!signedSplitTx) throw "failed to sign splittx";
+ const refTxs = await walletTxToRefTx(walletService, decodedInp);
+
+ for (const ticket of res.ticketsList) {
+ const decodedTicket = await wallet.decodeTransactionLocal(
+ ticket,
+ chainParams
+ );
+ refTxs.hash = decodedTicket.inputs[0].prevTxId;
+ const { inputs, outputs } = await ticketInsOuts(
+ getState,
+ decodedTicket,
+ decodedInp,
+ refTxs,
+ votingAddr
+ );
+ const payload = await deviceRun(dispatch, getState, async () => {
+ const res = await session.signTransaction({
+ coin: chainParams.trezorCoinName,
+ inputs: inputs,
+ outputs: outputs,
+ refTxs: [refTxs],
+ decredStakingTicket: true
+ });
+ return res.payload;
+ });
+
+ const signedRaw = payload.serializedTx;
+ dispatch(publishTransactionAttempt(hexToBytes(signedRaw)));
+ // Pay fee.
+ console.log(
+ "waiting 5 seconds for the ticket to propogate throughout the network"
+ );
+ await new Promise((r) => setTimeout(r, 5000));
+ const host = "https://" + vsp.host;
+ await payVSPFee(
+ host,
+ signedRaw,
+ signedSplitTx,
+ votingKey,
+ accountNum.value,
+ true,
+ dispatch,
+ getState
+ );
+ }
+ dispatch({ type: TRZ_PURCHASETICKET_SUCCESS });
+ } catch (error) {
+ dispatch({ error, type: TRZ_PURCHASETICKET_FAILED });
+ }
+ };
+
+// payVSPFee attempts to contact a vsp about a ticket and pay the fee if
+// necessary. It will search transacitons for a suitable fee transaction before
+// attempting to pay if newTicket is false.
+async function payVSPFee(
+ host,
+ txHex,
+ parentTxHex,
+ votingKey,
+ accountNum,
+ newTicket,
+ dispatch,
+ getState
+) {
+ const {
+ grpc: { walletService }
+ } = getState();
+ // Gather information about the ticket.
+ const chainParams = selectors.chainParams(getState());
+ const txBytes = hexToBytes(txHex);
+ const decodedTicket = await wallet.decodeTransactionLocal(
+ txBytes,
+ chainParams
+ );
+ const commitmentAddr = decodedTicket.outputs[1].decodedScript.address;
+
+ const prefix = txBytes.slice(0, decodedTicket.prefixOffset);
+ prefix.set(putUint16(SERTYPE_NOWITNESS), 2);
+ const txid = rawHashToHex(blake256(prefix));
+
+ // Request fee info from the vspd.
+ let req = {
+ timestamp: +new Date(),
+ tickethash: txid,
+ tickethex: txHex,
+ parenthex: parentTxHex
+ };
+ let jsonStr = JSON.stringify(req);
+ let sig = await signMessageAttemptTrezor(commitmentAddr, jsonStr)(
+ dispatch,
+ getState
+ );
+ if (!sig) throw "unable to sign fee address message";
+ wallet.allowVSPHost(host);
+ // This will throw becuase of http.status 400 if already paid.
+ // TODO: Investigate whether other fee payment errors will cause this to
+ // throw. Other fee payment errors should continue, and we should only stop
+ // here if already paid or the ticket is not found by the vsp.
+ let res = null;
+ try {
+ res = await wallet.getVSPFeeAddress({ host, sig, req });
+ } catch (error) {
+ if (error.response && error.response.data && error.response.data.message) {
+ // NOTE: already paid is error.response.data.code == 3
+ throw error.response.data.message;
+ }
+ throw error;
+ }
+ const payAddr = res.data.feeaddress;
+ const fee = res.data.feeamount;
+
+ // Find the fee transaction or make a new one.
+ let feeTx = null;
+ // Do not search for the fee tx of a new ticket.
+ if (!newTicket) {
+ feeTx = await findFeeTx(payAddr, fee, dispatch, getState);
+ }
+ if (!feeTx) {
+ const outputs = [{ destination: payAddr, amount: fee }];
+ const txResp = await wallet.constructTransaction(
+ walletService,
+ accountNum,
+ 0,
+ outputs
+ );
+ const unsignedTx = txResp.unsignedTransaction;
+ const decodedInp = await wallet.decodeTransactionLocal(
+ unsignedTx,
+ chainParams
+ );
+ let changeIndex = 0;
+ for (const out of decodedInp.outputs) {
+ const addr = out.decodedScript.address;
+ const addrValidResp = await wallet.validateAddress(walletService, addr);
+ if (addrValidResp.isInternal) {
+ break;
+ }
+ changeIndex++;
+ }
+ const success = await signTransactionAttemptTrezor(unsignedTx, [
+ changeIndex
+ ])(dispatch, getState);
+ if (!success) throw "unable to sign fee tx";
+ for (let i = 0; i < 5; i++) {
+ console.log(
+ "waiting 5 seconds for the fee tx to propogate throughout the network"
+ );
+ await new Promise((r) => setTimeout(r, 5000));
+ feeTx = await findFeeTx(payAddr, fee, dispatch, getState);
+ if (feeTx) break;
+ }
+ if (!feeTx) throw "unable to find fee tx " + rawToHex(unsignedTx);
+ }
+
+ // Send ticket fee data and voting chioces back to the vsp.
+ const {
+ grpc: { votingService }
+ } = getState();
+ const voteChoicesRes = await wallet.getVoteChoices(votingService);
+ const voteChoices = {};
+ for (const choice of voteChoicesRes.choicesList) {
+ voteChoices[choice.agendaId] = choice.choiceId;
+ }
+ req = {
+ timestamp: +new Date(),
+ tickethash: txid,
+ feetx: feeTx,
+ votingkey: votingKey,
+ votechoices: voteChoices
+ };
+ jsonStr = JSON.stringify(req);
+ sig = await signMessageAttemptTrezor(commitmentAddr, jsonStr)(
+ dispatch,
+ getState
+ );
+ if (!sig) throw "unable to sign fee tx message";
+ wallet.allowVSPHost(host);
+ await wallet.payVSPFee({ host, sig, req });
+}
+
+// findFeeTx searches unmined and recent transactions for a tx that pays to
+// FeeAddr of the amount feeAmt. It stops searching below a resonable depth for
+// a ticket.
+async function findFeeTx(feeAddr, feeAmt, dispatch, getState) {
+ const {
+ grpc: { walletService }
+ } = getState();
+ const chainParams = selectors.chainParams(getState());
+ // findFee looks for a transaction the paid out exactl feeAmt and has an
+ // output address that matches feeAddr.
+ const findFee = async (res) => {
+ for (const credit of res) {
+ if (credit.txType != "sent" && credit.txType != "regular") continue;
+ const sentAmt = Math.abs(credit.amount + credit.fee);
+ if (sentAmt == feeAmt) {
+ const tx = await wallet.decodeTransactionLocal(
+ hexToBytes(credit.rawTx),
+ chainParams
+ );
+ if (
+ tx.outputs.find(
+ (e) => e.decodedScript && e.decodedScript.address == feeAddr
+ )
+ )
+ return credit.rawTx;
+ }
+ }
+ return null;
+ };
+ // First search mempool.
+ const { unmined } = await wallet.getTransactions(walletService, -1, -1, 0);
+ const feeTx = await findFee(unmined);
+ if (feeTx) return feeTx;
+ // TODO: Take these constants from the chainparams.
+ const ticketMaturity = 256;
+ const ticketExpiry = 40960;
+ const { currentBlockHeight } = getState().grpc;
+ let start = currentBlockHeight - 100;
+ let end = currentBlockHeight;
+ const maxAge = currentBlockHeight - (ticketMaturity + ticketExpiry);
+ const blockIncrement = 100;
+ // Search mined txs in reverse order up until a ticket must have expired on
+ // mainnet.
+ while (start > maxAge) {
+ const { mined } = await wallet.getTransactions(
+ walletService,
+ start,
+ end,
+ 0
+ );
+ start -= blockIncrement;
+ end -= blockIncrement;
+ const feeTx = await findFee(mined);
+ if (feeTx) return feeTx;
+ }
+ return null;
+}
diff --git a/app/components/SideBar/AccountsList/AccountsList.jsx b/app/components/SideBar/AccountsList/AccountsList.jsx
index 84802e5c17..b03ddbe892 100644
--- a/app/components/SideBar/AccountsList/AccountsList.jsx
+++ b/app/components/SideBar/AccountsList/AccountsList.jsx
@@ -20,7 +20,8 @@ const AccountsList = ({
className={classNames(
style.extended,
isShowingAccounts && style.showingAccounts
- )}>
+ )}
+ >
{balances.map(
({ hidden, total, accountName, accountNumber }) =>
@@ -32,7 +33,8 @@ const AccountsList = ({
isMixed(accountNumber) && style.mixed,
isChange(accountNumber) && style.unmixed
)}
- key={accountName}>
+ key={accountName}
+ >
{accountName === "default" ? (
diff --git a/app/components/SideBar/Logo/Logo.jsx b/app/components/SideBar/Logo/Logo.jsx
index b4ccecd89d..7d922052b5 100644
--- a/app/components/SideBar/Logo/Logo.jsx
+++ b/app/components/SideBar/Logo/Logo.jsx
@@ -20,7 +20,8 @@ const Logo = React.memo(
id="sidebar.isWatchingOnlyTooltip"
m="This is a watch-only wallet with limited functionality."
/>
- }>
+ }
+ >
)}
@@ -46,7 +47,8 @@ const Logo = React.memo(
the background: Privacy Mixer, Ticket Auto Buyer, Purchase Ticket
Attempt`}
/>
- }>
+ }
+ >
)}
diff --git a/app/components/SideBar/MenuBottom/MenuBottomExpanded.jsx b/app/components/SideBar/MenuBottom/MenuBottomExpanded.jsx
index 1ad26f939d..2e93d5eff2 100644
--- a/app/components/SideBar/MenuBottom/MenuBottomExpanded.jsx
+++ b/app/components/SideBar/MenuBottom/MenuBottomExpanded.jsx
@@ -26,12 +26,14 @@ const MenuBarExpanded = ({
className={styles.short}
onMouseEnter={rescanRequest ? null : onShowAccounts}
onMouseLeave={rescanRequest ? null : onHideAccounts}
- onWheel={onAccountsListWheel}>
+ onWheel={onAccountsListWheel}
+ >
+ )}
+ >
:
diff --git a/app/components/SideBar/MenuBottom/SettingsIconLink/SettingsIconLink.jsx b/app/components/SideBar/MenuBottom/SettingsIconLink/SettingsIconLink.jsx
index dd91a87f66..22e513b2c0 100644
--- a/app/components/SideBar/MenuBottom/SettingsIconLink/SettingsIconLink.jsx
+++ b/app/components/SideBar/MenuBottom/SettingsIconLink/SettingsIconLink.jsx
@@ -6,7 +6,8 @@ import styles from "./SettingsIconLink.module.css";
const SettingsIconLink = ({ className }) => (
}>
+ content={}
+ >
diff --git a/app/components/SideBar/MenuBottom/SpvIcon/SpvIcon.jsx b/app/components/SideBar/MenuBottom/SpvIcon/SpvIcon.jsx
index ac03e408eb..024a18ddb5 100644
--- a/app/components/SideBar/MenuBottom/SpvIcon/SpvIcon.jsx
+++ b/app/components/SideBar/MenuBottom/SpvIcon/SpvIcon.jsx
@@ -12,7 +12,8 @@ const SpvIcon = ({ isSPV }) => (
) : (
)
- }>
+ }
+ >
);
diff --git a/app/components/SideBar/MenuLinks/MenuLinks.jsx b/app/components/SideBar/MenuLinks/MenuLinks.jsx
index b755aa4da2..31393a6190 100644
--- a/app/components/SideBar/MenuLinks/MenuLinks.jsx
+++ b/app/components/SideBar/MenuLinks/MenuLinks.jsx
@@ -29,7 +29,8 @@ const MenuLinks = () => {
"tab-default-background": getThemeProperty(theme, "sidebar-color"),
"tab-default-color": getThemeProperty(theme, "sidebar-color"),
"tab-secondary-active-color": getThemeProperty(theme, "sidebar-color")
- }}>
+ }}
+ >
{
styles.tabs,
expandSideBar && styles.expanded,
sidebarOnBottom && styles.onBottom
- )}>
+ )}
+ >
{menuLinks.map((menuLink, index) => {
const menuLinkLabel = () => (
+ data-testid={`menuLinkContent-${menuLink.icon}`}
+ >
{
+ placement={sidebarOnBottom ? "top" : "right"}
+ >
{menuLinkLabel()}
);
diff --git a/app/components/SideBar/SideBar.jsx b/app/components/SideBar/SideBar.jsx
index a1b7d83ae7..0567d74177 100644
--- a/app/components/SideBar/SideBar.jsx
+++ b/app/components/SideBar/SideBar.jsx
@@ -43,7 +43,8 @@ const SideBar = () => {
uiAnimations && style.animated,
!expandSideBar && style.sidebarReduced,
!expandSideBar && sidebarOnBottom && style.sidebarOnBottom
- )}>
+ )}
+ >
{
className={classNames(
style.sidebarMain,
isShowingAccounts && style.isShowingAccounts
- )}>
+ )}
+ >
+ onClick={onDismissMessage}
+ >
)}
diff --git a/app/components/Snackbar/Notification/Transaction.jsx b/app/components/Snackbar/Notification/Transaction.jsx
index 324e4e3239..c74e48778a 100644
--- a/app/components/Snackbar/Notification/Transaction.jsx
+++ b/app/components/Snackbar/Notification/Transaction.jsx
@@ -53,7 +53,8 @@ const Transaction = ({
)}
@@ -89,7 +90,8 @@ const Transaction = ({
+ to={`/transactions/history/${message.txHash}`}
+ >
{message.txHash}
diff --git a/app/components/Snackbar/index.js b/app/components/Snackbar/index.js
index 62bfa0f096..e1470da0e9 100644
--- a/app/components/Snackbar/index.js
+++ b/app/components/Snackbar/index.js
@@ -78,7 +78,8 @@ const Snackbar = () => {
className={snackbarClasses(message || "")}
onMouseEnter={clearHideTimer}
onMouseLeave={enableHideTimer}
- style={{ bottom: "0px" }}>
+ style={{ bottom: "0px" }}
+ >
{
onMouseEnter={clearHideTimer}
onMouseLeave={enableHideTimer}
style={s.style}
- ref={(ref) => animatedNotifRef(s.key, ref)}>
+ ref={(ref) => animatedNotifRef(s.key, ref)}
+ >
{
!disabled && onClick?.(e);
}}
- hidden={hidden}>
+ hidden={hidden}
+ >
{loading ? : children}
);
diff --git a/app/components/buttons/CopyToClipboardButton/CopyToClipboardButton.jsx b/app/components/buttons/CopyToClipboardButton/CopyToClipboardButton.jsx
index a7e552fa57..8d00439a68 100644
--- a/app/components/buttons/CopyToClipboardButton/CopyToClipboardButton.jsx
+++ b/app/components/buttons/CopyToClipboardButton/CopyToClipboardButton.jsx
@@ -22,10 +22,8 @@ const CopyToClipboardButton = ({ textToCopy, className }) => {
return (
+ className={classNames(styles.success, isSuccessHidden && styles.hidden)}
+ >
{
onAddAllowedRequestType(requestType).then(() => onClick && onClick())
- }>
+ }
+ >
{children}
);
diff --git a/app/components/buttons/EyeFilterMenu/EyeFilterMenu.jsx b/app/components/buttons/EyeFilterMenu/EyeFilterMenu.jsx
index c23f4d9454..5d66207f96 100644
--- a/app/components/buttons/EyeFilterMenu/EyeFilterMenu.jsx
+++ b/app/components/buttons/EyeFilterMenu/EyeFilterMenu.jsx
@@ -48,7 +48,8 @@ const EyeFilterMenu = ({
)}
onClick={(e) =>
onMenuChanged(e, { value: option.value, key: option.key })
- }>
+ }
+ >
{option.label}
))}
@@ -60,7 +61,8 @@ const EyeFilterMenu = ({
return (
+ ref={wrapperRef}
+ >
+ className={styles.kebab}
+ >
(
wallet.openExternalURL(href)}>
+ onClick={onClick ? onClick : () => wallet.openExternalURL(href)}
+ >
{title}
{subtitle}
diff --git a/app/components/buttons/ModalButton.jsx b/app/components/buttons/ModalButton.jsx
index debe7e2ba1..ccc4780382 100644
--- a/app/components/buttons/ModalButton.jsx
+++ b/app/components/buttons/ModalButton.jsx
@@ -10,7 +10,8 @@ const defaultButton = ({
diff --git a/app/components/buttons/PathButton/PathButton.jsx b/app/components/buttons/PathButton/PathButton.jsx
index ff2897942a..9b22da1edf 100644
--- a/app/components/buttons/PathButton/PathButton.jsx
+++ b/app/components/buttons/PathButton/PathButton.jsx
@@ -5,7 +5,8 @@ import styles from "./PathButton.module.css";
const PathButton = ({ disabled, onClick }) => (
}>
+ content={
}
+ >
onClick("right") : null}>
+ onClick={activeButton == "left" ? () => onClick("right") : null}
+ >
{rightText}
diff --git a/app/components/buttons/ToggleSwitch/ToggleSwitch.jsx b/app/components/buttons/ToggleSwitch/ToggleSwitch.jsx
index 472dcbdb3c..64ae2639b2 100644
--- a/app/components/buttons/ToggleSwitch/ToggleSwitch.jsx
+++ b/app/components/buttons/ToggleSwitch/ToggleSwitch.jsx
@@ -25,7 +25,8 @@ const ToggleSwitch = ({
contentClassName={classNames(styles.tooltip, tooltipClassName)}
content={
disabled ? disabledText : enabled ? enabledText : notEnabledText
- }>
+ }
+ >
{
stackOffset="sign"
width={chartSize.width}
height={chartSize.height}
- data={displayData}>
+ data={displayData}
+ >
{
+ style={{ background: entry.fill }}
+ >
{entry.dataKey}:
{
+ style={{ background: entry.fill }}
+ >
{
stackOffset="sign"
width={chartSize.width}
height={chartSize.height}
- data={displayData}>
+ data={displayData}
+ >
{
stackOffset="sign"
width={chartSize.width}
height={chartSize.height}
- data={displayData}>
+ data={displayData}
+ >
{
stackOffset="sign"
width={chartSize.width}
height={chartSize.height}
- data={displayData}>
+ data={displayData}
+ >
{
stackOffset="sign"
width={chartSize.width}
height={chartSize.height}
- data={displayData}>
+ data={displayData}
+ >
}>
+ content={}
+ >
@@ -191,7 +192,8 @@ const AnimatedLinearProgressFull = ({
<>
+ className={styles.openWalletButton}
+ >
+ className={styles.cancelLoadingButton}
+ >
)
diff --git a/app/components/indicators/LinearProgress/LinearProgressSmall.jsx b/app/components/indicators/LinearProgress/LinearProgressSmall.jsx
index 2dc54efabe..273f6cb26b 100644
--- a/app/components/indicators/LinearProgress/LinearProgressSmall.jsx
+++ b/app/components/indicators/LinearProgress/LinearProgressSmall.jsx
@@ -8,13 +8,15 @@ const LinearProgressSmall = ({ value, min, max, className, barClassName }) => (
style.small,
className && className
)}
- data-testid="linear-prgress-small">
+ data-testid="linear-prgress-small"
+ >
+ style={{ width: `${((value - min) / (max - min)) * 100}%` }}
+ >
);
diff --git a/app/components/indicators/LoadingMoreTickets/LoadingMoreTickets.jsx b/app/components/indicators/LoadingMoreTickets/LoadingMoreTickets.jsx
index edd47b9576..0951a6bf22 100644
--- a/app/components/indicators/LoadingMoreTickets/LoadingMoreTickets.jsx
+++ b/app/components/indicators/LoadingMoreTickets/LoadingMoreTickets.jsx
@@ -41,15 +41,13 @@ const LoadingMoreTicketsIndicator = ({
return stakeTransactionsCancel ? (
+ className={classNames(styles.loadingMoreTickets, styles.isRow, className)}
+ >
{startRequestHeight && (
<>
+ className={classNames(styles.isRow, styles.loadingMoreTicketsInfo)}
+ >
- }>
+ }
+ >
) : (
+ className={classNames(styles.loadingMoreTickets, styles.isRow, className)}
+ >
{startRequestHeight && (
<>
+ className={classNames(styles.isRow, styles.loadingMoreTicketsInfo)}
+ >
!transactionsRequestAttempt && getTickets()}>
<>
@@ -115,7 +112,8 @@ const LoadingMoreTicketsIndicator = ({
id="mytickets.loadingMoreTickets.cancelBtn"
m={"Cancel listing tickets"}
/>
- }>
+ }
+ >
{
return (
+ data-testid="voting-progress"
+ >
+ )}
+ >
{props.data.name}
{!hideSpendable && (
@@ -64,7 +65,8 @@ const AccountsSelect = ({
return (
+ data-testid="accountsSelect"
+ >
diff --git a/app/components/inputs/Input/Input.jsx b/app/components/inputs/Input/Input.jsx
index 28dab8e8bf..d6607bcb10 100644
--- a/app/components/inputs/Input/Input.jsx
+++ b/app/components/inputs/Input/Input.jsx
@@ -102,14 +102,16 @@ const Input = ({
onKeyDown={onInputKeyDown}
data-testid={dataTestId}
maxLength={maxLength}
- aria-labelledby={ariaLabelledBy}>
+ aria-labelledby={ariaLabelledBy}
+ >
{unit && (
+ )}
+ >
{unit}
)}
diff --git a/app/components/inputs/NumTicketsInput/NumTicketsInput.jsx b/app/components/inputs/NumTicketsInput/NumTicketsInput.jsx
index ad9d1d95b8..344096d564 100644
--- a/app/components/inputs/NumTicketsInput/NumTicketsInput.jsx
+++ b/app/components/inputs/NumTicketsInput/NumTicketsInput.jsx
@@ -45,7 +45,8 @@ const NumTicketsInput = ({
onChangeNumTickets && onChangeNumTickets(e.target.value)
}
data-max-width="70"
- {...props}>
+ {...props}
+ >
{ticketUnitLabel}
{
onClick={(e) => {
e.preventDefault();
togglePasswordVisibility();
- }}>
+ }}
+ >
)}
diff --git a/app/components/inputs/PathBrowseInput/PathBrowseInput.jsx b/app/components/inputs/PathBrowseInput/PathBrowseInput.jsx
index ee7ba2aca4..a08453cc34 100644
--- a/app/components/inputs/PathBrowseInput/PathBrowseInput.jsx
+++ b/app/components/inputs/PathBrowseInput/PathBrowseInput.jsx
@@ -47,7 +47,8 @@ const PathBrowseInput = ({ intl, filters, save, type, onChange, ...props }) => {
type="text"
onChange={(e) => onChange(e.target.value)}
inputClassNames={style.textInput}
- {...props}>
+ {...props}
+ >
);
diff --git a/app/components/inputs/VSPSelect/VSPSelect.jsx b/app/components/inputs/VSPSelect/VSPSelect.jsx
index 93b4f87604..4a3b0d386d 100644
--- a/app/components/inputs/VSPSelect/VSPSelect.jsx
+++ b/app/components/inputs/VSPSelect/VSPSelect.jsx
@@ -73,12 +73,14 @@ function VSPSelect({
/>
)}
- }>
+ }
+ >
+ )}
+ >
{vsp.host}
diff --git a/app/components/layout/PageBody/PageBody.jsx b/app/components/layout/PageBody/PageBody.jsx
index ffa314cddd..f1602ce22e 100644
--- a/app/components/layout/PageBody/PageBody.jsx
+++ b/app/components/layout/PageBody/PageBody.jsx
@@ -13,7 +13,8 @@ const PageBody = ({ className, getStarted, children, isTestNet, ...props }) => {
getStarted && styles.getstarted,
isTestNet && styles.testnetBody,
className
- )}>
+ )}
+ >
{children}
diff --git a/app/components/layout/TabbedPage/TabbedPage.jsx b/app/components/layout/TabbedPage/TabbedPage.jsx
index cbfcdeb9a3..4d2966147c 100644
--- a/app/components/layout/TabbedPage/TabbedPage.jsx
+++ b/app/components/layout/TabbedPage/TabbedPage.jsx
@@ -59,7 +59,8 @@ const TabbedPage = ({
styles.tabContent,
tabContentClassName
)}
- contentAnimation={uiAnimations ? "slide" : "none"}>
+ contentAnimation={uiAnimations ? "slide" : "none"}
+ >
{tabs
.filter(({ disabled }) => !disabled)
.map(({ label, content, path, props, key }) => {
@@ -75,7 +76,8 @@ const TabbedPage = ({
+ className={styles.tabContentContainer}
+ >
{element}
diff --git a/app/components/modals/AboutModal/AboutModal.jsx b/app/components/modals/AboutModal/AboutModal.jsx
index 29b52335de..2166304dcb 100644
--- a/app/components/modals/AboutModal/AboutModal.jsx
+++ b/app/components/modals/AboutModal/AboutModal.jsx
@@ -47,13 +47,15 @@ const AboutModal = ({ show, onCancelModal }) => {
{updateAvailable ? (
+ className={styles.upgrade}
+ >
) : (
+ className={styles.upgrade}
+ >
)}
diff --git a/app/components/modals/AppPassAndPassphraseModal/AppPassAndPassphraseModalContent.jsx b/app/components/modals/AppPassAndPassphraseModal/AppPassAndPassphraseModalContent.jsx
index 8a61bfd261..12c0fc8a35 100644
--- a/app/components/modals/AppPassAndPassphraseModal/AppPassAndPassphraseModalContent.jsx
+++ b/app/components/modals/AppPassAndPassphraseModal/AppPassAndPassphraseModalContent.jsx
@@ -28,7 +28,8 @@ const Modal = ({
...props,
onSubmit,
parentIsValid: isValid
- }}>
+ }}
+ >
+ }
+ >
diff --git a/app/components/modals/ChangePassphraseModal/ChangePassphraseModalContent.jsx b/app/components/modals/ChangePassphraseModal/ChangePassphraseModalContent.jsx
index 8d51c22797..6dd9bd9c57 100644
--- a/app/components/modals/ChangePassphraseModal/ChangePassphraseModalContent.jsx
+++ b/app/components/modals/ChangePassphraseModal/ChangePassphraseModalContent.jsx
@@ -56,7 +56,8 @@ const Modal = ({
...props,
onSubmit,
parentIsValid: isValid
- }}>
+ }}
+ >
(
+ {...{ show, onCancelModal }}
+ >
diff --git a/app/components/modals/InfoModal/InfoModal.jsx b/app/components/modals/InfoModal/InfoModal.jsx
index bb88dcaf8f..7d44a9b6bb 100644
--- a/app/components/modals/InfoModal/InfoModal.jsx
+++ b/app/components/modals/InfoModal/InfoModal.jsx
@@ -15,7 +15,8 @@ const InfoModal = ({
}) => (
+ {...{ show, onCancelModal, draggable }}
+ >
{modalTitle ? <>{modalTitle}> : null}
{modalContent}
diff --git a/app/components/modals/LNInvoiceModal/LNInvoiceModal.jsx b/app/components/modals/LNInvoiceModal/LNInvoiceModal.jsx
index cc821808bd..17591c7d8d 100644
--- a/app/components/modals/LNInvoiceModal/LNInvoiceModal.jsx
+++ b/app/components/modals/LNInvoiceModal/LNInvoiceModal.jsx
@@ -92,7 +92,8 @@ const LNInvoiceModal = ({
isCancelButtonDisabled && styles.disabled
)}
onClick={onCancelInvoice}
- disabled={isCancelButtonDisabled}>
+ disabled={isCancelButtonDisabled}
+ >
@@ -110,7 +111,8 @@ const LNInvoiceModal = ({
+ truncate={false}
+ >
{invoice?.paymentRequest}
)}
diff --git a/app/components/modals/LNPaymentModal/LNPaymentModal.jsx b/app/components/modals/LNPaymentModal/LNPaymentModal.jsx
index de78c6265c..c645fa1060 100644
--- a/app/components/modals/LNPaymentModal/LNPaymentModal.jsx
+++ b/app/components/modals/LNPaymentModal/LNPaymentModal.jsx
@@ -52,7 +52,8 @@ const LNPaymentModal = ({ show, onCancelModal, tsDate, payment }) => (
+ truncate={false}
+ >
{payment.paymentRequest}
>
diff --git a/app/components/modals/Modal/Modal.jsx b/app/components/modals/Modal/Modal.jsx
index d3d5a2924a..720436b07d 100644
--- a/app/components/modals/Modal/Modal.jsx
+++ b/app/components/modals/Modal/Modal.jsx
@@ -24,7 +24,8 @@ const Modal = showCheck(({ children, className, draggable, onCancelModal }) => {
: styles.standalone,
className,
draggable && styles.draggable
- )}>
+ )}
+ >
{children}
);
@@ -38,7 +39,8 @@ const Modal = showCheck(({ children, className, draggable, onCancelModal }) => {
? styles.overlay
: styles.overlayReducedBar
: styles.overlayStandalone
- }>
+ }
+ >
{draggable ? (
{innerView}
diff --git a/app/components/modals/PassphraseModal/PassphraseModalContent.jsx b/app/components/modals/PassphraseModal/PassphraseModalContent.jsx
index 326f026b94..ab25700b73 100644
--- a/app/components/modals/PassphraseModal/PassphraseModalContent.jsx
+++ b/app/components/modals/PassphraseModal/PassphraseModalContent.jsx
@@ -38,7 +38,8 @@ const Modal = ({
}) => (
+ {...{ show, onCancelModal }}
+ >
diff --git a/app/components/modals/QRModal/QRModal.jsx b/app/components/modals/QRModal/QRModal.jsx
index c87c20b2ad..78421e0bfa 100644
--- a/app/components/modals/QRModal/QRModal.jsx
+++ b/app/components/modals/QRModal/QRModal.jsx
@@ -14,7 +14,8 @@ const QRModal = ({
}) => (
+ {...{ show, onCancelModal, draggable }}
+ >
{modalTitle && modalTitle}
{modalContent}
diff --git a/app/components/modals/SearchForNodesModal/NodeListElement/NodeListElement.jsx b/app/components/modals/SearchForNodesModal/NodeListElement/NodeListElement.jsx
index 0e7bb4b944..b1d4f090bb 100644
--- a/app/components/modals/SearchForNodesModal/NodeListElement/NodeListElement.jsx
+++ b/app/components/modals/SearchForNodesModal/NodeListElement/NodeListElement.jsx
@@ -18,7 +18,8 @@ const NodeListElement = ({ alias, pubKey, onNodeSelected }) => (
onClick={(e) => {
e.preventDefault();
onNodeSelected(pubKey);
- }}>
+ }}
+ >
diff --git a/app/components/modals/SearchForNodesModal/SearchForNodesModal.jsx b/app/components/modals/SearchForNodesModal/SearchForNodesModal.jsx
index 6ac98fb9a6..cdb152fe69 100644
--- a/app/components/modals/SearchForNodesModal/SearchForNodesModal.jsx
+++ b/app/components/modals/SearchForNodesModal/SearchForNodesModal.jsx
@@ -52,7 +52,8 @@ const SearchForNodesModal = ({
inputClassNames={styles.searchInput}
onChange={(e) => setNode(e.target.value)}
placeholder={intl.formatMessage(messages.searchInputPlaceholder)}
- label={intl.formatMessage(messages.searchInputLabel)}>
+ label={intl.formatMessage(messages.searchInputLabel)}
+ >
{!node ? (
{
e.preventDefault();
setNode(wallet.readFromClipboard());
- }}>
+ }}
+ >
) : (
@@ -72,7 +74,8 @@ const SearchForNodesModal = ({
onClick={(e) => {
e.preventDefault();
setNode("");
- }}>
+ }}
+ >
)}
diff --git a/app/components/modals/SeedCopyConfirmModal/SeedCopyConfirmModalContent.jsx b/app/components/modals/SeedCopyConfirmModal/SeedCopyConfirmModalContent.jsx
index d636d4ebdf..9cb3579b37 100644
--- a/app/components/modals/SeedCopyConfirmModal/SeedCopyConfirmModalContent.jsx
+++ b/app/components/modals/SeedCopyConfirmModal/SeedCopyConfirmModalContent.jsx
@@ -53,13 +53,15 @@ const SeedCopyConfirmModalContent = ({
disabled={
typedConfirmationPhrase.toLowerCase() !==
copyConfirmationPhrase.toLowerCase()
- }>
+ }
+ >
+ ariaLabel="Cancel seed copy"
+ >
diff --git a/app/components/modals/SendFromUnmixedAccountModal/SendFromUnmixedAccountContent.jsx b/app/components/modals/SendFromUnmixedAccountModal/SendFromUnmixedAccountContent.jsx
index 20660aec8f..4dc3bba29c 100644
--- a/app/components/modals/SendFromUnmixedAccountModal/SendFromUnmixedAccountContent.jsx
+++ b/app/components/modals/SendFromUnmixedAccountModal/SendFromUnmixedAccountContent.jsx
@@ -53,7 +53,8 @@ const SendFromUnmixedAccountContent = ({
disabled={
typedConfirmationPhrase.toLowerCase() !==
copyConfirmationPhrase.toLowerCase()
- }>
+ }
+ >
(
+ {...{ show, onCancelModal }}
+ >
diff --git a/app/components/modals/TrezorModals/TrezorPinModal.jsx b/app/components/modals/TrezorModals/TrezorPinModal.jsx
index 7569c1b5e3..40c68700cc 100644
--- a/app/components/modals/TrezorModals/TrezorPinModal.jsx
+++ b/app/components/modals/TrezorModals/TrezorPinModal.jsx
@@ -30,7 +30,8 @@ const TrezorPinModal = ({
return (
+ onCancelModal={onCancelPinModal}
+ >
@@ -44,7 +45,8 @@ const TrezorPinModal = ({
link: (
+ href="https://wiki.trezor.io/User_manual:Entering_PIN"
+ >
)
@@ -58,12 +60,14 @@ const TrezorPinModal = ({
id="passwordFieldInput"
inputClassNames={styles.passwordFieldInput}
value={currentPin}
- disabled={true}>
+ disabled={true}
+ >
+ onClick={onClearPin}
+ >
@@ -74,7 +78,8 @@ const TrezorPinModal = ({
setCurrentPin(currentPin + index)}>
+ onClick={() => setCurrentPin(currentPin + index)}
+ >
•
))}
diff --git a/app/components/modals/TrezorModals/TrezorWalletCreationPassphraseModal.jsx b/app/components/modals/TrezorModals/TrezorWalletCreationPassphraseModal.jsx
index e3661965b5..dfd30fe944 100644
--- a/app/components/modals/TrezorModals/TrezorWalletCreationPassphraseModal.jsx
+++ b/app/components/modals/TrezorModals/TrezorWalletCreationPassphraseModal.jsx
@@ -63,7 +63,8 @@ const TrezorWalletCreationPassphraseModal = ({
styles.passphraseModal,
isGetStarted && styles.getStarted
)}
- onCancelModal={onCancelModal}>
+ onCancelModal={onCancelModal}
+ >
- }>
+ }
+ >
- }>
+ }
+ >
+ onCancelModal={onCancelWordModal}
+ >
diff --git a/app/components/shared/Balance/Balance.jsx b/app/components/shared/Balance/Balance.jsx
index 000bfd4303..427f7acc5c 100644
--- a/app/components/shared/Balance/Balance.jsx
+++ b/app/components/shared/Balance/Balance.jsx
@@ -47,7 +47,8 @@ export const Balance = ({
styles[secondary],
classNameSecondary,
bold && "bold"
- )}>
+ )}
+ >
{`${tail} `}
)}
diff --git a/app/components/shared/ButtonsToolbar.jsx b/app/components/shared/ButtonsToolbar.jsx
index 25068b44db..4b840964b4 100644
--- a/app/components/shared/ButtonsToolbar.jsx
+++ b/app/components/shared/ButtonsToolbar.jsx
@@ -19,7 +19,8 @@ const ButtonsToolbar = ({
// if isValid is not passed as props, we never validate it.
(isValid === undefined ? false : !isValid) || loading
}
- onClick={onSubmit}>
+ onClick={onSubmit}
+ >
{submitLabel ? (
submitLabel
) : (
diff --git a/app/components/shared/DetailsTable/DetailsTable.jsx b/app/components/shared/DetailsTable/DetailsTable.jsx
index c15bcf3995..4aa4036d30 100644
--- a/app/components/shared/DetailsTable/DetailsTable.jsx
+++ b/app/components/shared/DetailsTable/DetailsTable.jsx
@@ -23,7 +23,8 @@ const ValueField = ({ data }) => {
styles.value,
copyable && styles.copyable,
href && styles.href
- )}>
+ )}
+ >
{copyable ? (
<>
{text}
@@ -89,7 +90,8 @@ const DetailsTable = ({
headerClassName,
showDetails && styles.active,
expandable && styles.expandable
- )}>
+ )}
+ >
{title}
{expandable && }
diff --git a/app/components/shared/Documentation/Documentation.jsx b/app/components/shared/Documentation/Documentation.jsx
index a09469e259..a011aafdd7 100644
--- a/app/components/shared/Documentation/Documentation.jsx
+++ b/app/components/shared/Documentation/Documentation.jsx
@@ -19,7 +19,8 @@ const renderDocLink = ({ href, children }) => {
const DocUnavailableMsg = ({ name, unavailableAlertClassName }) => (
+ className={classNames(styles.unavailableAlert, unavailableAlertClassName)}
+ >
{
+ href="#"
+ >
{children}
);
diff --git a/app/components/shared/LoadingError.jsx b/app/components/shared/LoadingError.jsx
index c6a448cf65..f0eb6a9d14 100644
--- a/app/components/shared/LoadingError.jsx
+++ b/app/components/shared/LoadingError.jsx
@@ -39,7 +39,8 @@ const LoadingError = ({
reload()}
disabled={false}
- loading={false}>
+ loading={false}
+ >
diff --git a/app/components/shared/Log/Log.jsx b/app/components/shared/Log/Log.jsx
index 2afb5ee7e5..f3fa046644 100644
--- a/app/components/shared/Log/Log.jsx
+++ b/app/components/shared/Log/Log.jsx
@@ -6,7 +6,8 @@ const Logs = ({ expanded, onShowLog, onHideLog, log, title }) =>
+ onClick={onShowLog}
+ >
{title}
@@ -14,7 +15,8 @@ const Logs = ({ expanded, onShowLog, onHideLog, log, title }) =>
+ onClick={onHideLog}
+ >
{title}
diff --git a/app/components/shared/PoliteiaLink.jsx b/app/components/shared/PoliteiaLink.jsx
index 7527b6ec50..818c6ebd97 100644
--- a/app/components/shared/PoliteiaLink.jsx
+++ b/app/components/shared/PoliteiaLink.jsx
@@ -29,7 +29,8 @@ const PoliteiaLink = ({
CustomComponent
? (props) => {children}
: null
- }>
+ }
+ >
{children}
);
diff --git a/app/components/shared/SendTransaction/Form.jsx b/app/components/shared/SendTransaction/Form.jsx
index 00e7b4332a..865369b43f 100644
--- a/app/components/shared/SendTransaction/Form.jsx
+++ b/app/components/shared/SendTransaction/Form.jsx
@@ -50,7 +50,8 @@ const Form = ({
+ data-testid="detailsValueColumn"
+ >
- }>
+ }
+ >
+ account={account}
+ >
{!isSendSelf ? (
<>
@@ -113,7 +116,8 @@ const Form = ({
{outputs.map((output, index) => (
+ key={"confirm-" + index}
+ >
{output.data.destination}
))}
diff --git a/app/components/shared/TabsHeader/TabsHeader.jsx b/app/components/shared/TabsHeader/TabsHeader.jsx
index ca6aceefd3..872602eda6 100644
--- a/app/components/shared/TabsHeader/TabsHeader.jsx
+++ b/app/components/shared/TabsHeader/TabsHeader.jsx
@@ -16,7 +16,8 @@ const TabsHeader = ({
activeTabIndex={activeTabIndex}
onSelectTab={setActiveTabIndex}
contentClassName={classNames(styles.tabsContent, contentClassName)}
- className={classNames(styles.tabs, className)}>
+ className={classNames(styles.tabs, className)}
+ >
{tabs.map((tab, index) => (
+ )}
+ >
{tab.component}
))}
diff --git a/app/components/shared/TxHistory/LiveStakeTxRow.jsx b/app/components/shared/TxHistory/LiveStakeTxRow.jsx
index a0cee402ab..8eda0c01d9 100644
--- a/app/components/shared/TxHistory/LiveStakeTxRow.jsx
+++ b/app/components/shared/TxHistory/LiveStakeTxRow.jsx
@@ -60,7 +60,8 @@ const StakeTxRow = ({
return (
+ className={classNames(styles.myTickets, overview && styles.overview)}
+ >
@@ -93,7 +94,8 @@ const StakeTxRow = ({
}>
+ content={
}
+ >
{feeStatusString}
diff --git a/app/components/shared/TxHistory/Row.jsx b/app/components/shared/TxHistory/Row.jsx
index 3de8f3f417..631e093838 100644
--- a/app/components/shared/TxHistory/Row.jsx
+++ b/app/components/shared/TxHistory/Row.jsx
@@ -18,7 +18,8 @@ const Row = ({
!overview && classNames("flex-row", styles.historyRow),
eligible && styles.eligibleRow,
active && styles.activeRow
- )}>
+ )}
+ >
{children}
{pending && (
diff --git a/app/components/shared/TxHistory/StakeTxRow.jsx b/app/components/shared/TxHistory/StakeTxRow.jsx
index a152ae6d63..9e69fdf917 100644
--- a/app/components/shared/TxHistory/StakeTxRow.jsx
+++ b/app/components/shared/TxHistory/StakeTxRow.jsx
@@ -72,7 +72,8 @@ const StakeTxRow = ({
return (
+ className={classNames(styles.myTickets, overview && styles.overview)}
+ >
diff --git a/app/components/shared/VericalAccordion/VerticalAccordion.jsx b/app/components/shared/VericalAccordion/VerticalAccordion.jsx
index 8fd4c076cb..abd37cdfb4 100644
--- a/app/components/shared/VericalAccordion/VerticalAccordion.jsx
+++ b/app/components/shared/VericalAccordion/VerticalAccordion.jsx
@@ -16,14 +16,12 @@ const VerticalAccordion = ({
}) => {
return (
+ className={classNames(styles.container, show && styles.active, className)}
+ >
onToggleAccordion?.() : null}>
+ onClick={!disabled ? () => onToggleAccordion?.() : null}
+ >
{header}
{
dispatchSingleMessage(messages.watchOnlyWarn) : null
- }>
+ }
+ >
{children}
);
diff --git a/app/components/views/AccountsPage/Accounts/AccountRow/AccountDetails/AccountDetails.jsx b/app/components/views/AccountsPage/Accounts/AccountRow/AccountDetails/AccountDetails.jsx
index 1cf2a00f83..7db1385d05 100644
--- a/app/components/views/AccountsPage/Accounts/AccountRow/AccountDetails/AccountDetails.jsx
+++ b/app/components/views/AccountsPage/Accounts/AccountRow/AccountDetails/AccountDetails.jsx
@@ -119,7 +119,8 @@ const AccountsDetails = ({
{account.accountName !== IMPORTED_ACCOUNT &&
account.accountName !== dexAccount && (
}>
+ content={
}
+ >
)
- }>
+ }
+ >
+ className={styles.details}
+ >
{isShowingDetails ? (
isShowingRenameAccount ? (
getRenameAccountStyles()
diff --git a/app/components/views/AccountsPage/Accounts/AccountRow/Header/Header.jsx b/app/components/views/AccountsPage/Accounts/AccountRow/Header/Header.jsx
index cea25ff01b..2bc5a02fe1 100644
--- a/app/components/views/AccountsPage/Accounts/AccountRow/Header/Header.jsx
+++ b/app/components/views/AccountsPage/Accounts/AccountRow/Header/Header.jsx
@@ -19,7 +19,8 @@ const Header = React.memo(
isImported(account) && !hasTickets && styles.disabled,
isMixed && styles.mixed,
isChange && styles.unmixed
- )}>
+ )}
+ >
{account.accountName === DEFAULT_ACCOUNT ? (
diff --git a/app/components/views/AccountsPage/Accounts/AccountRow/RenameAccount/RenameAccount.jsx b/app/components/views/AccountsPage/Accounts/AccountRow/RenameAccount/RenameAccount.jsx
index 4d3ba13f82..0da38e3e97 100644
--- a/app/components/views/AccountsPage/Accounts/AccountRow/RenameAccount/RenameAccount.jsx
+++ b/app/components/views/AccountsPage/Accounts/AccountRow/RenameAccount/RenameAccount.jsx
@@ -47,12 +47,14 @@ const RenameAccount = ({
+ onClick={hideRenameAccount}
+ >
+ onClick={renameAccount}
+ >
diff --git a/app/components/views/AccountsPage/AccountsPage.jsx b/app/components/views/AccountsPage/AccountsPage.jsx
index 22465d943b..a6da0f331a 100644
--- a/app/components/views/AccountsPage/AccountsPage.jsx
+++ b/app/components/views/AccountsPage/AccountsPage.jsx
@@ -48,7 +48,8 @@ const AccountsPage = () => {
- }>
+ }
+ >
);
diff --git a/app/components/views/AgendaDetailsPage/AgendaDetails.jsx b/app/components/views/AgendaDetailsPage/AgendaDetails.jsx
index 48680e5a59..17dbcf47e3 100644
--- a/app/components/views/AgendaDetailsPage/AgendaDetails.jsx
+++ b/app/components/views/AgendaDetailsPage/AgendaDetails.jsx
@@ -20,7 +20,8 @@ const AgendaDetails = () => {
+ onClick={goBackHistory}
+ >
diff --git a/app/components/views/AgendaDetailsPage/helpers/AgendaCard/AgendaCard.jsx b/app/components/views/AgendaDetailsPage/helpers/AgendaCard/AgendaCard.jsx
index aefc328055..208576387c 100644
--- a/app/components/views/AgendaDetailsPage/helpers/AgendaCard/AgendaCard.jsx
+++ b/app/components/views/AgendaDetailsPage/helpers/AgendaCard/AgendaCard.jsx
@@ -31,7 +31,8 @@ const AgendaCard = ({ agenda, selectedChoice, className }) => {
m="This agenda has finished voting and {passed}."
values={{ passed: agenda.passed ? "PASSED" : "NOT PASSED" }}
/>
- }>
+ }
+ >
{
id="agenda.card.inProgressTooltip"
m="Voting is still in progress."
/>
- }>
+ }
+ >
{
+ className={classNames(styles.isRow, styles.seedInstructions)}
+ >
- }>
+ }
+ >
{dexSeed}
diff --git a/app/components/views/DexPage/CreateDexAcctPage/CreateDexAcctPage.jsx b/app/components/views/DexPage/CreateDexAcctPage/CreateDexAcctPage.jsx
index 671d445b6e..072f66f2f7 100644
--- a/app/components/views/DexPage/CreateDexAcctPage/CreateDexAcctPage.jsx
+++ b/app/components/views/DexPage/CreateDexAcctPage/CreateDexAcctPage.jsx
@@ -48,7 +48,8 @@ const CreateDexAcctPage = () => {
onSelectDexAccount(account.name)}>
+ onClick={() => onSelectDexAccount(account.name)}
+ >
+ onClick={backToCredentials}
+ >
+ disabled={!appDataValid}
+ >
)}
diff --git a/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/ConfirmSeedForm.jsx b/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/ConfirmSeedForm.jsx
index d4d50be0a6..7f5291d7c2 100644
--- a/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/ConfirmSeedForm.jsx
+++ b/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/ConfirmSeedForm.jsx
@@ -23,7 +23,8 @@ export const ConfirmSeedForm = ({
className={classNames(
styles.container,
posBtBarToBottom && styles.posBtBarToBottom
- )}>
+ )}
+ >
diff --git a/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/SeedWordRow/SeedWordRow.jsx b/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/SeedWordRow/SeedWordRow.jsx
index b118b10c8a..7ea640e62f 100644
--- a/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/SeedWordRow/SeedWordRow.jsx
+++ b/app/components/views/GetStartedPage/CreateWalletPage/ConfirmSeed/ConfirmSeedForm/SeedWordRow/SeedWordRow.jsx
@@ -31,7 +31,8 @@ const SeedWordRow = ({
isSelectedWordInvalid && showError && styles.invalid
)}
key={`${index}-${wordToShowIndex}`}
- onClick={() => onSeedButtonClick(index, wordToShowIndex)}>
+ onClick={() => onSeedButtonClick(index, wordToShowIndex)}
+ >
{wordToShow}
);
diff --git a/app/components/views/GetStartedPage/CreateWalletPage/ExistingSeed/Form/Form.jsx b/app/components/views/GetStartedPage/CreateWalletPage/ExistingSeed/Form/Form.jsx
index 2368fb3f38..93b1611803 100644
--- a/app/components/views/GetStartedPage/CreateWalletPage/ExistingSeed/Form/Form.jsx
+++ b/app/components/views/GetStartedPage/CreateWalletPage/ExistingSeed/Form/Form.jsx
@@ -38,7 +38,8 @@ const ExistingSeedForm = ({
}) => (
}>
+ title={}
+ >
{/* XXX: Use pi-iu's toggle */}
+ onClick={onClick}
+ >
{message}
+ onClick={onBackClick}
+ >
{backMessage || }
diff --git a/app/components/views/GetStartedPage/CreateWalletPage/helpers/SeedWord/SeedWord.jsx b/app/components/views/GetStartedPage/CreateWalletPage/helpers/SeedWord/SeedWord.jsx
index e7f9fce176..830af96689 100644
--- a/app/components/views/GetStartedPage/CreateWalletPage/helpers/SeedWord/SeedWord.jsx
+++ b/app/components/views/GetStartedPage/CreateWalletPage/helpers/SeedWord/SeedWord.jsx
@@ -22,7 +22,8 @@ const SeedWord = ({
word && error && styles.error,
!isConfirm && word && !error && !show && styles.populated,
!isConfirm && !word && !error && !show && styles.restore
- )}>
+ )}
+ >
{index + 1}.
{show ? (
diff --git a/app/components/views/GetStartedPage/GetStartedPage.jsx b/app/components/views/GetStartedPage/GetStartedPage.jsx
index 1d290d54cb..98a0a9443f 100644
--- a/app/components/views/GetStartedPage/GetStartedPage.jsx
+++ b/app/components/views/GetStartedPage/GetStartedPage.jsx
@@ -33,7 +33,8 @@ const GetStarted = ({
+ isTestNet={isTestNet}
+ >
{updateAvailable && (
@@ -50,7 +51,8 @@ const GetStarted = ({
className={classNames(
styles.invisibleButton,
styles.tutorialButton
- )}>
+ )}
+ >
+ )}
+ >
+ className={styles.invisibleButton}
+ >
+ className={styles.invisibleButton}
+ >
>
diff --git a/app/components/views/GetStartedPage/PreCreateWallet/CreateTrezorWalletForm/CreateTrezorWalletForm.jsx b/app/components/views/GetStartedPage/PreCreateWallet/CreateTrezorWalletForm/CreateTrezorWalletForm.jsx
index f31d8607ab..2b9f7944ab 100644
--- a/app/components/views/GetStartedPage/PreCreateWallet/CreateTrezorWalletForm/CreateTrezorWalletForm.jsx
+++ b/app/components/views/GetStartedPage/PreCreateWallet/CreateTrezorWalletForm/CreateTrezorWalletForm.jsx
@@ -81,12 +81,14 @@ const CreateTrezorWalletForm = ({
+ className={styles.cancelBt}
+ >
+ classNames={styles.createWalletBt}
+ >
diff --git a/app/components/views/GetStartedPage/PreCreateWallet/CreateWalletForm/CreateWalletForm.jsx b/app/components/views/GetStartedPage/PreCreateWallet/CreateWalletForm/CreateWalletForm.jsx
index ca38c40138..97fcbdb2a1 100644
--- a/app/components/views/GetStartedPage/PreCreateWallet/CreateWalletForm/CreateWalletForm.jsx
+++ b/app/components/views/GetStartedPage/PreCreateWallet/CreateWalletForm/CreateWalletForm.jsx
@@ -61,7 +61,8 @@ const CreateWalletForm = ({
+ className={classNames(styles.advancedOption, styles.gapLimit)}
+ >
diff --git a/app/components/views/GetStartedPage/SetupWallet/SetMixedAcctPage/SetMixedAcctPage.jsx b/app/components/views/GetStartedPage/SetupWallet/SetMixedAcctPage/SetMixedAcctPage.jsx
index b44dd91f6c..24502dc9e4 100644
--- a/app/components/views/GetStartedPage/SetupWallet/SetMixedAcctPage/SetMixedAcctPage.jsx
+++ b/app/components/views/GetStartedPage/SetupWallet/SetMixedAcctPage/SetMixedAcctPage.jsx
@@ -99,7 +99,8 @@ export default ({ onSendContinue }) => {
{coinjoinSumByAcct.map(({ acctIdx, coinjoinSum }) => (
+ className={classNames("flex-row", styles.card)}
+ >
diff --git a/app/components/views/GetStartedPage/SetupWallet/hooks.js b/app/components/views/GetStartedPage/SetupWallet/hooks.js
index d6195921e7..e374966b53 100644
--- a/app/components/views/GetStartedPage/SetupWallet/hooks.js
+++ b/app/components/views/GetStartedPage/SetupWallet/hooks.js
@@ -175,7 +175,8 @@ export const useWalletSetup = (settingUpWalletRef) => {
+ }
+ >
)
diff --git a/app/components/views/GetStartedPage/TutorialPage/Page.jsx b/app/components/views/GetStartedPage/TutorialPage/Page.jsx
index 9b6498954c..c375ba3923 100644
--- a/app/components/views/GetStartedPage/TutorialPage/Page.jsx
+++ b/app/components/views/GetStartedPage/TutorialPage/Page.jsx
@@ -40,7 +40,8 @@ const TutorialPage = ({
+ onClick={finishTutorial}
+ >
{tutorialStep < 3 ? (
) : (
@@ -56,7 +57,8 @@ const TutorialPage = ({
+ onClick={tutorialStep < 3 ? onNextTutorialStep : finishTutorial}
+ >
diff --git a/app/components/views/GetStartedPage/WalletSelection/Form/Form.jsx b/app/components/views/GetStartedPage/WalletSelection/Form/Form.jsx
index b8610894f6..f1cc3cb6d6 100644
--- a/app/components/views/GetStartedPage/WalletSelection/Form/Form.jsx
+++ b/app/components/views/GetStartedPage/WalletSelection/Form/Form.jsx
@@ -117,7 +117,8 @@ const WalletSelectionForm = ({
!editWallets
? () => submitChosenWallet({ selectedWallet: wallet })
: null
- }>
+ }
+ >
+ )}
+ >
{editWallets ? (
- }>
+ }
+ >
- }>
+ }
+ >
@@ -194,7 +198,8 @@ const WalletSelectionForm = ({
- }>
+ }
+ >
@@ -204,7 +209,8 @@ const WalletSelectionForm = ({
- }>
+ }
+ >
- }>
+ }
+ >
diff --git a/app/components/views/GetStartedPage/messages/messages.jsx b/app/components/views/GetStartedPage/messages/messages.jsx
index df9a250106..9ef186bf68 100644
--- a/app/components/views/GetStartedPage/messages/messages.jsx
+++ b/app/components/views/GetStartedPage/messages/messages.jsx
@@ -144,7 +144,8 @@ export const UpdateAvailableLink = ({
m="New version {version} available"
values={{ version: updateAvailable }}
/>
- }>
+ }
+ >
diff --git a/app/components/views/GovernancePage/Blockchain/AgendaOverview/AgendaOverview.jsx b/app/components/views/GovernancePage/Blockchain/AgendaOverview/AgendaOverview.jsx
index a6afbe5e30..5bb3a6fa5e 100644
--- a/app/components/views/GovernancePage/Blockchain/AgendaOverview/AgendaOverview.jsx
+++ b/app/components/views/GovernancePage/Blockchain/AgendaOverview/AgendaOverview.jsx
@@ -9,7 +9,8 @@ const AgendaOverview = ({
}) => (
viewAgendaDetailsHandler(agenda.name)}
- className={classNames(styles.cardWrapper)}>
+ className={classNames(styles.cardWrapper)}
+ >
diff --git a/app/components/views/GovernancePage/Blockchain/Blockchain.jsx b/app/components/views/GovernancePage/Blockchain/Blockchain.jsx
index 5049f38639..919ab40eca 100644
--- a/app/components/views/GovernancePage/Blockchain/Blockchain.jsx
+++ b/app/components/views/GovernancePage/Blockchain/Blockchain.jsx
@@ -76,7 +76,8 @@ const Blockchain = () => {
link: (
+ href="https://docs.decred.org/getting-started/user-guides/agenda-voting/"
+ >
docs.decred.org
)
@@ -88,7 +89,8 @@ const Blockchain = () => {
+ hrefTestNet="https://voting.decred.org/testnet"
+ >
{
outdatedUsedVsps?.length === 1 ? (
+ href={outdatedUsedVsps[0].host}
+ >
{outdatedUsedVsps[0].host}
) : (
@@ -128,7 +131,8 @@ const Blockchain = () => {
+ href={vsp.host}
+ >
{vsp.host}
@@ -154,7 +158,8 @@ const Blockchain = () => {
}>
+ content={}
+ >
(
+ onClick={getTokenAndInitialBatch}
+ >
diff --git a/app/components/views/GovernancePage/Proposals/ProposalsList/ProposalsList.jsx b/app/components/views/GovernancePage/Proposals/ProposalsList/ProposalsList.jsx
index 5cdd86c568..99f1906399 100644
--- a/app/components/views/GovernancePage/Proposals/ProposalsList/ProposalsList.jsx
+++ b/app/components/views/GovernancePage/Proposals/ProposalsList/ProposalsList.jsx
@@ -85,7 +85,8 @@ const ProposalsList = ({ finishedVote, tab, isDarkTheme }) => {
loadMore={loadMore}
initialLoad={false}
useWindow={false}
- threshold={300}>
+ threshold={300}
+ >
{proposals[selectedFilter].map((v) => (
+ )}
+ >
{
m="Refresh Proposals"
/>
}
- placement="right">
+ placement="right"
+ >
{
className={styles.politeiaButton}
CustomComponent={Button}
path="/record/new"
- isTestnet={isTestnet}>
+ isTestnet={isTestnet}
+ >
diff --git a/app/components/views/GovernancePage/TreasurySpendingTab/TreasurySpendingTab.jsx b/app/components/views/GovernancePage/TreasurySpendingTab/TreasurySpendingTab.jsx
index 9c6954e8dd..ed2321c07f 100644
--- a/app/components/views/GovernancePage/TreasurySpendingTab/TreasurySpendingTab.jsx
+++ b/app/components/views/GovernancePage/TreasurySpendingTab/TreasurySpendingTab.jsx
@@ -32,7 +32,8 @@ const TreasurySpendingTab = () => {
link: (
+ href={dcrdSourceLink}
+ >
dcrd source code
)
diff --git a/app/components/views/HomePage/HomePage.jsx b/app/components/views/HomePage/HomePage.jsx
index cc105af874..04b681f510 100644
--- a/app/components/views/HomePage/HomePage.jsx
+++ b/app/components/views/HomePage/HomePage.jsx
@@ -75,7 +75,8 @@ export default () => {
}}
/>
+ className={classNames(styles.overviewTransactionsTicket, styles.isRow)}
+ >
+ className={styles.ticketLifeCycle}
+ >
+ className={styles.buy}
+ >
{
amount={unconfirmedTotalBalance}
/>
- }>
+ }
+ >
{
className={classNames(
sharedStyles.overviewSpendableLockedWrapperArea,
sharedStyles.tickets
- )}>
+ )}
+ >
+ )}
+ >
{
className={classNames(
sharedStyles.overviewBalanceSpendableLocked,
sharedStyles.voted
- )}>
+ )}
+ >
{
}
- className={styles.backupSubtitle}>
+ className={styles.backupSubtitle}
+ >
diff --git a/app/components/views/LNPage/AdvancedTab/Network/QueryRoutes/QueryRoutes.jsx b/app/components/views/LNPage/AdvancedTab/Network/QueryRoutes/QueryRoutes.jsx
index 3878fbc8fe..63732da38e 100644
--- a/app/components/views/LNPage/AdvancedTab/Network/QueryRoutes/QueryRoutes.jsx
+++ b/app/components/views/LNPage/AdvancedTab/Network/QueryRoutes/QueryRoutes.jsx
@@ -46,7 +46,8 @@ const QueryRoutes = ({
+ onClick={requestRoutes}
+ >
);
};
diff --git a/app/components/views/LNPage/AdvancedTab/Network/Tabs/Tabs.jsx b/app/components/views/LNPage/AdvancedTab/Network/Tabs/Tabs.jsx
index d5137d7c8d..cb722a26a8 100644
--- a/app/components/views/LNPage/AdvancedTab/Network/Tabs/Tabs.jsx
+++ b/app/components/views/LNPage/AdvancedTab/Network/Tabs/Tabs.jsx
@@ -15,7 +15,8 @@ const Tabs = ({ active, set }) => {
? styles.tabBackgroundSelected
: styles.tabBackgroundUnselected
)}
- onClick={() => set(QUERY_NODE)}>
+ onClick={() => set(QUERY_NODE)}
+ >
{
? styles.tabBackgroundSelected
: styles.tabBackgroundUnselected
)}
- onClick={() => set(QUERY_ROUTE)}>
+ onClick={() => set(QUERY_ROUTE)}
+ >
diff --git a/app/components/views/LNPage/AdvancedTab/Watchtowers/AddWatchtower/AddWatchtower.jsx b/app/components/views/LNPage/AdvancedTab/Watchtowers/AddWatchtower/AddWatchtower.jsx
index 5754f0cb2c..332b40b68e 100644
--- a/app/components/views/LNPage/AdvancedTab/Watchtowers/AddWatchtower/AddWatchtower.jsx
+++ b/app/components/views/LNPage/AdvancedTab/Watchtowers/AddWatchtower/AddWatchtower.jsx
@@ -14,7 +14,8 @@ const AddWatchtower = ({ addWatchtower, listWatchtowers }) => {
{
{
className={styles.addWatchtowerButton}
onClick={() =>
addWatchtower(pubkey, addr).then(() => listWatchtowers())
- }>
+ }
+ >
diff --git a/app/components/views/LNPage/AdvancedTab/Watchtowers/Watchtowers.jsx b/app/components/views/LNPage/AdvancedTab/Watchtowers/Watchtowers.jsx
index bdd3e3f2d4..432209598d 100644
--- a/app/components/views/LNPage/AdvancedTab/Watchtowers/Watchtowers.jsx
+++ b/app/components/views/LNPage/AdvancedTab/Watchtowers/Watchtowers.jsx
@@ -34,19 +34,22 @@ const Watchtowers = () => {
? styles.statusTrue
: styles.statusFalse
)}
- key={tower.pubkey}>
+ key={tower.pubkey}
+ >
- }>
+ }
+ >
{
removeWatchtower(tower.pubkeyHex);
listWatchtowers();
}}
- href="#">
+ href="#"
+ >
×
diff --git a/app/components/views/LNPage/ChannelDetailsPage/ChannelDetails.jsx b/app/components/views/LNPage/ChannelDetailsPage/ChannelDetails.jsx
index df9ce6b2e1..627c09b6c6 100644
--- a/app/components/views/LNPage/ChannelDetailsPage/ChannelDetails.jsx
+++ b/app/components/views/LNPage/ChannelDetailsPage/ChannelDetails.jsx
@@ -20,7 +20,8 @@ const ChannelDetails = () => {
+ onClick={goBackHistory}
+ >
diff --git a/app/components/views/LNPage/ChannelsTab/ChannelsTab.jsx b/app/components/views/LNPage/ChannelsTab/ChannelsTab.jsx
index 05b1f9f9a4..c9b45e5d99 100644
--- a/app/components/views/LNPage/ChannelsTab/ChannelsTab.jsx
+++ b/app/components/views/LNPage/ChannelsTab/ChannelsTab.jsx
@@ -95,7 +95,8 @@ const subtitleMenu = ({
}>
+ content={
}
+ >
{
className={classNames(
styles.counterpartyWrapper,
hideSearchBt && styles.hideSearchBt
- )}>
+ )}
+ >
{
showSuccess={nodeShowSuccess}
showErrors={!!nodeErrorMsg}
invalid={!!nodeErrorMsg}
- invalidMessage={nodeErrorMsg}>
+ invalidMessage={nodeErrorMsg}
+ >
{!node ? (
{
onClick={(e) => {
e.preventDefault();
onNodeChanged(wallet.readFromClipboard());
- }}>
+ }}
+ >
Paste
) : (
@@ -193,7 +197,8 @@ const ChannelsTab = () => {
onClick={(e) => {
e.preventDefault();
onNodeChanged("");
- }}>
+ }}
+ >
)}
@@ -238,7 +243,8 @@ const ChannelsTab = () => {
recentNodes.slice(0, isMainNet ? 4 : 6).map((node) => (
onNodeChanged(node.pubKey)}
- key={node.pubKey}>
+ key={node.pubKey}
+ >
{node.alias}
))
@@ -253,7 +259,8 @@ const ChannelsTab = () => {
+ disabled={opening || !canOpen}
+ >
@@ -280,10 +287,12 @@ const ChannelsTab = () => {
: styles.channelGrayBorder
)}
key={c.channelPoint}
- onClick={() => viewChannelDetailsHandler(c.channelPoint)}>
+ onClick={() => viewChannelDetailsHandler(c.channelPoint)}
+ >
+ className={classNames(styles.continueButton, "flex-centralize")}
+ >
diff --git a/app/components/views/LNPage/ConnectPage/ConnectPage.jsx b/app/components/views/LNPage/ConnectPage/ConnectPage.jsx
index 4a06cbe091..54fbe86ce8 100644
--- a/app/components/views/LNPage/ConnectPage/ConnectPage.jsx
+++ b/app/components/views/LNPage/ConnectPage/ConnectPage.jsx
@@ -80,7 +80,8 @@ const ConnectPage = () => {
) : (
)
- }>
+ }
+ >
{displayCreationWarning ? (
) : (
@@ -111,7 +112,8 @@ const ConnectPage = () => {
id="ln.connectPage.disabled.unlockWalletModal"
m="Privacy Mixer, Autobuyer or Purchase Ticket Attempt running, please shut them off before unlock LN Wallet."
/>
- }>
+ }
+ >
{
}>
+ title={
}
+ >
+ disabled={!isAcceptCreationWarningButtonEnabled}
+ >
}>
+ content={}
+ >
}>
+ content={}
+ >
{
+ disabled={addInvoiceAttempt || !isFormValid}
+ >
diff --git a/app/components/views/LNPage/SendTab/DecodedPayRequest/DecodedPayRequest.jsx b/app/components/views/LNPage/SendTab/DecodedPayRequest/DecodedPayRequest.jsx
index 3db4a1af8b..69bbaaa863 100644
--- a/app/components/views/LNPage/SendTab/DecodedPayRequest/DecodedPayRequest.jsx
+++ b/app/components/views/LNPage/SendTab/DecodedPayRequest/DecodedPayRequest.jsx
@@ -78,7 +78,8 @@ const DecodedPayRequest = ({
+ className={classNames(styles.propContainer, styles.descriptionContainer)}
+ >
@@ -89,7 +90,8 @@ const DecodedPayRequest = ({
)}
+ className={classNames(styles.propContainer, styles.paymentHashContainer)}
+ >
diff --git a/app/components/views/LNPage/SendTab/SendTab.jsx b/app/components/views/LNPage/SendTab/SendTab.jsx
index 1b61a8d967..4ed85d6a76 100644
--- a/app/components/views/LNPage/SendTab/SendTab.jsx
+++ b/app/components/views/LNPage/SendTab/SendTab.jsx
@@ -76,7 +76,8 @@ const subtitleMenu = ({
}>
+ content={}
+ >
}>
+ content={}
+ >
{
: expired
? intl.formatMessage(messages.expiredErrorMsg)
: null
- }>
+ }
+ >
{!payRequest ? (
{
onClick={(e) => {
e.preventDefault();
onPayRequestChanged(wallet.readFromClipboard());
- }}>
+ }}
+ >
Paste
) : (
@@ -173,7 +177,8 @@ const SendTab = ({ setTimeout }) => {
onClick={(e) => {
e.preventDefault();
onPayRequestChanged("");
- }}>
+ }}
+ >
)}
diff --git a/app/components/views/PrivacyPage/PrivacyTab/PrivacyContent.jsx b/app/components/views/PrivacyPage/PrivacyTab/PrivacyContent.jsx
index 82c39365c9..4ad40d6e3c 100644
--- a/app/components/views/PrivacyPage/PrivacyTab/PrivacyContent.jsx
+++ b/app/components/views/PrivacyPage/PrivacyTab/PrivacyContent.jsx
@@ -57,7 +57,8 @@ const PrivacyContent = ({
styles.mixerStatus,
styles.isRow,
(accountMixerRunning || isAutoBuyerRunning) && styles.running
- )}>
+ )}
+ >
{accountMixerRunning || isAutoBuyerRunning ? (
isAutoBuyerRunning ? (
@@ -74,7 +75,8 @@ const PrivacyContent = ({
styles.balanceContainer,
styles.unmixedAccount,
isMixerDisabled && styles.balanceError
- )}>
+ )}
+ >
{isMixerDisabled && }
diff --git a/app/components/views/PrivacyPage/SecurityTab/ValidateAddress/ValidateAddressForm.jsx b/app/components/views/PrivacyPage/SecurityTab/ValidateAddress/ValidateAddressForm.jsx
index c607eb957c..ee708bb7bb 100644
--- a/app/components/views/PrivacyPage/SecurityTab/ValidateAddress/ValidateAddressForm.jsx
+++ b/app/components/views/PrivacyPage/SecurityTab/ValidateAddress/ValidateAddressForm.jsx
@@ -16,7 +16,8 @@ const InvalidAddress = () => (
className={classNames(
styles.validateAddressFormResponse,
styles.responseInvalid
- )}>
+ )}
+ >
);
@@ -26,7 +27,8 @@ const OwnedAddress = () => (
className={classNames(
styles.validateAddressFormResponse,
styles.responseOwned
- )}>
+ )}
+ >
);
@@ -36,7 +38,8 @@ const NotOwnedAddress = () => (
className={classNames(
styles.validateAddressFormResponse,
styles.responseNotOwned
- )}>
+ )}
+ >
+ )}
+ >
+ onClick={onSubmit}
+ >
Verify Message
>
diff --git a/app/components/views/ProposalDetailsPage/ProposalDetails.jsx b/app/components/views/ProposalDetailsPage/ProposalDetails.jsx
index bf014071e3..24228c221b 100644
--- a/app/components/views/ProposalDetailsPage/ProposalDetails.jsx
+++ b/app/components/views/ProposalDetailsPage/ProposalDetails.jsx
@@ -54,7 +54,8 @@ const ProposalDetails = ({
+ onClick={goBackHistory}
+ >
+ isTestnet={isTestnet}
+ >
@@ -103,7 +106,8 @@ const ProposalCard = ({
) : (
+ path={`/record/${shortRFPToken}`}
+ >
{`${linkedProposal.name} (${shortRFPToken})`}
)
@@ -125,7 +129,8 @@ const ProposalCard = ({
styles.quorumTooltip,
isDarkTheme && styles.darkQuorumTooltip
)}
- content={`${totalVotes} votes cast, quorum requirement is ${quorumMinimumVotes} votes`}>
+ content={`${totalVotes} votes cast, quorum requirement is ${quorumMinimumVotes} votes`}
+ >
{totalVotes}
diff --git a/app/components/views/SettingsPage/ConnectivitySettingsTab/NetworkSettings/NetworkSettings.jsx b/app/components/views/SettingsPage/ConnectivitySettingsTab/NetworkSettings/NetworkSettings.jsx
index fe8e6bcfde..0869c72818 100644
--- a/app/components/views/SettingsPage/ConnectivitySettingsTab/NetworkSettings/NetworkSettings.jsx
+++ b/app/components/views/SettingsPage/ConnectivitySettingsTab/NetworkSettings/NetworkSettings.jsx
@@ -14,7 +14,8 @@ const SettingsInputWrapper = ({ isTooltipEnabled, children }) =>
m="This was set as a command-line option when launching decrediton"
/>
}
- className={styles.tooltip}>
+ className={styles.tooltip}
+ >
{children}
) : (
@@ -95,7 +96,8 @@ const NetworkSettings = ({ tempSettings, onChangeTempSettings }) => (
+ isTooltipEnabled={tempSettings.daemonStartAdvancedFromCli}
+ >
{
onChangeTempSettings({ proxyType, proxyLocation })}>
+ onClick={() => onChangeTempSettings({ proxyType, proxyLocation })}
+ >
)}
diff --git a/app/components/views/SettingsPage/GeneralSettingsTab/MiscSettings/MiscSettings.jsx b/app/components/views/SettingsPage/GeneralSettingsTab/MiscSettings/MiscSettings.jsx
index 9908be1a5e..f8d0ce4e79 100644
--- a/app/components/views/SettingsPage/GeneralSettingsTab/MiscSettings/MiscSettings.jsx
+++ b/app/components/views/SettingsPage/GeneralSettingsTab/MiscSettings/MiscSettings.jsx
@@ -48,7 +48,8 @@ const MiscSettings = ({ tempSettings, currencies, onChangeTempSettings }) => {
className={styles.discoverUsageButton}
onClick={showDiscoverModal}
loading={discoverUsageAttempt || rescanRunning}
- disabled={discoverUsageAttempt || rescanRunning}>
+ disabled={discoverUsageAttempt || rescanRunning}
+ >
{
style={{
position: "absolute",
opacity
- }}>
+ }}
+ >
))}
diff --git a/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/PagedTutorial.jsx b/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/PagedTutorial.jsx
index eeb5b2e64d..3f038f52ba 100644
--- a/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/PagedTutorial.jsx
+++ b/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/PagedTutorial.jsx
@@ -76,13 +76,15 @@ const PagedTutorial = ({
styles.previous,
previousArrowDisabled && styles.disabled
)}
- onClick={onPreviousTab}>
+ onClick={onPreviousTab}
+ >
+ onSelectTab={onSelectTabs}
+ >
{slides.map((slide, i) => (
}
- className={styles.tab}>
+ className={styles.tab}
+ >
+ )}
+ >
{`${parseInt(i) + 1}/${
slides.length
}`}
@@ -145,7 +149,8 @@ const PagedTutorial = ({
styles.next,
nextArrowDisabled && styles.disabled
)}
- onClick={onNextTab}>
+ onClick={onNextTab}
+ >
diff --git a/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/TabLabel/TabLabel.jsx b/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/TabLabel/TabLabel.jsx
index f6849ce5c5..2dec48c55c 100644
--- a/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/TabLabel/TabLabel.jsx
+++ b/app/components/views/SettingsPage/TutorialsTab/helpers/PagedTutorial/TabLabel/TabLabel.jsx
@@ -16,7 +16,8 @@ const TabLabel = ({
activeTabIndex === parseInt(index) && styles.active,
visited && styles.visited,
className
- )}>
+ )}
+ >
{parseInt(index) + 1}/{slides.length}
diff --git a/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialCard/TutorialCard.jsx b/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialCard/TutorialCard.jsx
index 6165763663..bea0560915 100644
--- a/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialCard/TutorialCard.jsx
+++ b/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialCard/TutorialCard.jsx
@@ -14,7 +14,8 @@ const TutorialCard = ({
styles.overview,
!showProgressBar && styles.small,
className
- )}>
+ )}
+ >
{tutorials[name].title}
diff --git a/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialOverview/TutorialOverview.jsx b/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialOverview/TutorialOverview.jsx
index 1b804ffd11..35dcb0bb20 100644
--- a/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialOverview/TutorialOverview.jsx
+++ b/app/components/views/SettingsPage/TutorialsTab/helpers/TutorialOverview/TutorialOverview.jsx
@@ -12,10 +12,8 @@ const TutorialOverview = ({
}) => (
viewTutorialHandler(name)}
- className={classNames(
- styles.cardWrapper,
- !showProgressBar && styles.small
- )}>
+ className={classNames(styles.cardWrapper, !showProgressBar && styles.small)}
+ >
}
- className={styles.backTooltip}>
+ className={styles.backTooltip}
+ >
+ className={classNames(styles.backButton, "flex-centralize")}
+ >
diff --git a/app/components/views/TicketsPage/MyTicketsTab/Page.jsx b/app/components/views/TicketsPage/MyTicketsTab/Page.jsx
index a4c4122d4a..78d4bc64c7 100644
--- a/app/components/views/TicketsPage/MyTicketsTab/Page.jsx
+++ b/app/components/views/TicketsPage/MyTicketsTab/Page.jsx
@@ -44,7 +44,8 @@ const subtitleMenu = ({
/>
}>
+ content={}
+ >
}>
+ content={}
+ >
}>
+ content={}
+ >
+ data-testid="ticketHistoryPageContent"
+ >
)}
diff --git a/app/components/views/TicketsPage/PurchaseTab/PurchaseTicketsForm/PurchaseTicketsForm.jsx b/app/components/views/TicketsPage/PurchaseTab/PurchaseTicketsForm/PurchaseTicketsForm.jsx
index 97086981af..c66b46c34d 100644
--- a/app/components/views/TicketsPage/PurchaseTab/PurchaseTicketsForm/PurchaseTicketsForm.jsx
+++ b/app/components/views/TicketsPage/PurchaseTab/PurchaseTicketsForm/PurchaseTicketsForm.jsx
@@ -36,7 +36,8 @@ const PurchaseTicketsForm = ({
rememberedVspHost,
toggleRememberVspHostCheckBox,
notMixedAccounts,
- getRunningIndicator
+ getRunningIndicator,
+ isPurchasingTicketsTrezor
}) => {
const intl = useIntl();
return (
@@ -116,7 +117,8 @@ const PurchaseTicketsForm = ({
:
+ className={classNames(styles.vspFee, vsp && styles.haveVspFee)}
+ >
{vsp && vspFee ? vspFee : 0} %
{isWatchingOnly ? (
-
+
{purchaseLabel()}
) : isLoading ? (
@@ -164,7 +170,8 @@ const PurchaseTicketsForm = ({
id="tickets.purchase.running"
m="Privacy Mixer or Autobuyer running, please shut them off before purchasing a ticket."
/>
- }>
+ }
+ >
{purchaseLabel()}
) : (
diff --git a/app/components/views/TicketsPage/PurchaseTab/StakeInfo/StakeInfoDisplay.jsx b/app/components/views/TicketsPage/PurchaseTab/StakeInfo/StakeInfoDisplay.jsx
index 3c5192bdd7..ab61847158 100644
--- a/app/components/views/TicketsPage/PurchaseTab/StakeInfo/StakeInfoDisplay.jsx
+++ b/app/components/views/TicketsPage/PurchaseTab/StakeInfo/StakeInfoDisplay.jsx
@@ -91,7 +91,8 @@ const StakeInfoDisplay = ({
lastVotedTicket && (
+ className={styles.foot}
+ >
+ activeArrowClassName={styles.activeAccordionArrow}
+ >
{
const ticketAutoBuyerRunning = useSelector(sel.getTicketAutoBuyerRunning);
const isLoading = useSelector(sel.purchaseTicketsRequestAttempt);
const notMixedAccounts = useSelector(sel.getNotMixedAccounts);
+ const isTrezor = useSelector(sel.isTrezor);
+ const isPurchasingTicketsTrezor = useSelector(sel.isPurchasingTicketsTrezor);
const rememberedVspHost = useSelector(sel.getRememberedVspHost);
const visibleAccounts = useSelector(sel.visibleAccounts);
@@ -54,9 +57,16 @@ export const usePurchaseTab = () => {
[dispatch]
);
const purchaseTicketsAttempt = useCallback(
- (passphrase, account, numTickets, vsp) =>
- dispatch(ca.purchaseTicketsAttempt(passphrase, account, numTickets, vsp)),
- [dispatch]
+ (passphrase, account, numTickets, vsp) => {
+ if (isTrezor) {
+ dispatch(trezorPurchseTicketsAttempt(account, numTickets, vsp));
+ } else {
+ dispatch(
+ ca.purchaseTicketsAttempt(passphrase, account, numTickets, vsp)
+ );
+ }
+ },
+ [dispatch, isTrezor]
);
const setRememberedVspHost = useCallback(
@@ -140,6 +150,7 @@ export const usePurchaseTab = () => {
vsp,
setVSP,
numTicketsToBuy,
- setNumTicketsToBuy
+ setNumTicketsToBuy,
+ isPurchasingTicketsTrezor
};
};
diff --git a/app/components/views/TicketsPage/StakingTabWarning/StakingTabWarning.jsx b/app/components/views/TicketsPage/StakingTabWarning/StakingTabWarning.jsx
index 5bd7a124de..9a0ce3c7c8 100644
--- a/app/components/views/TicketsPage/StakingTabWarning/StakingTabWarning.jsx
+++ b/app/components/views/TicketsPage/StakingTabWarning/StakingTabWarning.jsx
@@ -27,10 +27,12 @@ const StakingTabWarning = ({ onAcceptCreationWarning }) => {
}>
+ title={
}
+ >
+ disabled={!isAcceptCreationWarningButtonEnabled}
+ >
}
- key={"index" + dayIndex}>
+ key={"index" + dayIndex}
+ >
+ }}
+ >
{Month({ date })}
);
@@ -135,7 +137,8 @@ function drawLegend(opts) {
position: "absolute",
top: offsetY - legendFontSize / 2,
left: legendStarts
- }}>
+ }}
+ >
Less
);
@@ -165,7 +168,8 @@ function drawLegend(opts) {
top: offsetY - legendFontSize / 2,
fontSize: legendFontSize,
left: legendStarts + 25 + totalBoxWidth * themeColorNumber
- }}>
+ }}
+ >
More
);
diff --git a/app/components/views/TicketsPage/StatisticsTab/StatisticsTab.jsx b/app/components/views/TicketsPage/StatisticsTab/StatisticsTab.jsx
index d5b5a007f1..bec710772e 100644
--- a/app/components/views/TicketsPage/StatisticsTab/StatisticsTab.jsx
+++ b/app/components/views/TicketsPage/StatisticsTab/StatisticsTab.jsx
@@ -17,7 +17,8 @@ const subtitleMenu = ({ hasStats }) => (
contentClassName={styles.myTicketsStakeTooltip}
content={
- }>
+ }
+ >
(
}>
+ content={}
+ >
(
}>
+ content={}
+ >
{
useTicketsPage();
return showStakingWarning ? (
}>
+ header={}
+ >
) : (
diff --git a/app/components/views/TicketsPage/VSPTicketsStatusTab/Page.jsx b/app/components/views/TicketsPage/VSPTicketsStatusTab/Page.jsx
index 34c6de6c47..bf153c7279 100644
--- a/app/components/views/TicketsPage/VSPTicketsStatusTab/Page.jsx
+++ b/app/components/views/TicketsPage/VSPTicketsStatusTab/Page.jsx
@@ -19,7 +19,8 @@ const subtitleMenu = ({
}>
+ content={
}
+ >
+ data-testid="VSPTicketHistoryPageContent"
+ >
+ to={location.pathname.replace(txHash, ticketTx.txHash)}
+ >
{ticketTx.txHash}
@@ -173,7 +174,8 @@ const TransactionContent = ({
+ to={location.pathname.replace(txHash, spenderTx.txHash)}
+ >
{spenderTx.txHash}
@@ -216,7 +218,8 @@ const TransactionContent = ({
+ contentClassName={styles.agendaDescTooltip}
+ >
{agenda.issueId}
@@ -224,7 +227,8 @@ const TransactionContent = ({
className={classNames(
styles.voteChoice,
styles[agenda.voteChoice]
- )}>
+ )}
+ >
{agenda.voteChoice}
@@ -310,7 +314,8 @@ const TransactionContent = ({
to={location.pathname.replace(
txHash,
VSPTicketStatus.feetxhash
- )}>
+ )}
+ >
{VSPTicketStatus.feetxhash}
@@ -332,7 +337,8 @@ const TransactionContent = ({
className={classNames(
styles.value,
styles.treasurypolicy
- )}>
+ )}
+ >
{Object.keys(VSPTicketStatus.treasurypolicy).map(
(key) => (
<>
@@ -353,7 +359,8 @@ const TransactionContent = ({
className={classNames(
styles.value,
styles.tspendpolicy
- )}>
+ )}
+ >
{Object.keys(VSPTicketStatus.tspendpolicy).map(
(key) => (
<>
@@ -402,7 +409,8 @@ const TransactionContent = ({
+ onClick={publishUnminedTransactions}
+ >
abandonTransaction(txHash)}>
+ onClick={() => abandonTransaction(txHash)}
+ >
@@ -430,7 +439,8 @@ const TransactionContent = ({
txInputs.length > 0
? styles.overviewTitleConsumed
: styles.overviewTitleEmpty
- }>
+ }
+ >
{txInputs.map(({ accountName, amount }, idx) => (
@@ -455,7 +465,8 @@ const TransactionContent = ({
nonWalletInputs.length > 0
? styles.overviewTitleConsumed
: styles.overviewTitleEmpty
- }>
+ }
+ >
{nonWalletInputs.map(({ address, amount }, idx) => (
@@ -491,7 +502,8 @@ const TransactionContent = ({
txOutputs.length > 0
? styles.overviewTitleConsumed
: styles.overviewTitleEmpty
- }>
+ }
+ >
{txOutputs.map(({ accountName, decodedScript, amount }, idx) => (
@@ -522,7 +534,8 @@ const TransactionContent = ({
nonWalletOutputs.length > 0
? styles.overviewTitleConsumed
: styles.overviewTitleEmpty
- }>
+ }
+ >
{nonWalletOutputs.length > MaxNonWalletOutputs ? (
@@ -536,7 +549,8 @@ const TransactionContent = ({
nonWalletOutputs.map(({ address, amount }, idx) => (
+ className={classNames(styles.address, styles.nonWallet)}
+ >
{
return (
+ className={styles.standalonePage}
+ >
);
@@ -39,7 +40,8 @@ const TransactionPage = () => {
return (
+ className={styles.standalonePage}
+ >
{
return (
+ className={styles.standalonePage}
+ >
Transaction not found
);
diff --git a/app/components/views/TransactionsPage/ExportTab/ExportPage/ExportPage.jsx b/app/components/views/TransactionsPage/ExportTab/ExportPage/ExportPage.jsx
index 55c5abb394..629e7180f7 100644
--- a/app/components/views/TransactionsPage/ExportTab/ExportPage/ExportPage.jsx
+++ b/app/components/views/TransactionsPage/ExportTab/ExportPage/ExportPage.jsx
@@ -91,7 +91,8 @@ const ExportPage = ({
+ data-testid="export-description"
+ >
{selectedExport.description}
@@ -99,7 +100,8 @@ const ExportPage = ({
:
+ data-testid="exported-fields"
+ >
{selectedExport.fields
.map(({ name }) => name.charAt(0).toUpperCase() + name.slice(1))
.join(", ")}
@@ -112,7 +114,8 @@ const ExportPage = ({
+ loading={exportingData}
+ >
diff --git a/app/components/views/TransactionsPage/HistoryTab/HistoryPage/HistoryPage.jsx b/app/components/views/TransactionsPage/HistoryTab/HistoryPage/HistoryPage.jsx
index c471e25994..5842c1e3e7 100644
--- a/app/components/views/TransactionsPage/HistoryTab/HistoryPage/HistoryPage.jsx
+++ b/app/components/views/TransactionsPage/HistoryTab/HistoryPage/HistoryPage.jsx
@@ -46,7 +46,8 @@ const subtitleMenu = ({
}>
+ content={}
+ >
}>
+ content={}
+ >
90}
useWindow={false}
- threshold={loadMoreThreshold}>
+ threshold={loadMoreThreshold}
+ >
+ data-testid="historyPageContent"
+ >
{transactions.length > 0 ? (
) : null}
diff --git a/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/QRCodeModal/QRCodeModal.jsx b/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/QRCodeModal/QRCodeModal.jsx
index 44aba3b29a..d3430b9da2 100644
--- a/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/QRCodeModal/QRCodeModal.jsx
+++ b/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/QRCodeModal/QRCodeModal.jsx
@@ -12,7 +12,8 @@ const QRCode = ({ addr, amount }) => {
return (
+ dangerouslySetInnerHTML={{ __html: qr_img }}
+ >
);
};
diff --git a/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/ReceivePage.jsx b/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/ReceivePage.jsx
index accb6d1e43..2b20e06890 100644
--- a/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/ReceivePage.jsx
+++ b/app/components/views/TransactionsPage/ReceiveTab/ReceivePage/ReceivePage.jsx
@@ -75,7 +75,8 @@ const ReceivePage = ({
className={classNames(
styles.inputWrapper,
styles.amountInputWrapper
- )}>
+ )}
+ >
+ className={classNames(styles.receiveContentNestQR)}
+ >
{nextAddress}
+ )}
+ >
{tooltipText ? (
@@ -154,7 +157,8 @@ const ReceivePage = ({
setTooltipText(true);
showTooltip();
onRequestAddress();
- }}>
+ }}
+ >
diff --git a/app/components/views/TransactionsPage/SendTab/SendOutputRow/SendOutputRow.jsx b/app/components/views/TransactionsPage/SendTab/SendOutputRow/SendOutputRow.jsx
index cc010db32f..7dae93d654 100644
--- a/app/components/views/TransactionsPage/SendTab/SendOutputRow/SendOutputRow.jsx
+++ b/app/components/views/TransactionsPage/SendTab/SendOutputRow/SendOutputRow.jsx
@@ -51,7 +51,8 @@ const getSendAllFundsIcon = ({
id="sendtab.sendAllTitle.disabled"
m="Send all funds from selected account - Disabled"
/>
- }>
+ }
+ >
) : !isSendAll ? (
@@ -62,7 +63,8 @@ const getSendAllFundsIcon = ({
id="sendtab.sendAllTitle"
m="Send all funds from selected account"
/>
- }>
+ }
+ >
) : (
@@ -70,7 +72,8 @@ const getSendAllFundsIcon = ({
contentClassName={styles.tooltipSendAllDisabled}
content={
- }>
+ }
+ >
)}
@@ -90,7 +93,8 @@ const getAddInputIcon = ({
return isSendSelf || onlySendSelfAllowed || isSendAll ? (
}>
+ content={
}
+ >
}>
+ content={
}
+ >
}>
+ content={
}
+ >
contentClassName={styles.tooltipSendToSelf}
content={
- }>
+ }
+ >
contentClassName={styles.tooltipSendAllDisabled}
content={
- }>
+ }
+ >
0 && styles.plus
- )}>
+ )}
+ >
{index === 0 && (
<>
@@ -231,7 +240,8 @@ const SendOutputRow = ({
{isSendAll && (
+ className={styles.amountInputLabel}
+ >
)}
@@ -239,7 +249,8 @@ const SendOutputRow = ({
className={classNames(
styles.amountContainer,
isSendAll && styles.sendAllContainer
- )}>
+ )}
+ >
{isSendAll ? (
100 && styles.error
- )}>
+ )}
+ >
+ className={styles.addressInputLabel}
+ >
onValidateAddress({ address: e.target.value, index })
}
- onKeyDown={onKeyDown}>
+ onKeyDown={onKeyDown}
+ >
{!destination ? (
+ }}
+ >
Paste
) : (
@@ -345,7 +360,8 @@ const SendOutputRow = ({
onClick={(e) => {
e.preventDefault();
onValidateAddress({ address: "", index });
- }}>
+ }}
+ >
)}
diff --git a/app/components/views/TrezorPage/TrezorPageAccordion/TrezorPageAccordion.jsx b/app/components/views/TrezorPage/TrezorPageAccordion/TrezorPageAccordion.jsx
index 752b664155..9b8de9d0a6 100644
--- a/app/components/views/TrezorPage/TrezorPageAccordion/TrezorPageAccordion.jsx
+++ b/app/components/views/TrezorPage/TrezorPageAccordion/TrezorPageAccordion.jsx
@@ -18,7 +18,8 @@ const TrezorPageAccordion = ({ children, label }) => {
className={styles.accordion}
childrenClassName={styles.accordionChildren}
arrowClassName={styles.accordionArrow}
- activeArrowClassName={styles.activeAccordionArrow}>
+ activeArrowClassName={styles.activeAccordionArrow}
+ >
{children}
);
diff --git a/app/components/views/TrezorPage/TrezorPageSections/ChangeLabel/ChangeLabel.jsx b/app/components/views/TrezorPage/TrezorPageSections/ChangeLabel/ChangeLabel.jsx
index 39047f9fa8..5c73773b25 100644
--- a/app/components/views/TrezorPage/TrezorPageSections/ChangeLabel/ChangeLabel.jsx
+++ b/app/components/views/TrezorPage/TrezorPageSections/ChangeLabel/ChangeLabel.jsx
@@ -39,7 +39,8 @@ const ChangeLabel = ({
return (
}>
+ label={}
+ >
+ loading={performingOperation}
+ >
diff --git a/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupRow/DeviceSetupRow.jsx b/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupRow/DeviceSetupRow.jsx
index bf34cb2ec6..7c8da18974 100644
--- a/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupRow/DeviceSetupRow.jsx
+++ b/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupRow/DeviceSetupRow.jsx
@@ -20,7 +20,8 @@ const DeviceSetupRow = ({
className={styles.button}
onClick={onClick}
disabled={performingOperation}
- loading={performingOperation}>
+ loading={performingOperation}
+ >
{buttonLabel}
diff --git a/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupSection.jsx b/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupSection.jsx
index 11f049d8b3..cbc29e7fb4 100644
--- a/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupSection.jsx
+++ b/app/components/views/TrezorPage/TrezorPageSections/DeviceSetupSection/DeviceSetupSection.jsx
@@ -12,7 +12,8 @@ const DeviceSetupSection = ({
backupDevice
}) => (
}>
+ label={}
+ >
diff --git a/app/components/views/TrezorPage/TrezorPageSections/FirmwareUpdate/FirmwareUpdate.jsx b/app/components/views/TrezorPage/TrezorPageSections/FirmwareUpdate/FirmwareUpdate.jsx
index b4ca82590c..7e89aed23b 100644
--- a/app/components/views/TrezorPage/TrezorPageSections/FirmwareUpdate/FirmwareUpdate.jsx
+++ b/app/components/views/TrezorPage/TrezorPageSections/FirmwareUpdate/FirmwareUpdate.jsx
@@ -36,7 +36,8 @@ const FirmwareUpdate = ({
return (
}>
+ label={}
+ >
+ disabled={performingOperation || isPerformingUpdate}
+ >
diff --git a/app/containers/App/App.jsx b/app/containers/App/App.jsx
index c862784613..273e3f5f81 100644
--- a/app/containers/App/App.jsx
+++ b/app/containers/App/App.jsx
@@ -23,7 +23,8 @@ const App = () => {
messages={locale.messages}
formats={locale.formats}
defaultFormats={defaultFormats}
- key={locale.key}>
+ key={locale.key}
+ >
@@ -40,7 +41,8 @@ const App = () => {
+ onCancelModal={hideAboutModalMacOS}
+ >
diff --git a/app/containers/Wallet/Wallet.jsx b/app/containers/Wallet/Wallet.jsx
index 78fc2e6851..de2d87cb74 100644
--- a/app/containers/Wallet/Wallet.jsx
+++ b/app/containers/Wallet/Wallet.jsx
@@ -43,7 +43,8 @@ const Wallet = ({ setInterval }) => {
+ className={expandSideBar ? styles.pageView : styles.reducedBar}
+ >
diff --git a/app/helpers/msgTx.js b/app/helpers/msgTx.js
index 3bd5c83c60..0808c490fc 100644
--- a/app/helpers/msgTx.js
+++ b/app/helpers/msgTx.js
@@ -268,6 +268,7 @@ export function decodeRawTransaction(rawTx) {
position += 4;
tx.expiry = rawTx.readUInt32LE(position);
position += 4;
+ tx.prefixOffset = position;
}
if (tx.serType !== SERTYPE_NOWITNESS) {
diff --git a/app/helpers/trezor.js b/app/helpers/trezor.js
index a6ed076cfa..468cb93561 100644
--- a/app/helpers/trezor.js
+++ b/app/helpers/trezor.js
@@ -28,14 +28,14 @@ export const addressPath = (index, branch, account, coinType) => {
};
// walletTxToBtcjsTx is a aux function to convert a tx decoded by the decred wallet (ie,
-// returned from wallet.decoreRawTransaction call) into a bitcoinjs-compatible
+// returned from wallet.decodeRawTransaction call) into a bitcoinjs-compatible
// transaction (to be used in trezor).
export const walletTxToBtcjsTx = async (
walletService,
chainParams,
tx,
inputTxs,
- changeIndex
+ changeIndexes
) => {
const inputs = tx.inputs.map(async (inp) => {
const addr = inp.outpointAddress;
@@ -81,7 +81,7 @@ export const walletTxToBtcjsTx = async (
const addrValidResp = await wallet.validateAddress(walletService, addr);
if (!addrValidResp.isValid) throw "Not a valid address: " + addr;
let address_n = null;
- if (i === changeIndex && addrValidResp.isMine) {
+ if (changeIndexes.includes(i) && addrValidResp.isMine) {
const addrIndex = addrValidResp.index;
const addrBranch = addrValidResp.isInternal ? 1 : 0;
address_n = addressPath(
@@ -124,7 +124,10 @@ export const walletTxToRefTx = async (walletService, tx) => {
const outputs = tx.outputs.map(async (outp) => {
const addr = outp.decodedScript.address;
const addrValidResp = await wallet.validateAddress(walletService, addr);
- if (!addrValidResp.isValid) throw new Error("Not a valid address: " + addr);
+ // Scripts with zero value can be ignored as they are not a concern when
+ // spending from an outpoint.
+ if (outp.value != 0 && !addrValidResp.isValid)
+ throw new Error("Not a valid address: " + addr);
return {
amount: outp.value,
script_pubkey: rawToHex(outp.script),
diff --git a/app/index.js b/app/index.js
index 48abab17fc..008ef94a5a 100644
--- a/app/index.js
+++ b/app/index.js
@@ -561,7 +561,8 @@ const render = () =>
+ fonts={fonts}
+ >
diff --git a/app/main_dev/externalRequests.js b/app/main_dev/externalRequests.js
index 0eef75a5b9..af0b056402 100644
--- a/app/main_dev/externalRequests.js
+++ b/app/main_dev/externalRequests.js
@@ -121,6 +121,10 @@ export const installSessionHandlers = (mainLogger) => {
`connect-src ${connectSrc}; `;
}
+ const requestURL = new URL(details.url);
+ const maybeVSPReqType = `stakepool_${requestURL.protocol}//${requestURL.host}`;
+ const isVSPRequest = allowedExternalRequests[maybeVSPReqType];
+
if (isDev && /^http[s]?:\/\//.test(details.url)) {
// In development (when accessing via the HMR server) we need to overwrite
// the origin, otherwise electron fails to contact external servers due
@@ -144,6 +148,12 @@ export const installSessionHandlers = (mainLogger) => {
newHeaders["Access-Control-Allow-Headers"] = "Content-Type";
}
+ if (isVSPRequest && details.method === "OPTIONS") {
+ statusLine = "OK";
+ newHeaders["Access-Control-Allow-Headers"] =
+ "Content-Type,vsp-client-signature";
+ }
+
const globalCfg = getGlobalCfg();
const cfgAllowedVSPs = globalCfg.get(cfgConstants.ALLOWED_VSP_HOSTS, []);
if (cfgAllowedVSPs.some((url) => details.url.includes(url))) {
@@ -204,6 +214,10 @@ export const allowVSPRequests = (stakePoolHost) => {
addAllowedURL(stakePoolHost + "/api/v3/vspinfo");
addAllowedURL(stakePoolHost + "/api/v3/ticketstatus");
+ addAllowedURL(stakePoolHost + "/api/v3/feeaddress");
+ addAllowedURL(stakePoolHost + "/api/v3/payfee");
+ addAllowedURL(stakePoolHost + "/api/ticketstatus");
+ allowedExternalRequests[reqType] = true;
};
export const reloadAllowedExternalRequests = () => {
diff --git a/app/middleware/vspapi.js b/app/middleware/vspapi.js
index 82977fe459..0ad4020afd 100644
--- a/app/middleware/vspapi.js
+++ b/app/middleware/vspapi.js
@@ -66,3 +66,25 @@ export function getVSPTicketStatus({ host, sig, json }, cb) {
.then((resp) => cb(resp, null, host))
.catch((error) => cb(null, error, host));
}
+
+// getFeeAddress gets a ticket`s fee address.
+export function getFeeAddress({ host, sig, req }, cb) {
+ console.log(req);
+ POST(host + "/api/v3/feeaddress", sig, req)
+ .then((resp) => cb(resp, null, host))
+ .catch((error) => cb(null, error, host));
+}
+
+// payFee infomrs of a ticket`s fee payment.
+export function payFee({ host, sig, req }, cb) {
+ console.log(req);
+ POST(host + "/api/v3/payfee", sig, req)
+ .then((resp) => cb(resp, null, host))
+ .catch((error) => cb(null, error, host));
+}
+
+export function getTicketStatus({ host, vspClientSig, request }, cb) {
+ POST(host + "/api/ticketstatus", vspClientSig, request)
+ .then((resp) => cb(resp, null, host))
+ .catch((error) => cb(null, error, host));
+}
diff --git a/app/reducers/trezor.js b/app/reducers/trezor.js
index 596bd18c51..1c1aff38c2 100644
--- a/app/reducers/trezor.js
+++ b/app/reducers/trezor.js
@@ -19,6 +19,9 @@ import {
TRZ_PASSPHRASE_REQUESTED,
TRZ_PASSPHRASE_ENTERED,
TRZ_PASSPHRASE_CANCELED,
+ TRZ_PURCHASETICKET_ATTEMPT,
+ TRZ_PURCHASETICKET_FAILED,
+ TRZ_PURCHASETICKET_SUCCESS,
TRZ_WORD_REQUESTED,
TRZ_WORD_ENTERED,
TRZ_WORD_CANCELED,
@@ -279,6 +282,12 @@ export default function trezor(state = {}, action) {
performingOperation: false,
performingTogglePassphraseOnDeviceProtection: false
};
+ case TRZ_PURCHASETICKET_ATTEMPT:
+ return {
+ ...state,
+ performingOperation: true,
+ purchasingTickets: true
+ };
case SIGNTX_FAILED:
case SIGNTX_SUCCESS:
case TRZ_CHANGEHOMESCREEN_FAILED:
@@ -305,7 +314,6 @@ export default function trezor(state = {}, action) {
performingOperation: false,
performingUpdate: false
};
-
case TRZ_TOGGLEPINPROTECTION_FAILED:
case TRZ_TOGGLEPINPROTECTION_SUCCESS:
return {
@@ -325,6 +333,13 @@ export default function trezor(state = {}, action) {
performingOperation: false,
performingTogglePassphraseOnDeviceProtection: false
};
+ case TRZ_PURCHASETICKET_FAILED:
+ case TRZ_PURCHASETICKET_SUCCESS:
+ return {
+ ...state,
+ performingOperation: false,
+ purchasingTickets: false
+ };
case CLOSEWALLET_SUCCESS:
return { ...state, enabled: false };
default:
diff --git a/app/selectors.js b/app/selectors.js
index 8a287b5591..69ebb0409e 100644
--- a/app/selectors.js
+++ b/app/selectors.js
@@ -1103,6 +1103,7 @@ export const confirmationDialogModalVisible = bool(
export const isTrezor = get(["trezor", "enabled"]);
export const isPerformingTrezorUpdate = get(["trezor", "performingUpdate"]);
+export const isPurchasingTicketsTrezor = get(["trezor", "purchasingTickets"]);
export const isSignMessageDisabled = and(isWatchingOnly, not(isTrezor));
export const isChangePassPhraseDisabled = isWatchingOnly;
diff --git a/app/wallet/control.js b/app/wallet/control.js
index 0384c38105..cc9bb8b966 100644
--- a/app/wallet/control.js
+++ b/app/wallet/control.js
@@ -222,6 +222,8 @@ export const purchaseTickets = (
resObj.ticketHashes = response
.getTicketHashesList()
.map((v) => rawHashToHex(v));
+ resObj.splitTx = Buffer.from(response.getSplitTx());
+ resObj.ticketsList = response.getTicketsList().map((v) => Buffer.from(v));
resolve(resObj);
});
});
diff --git a/app/wallet/vsp.js b/app/wallet/vsp.js
index 41dbca78d6..500f77d30a 100644
--- a/app/wallet/vsp.js
+++ b/app/wallet/vsp.js
@@ -16,6 +16,11 @@ const promisifyReqLogNoData = (fnName, Req) =>
);
export const getVSPInfo = promisifyReqLogNoData("getVSPInfo", api.getVSPInfo);
+export const getVSPFeeAddress = promisifyReqLogNoData(
+ "getFeeAddress",
+ api.getFeeAddress
+);
+export const payVSPFee = promisifyReqLogNoData("getFeeAddress", api.payFee);
export const getVSPTicketStatus = promisifyReqLogNoData(
"getVSPTicketStatus",
api.getVSPTicketStatus
diff --git a/test/data/decodedTransactions.js b/test/data/decodedTransactions.js
index fc7342676d..900df815fe 100644
--- a/test/data/decodedTransactions.js
+++ b/test/data/decodedTransactions.js
@@ -1,5 +1,6 @@
export const decodedPurchasedTicketTx = {
"version": 1,
+ "prefixOffset": 172,
"serType": 0,
"numInputs": 1,
"inputs": [
@@ -56,6 +57,7 @@ export const decodedPurchasedTicketTx = {
// multiTxPrefix is a tx prefix in the format of how our decodeTxs are. We get
// this format from wallet.decodeRawTransaction().
export const multiTxPrefix = {
+ prefixOffset: 211,
serType: 1, // TxSerializeNoWitness,
version: 1,
numInputs: 1,
@@ -113,6 +115,7 @@ export const multiTxPrefix = {
export const decodedVoteTx = {
"version": 1,
+ "prefixOffset": 201,
"serType": 0,
"numInputs": 2,
"inputs": [
diff --git a/test/test-utils.js b/test/test-utils.js
index eb5c14d515..c48c33d9cb 100644
--- a/test/test-utils.js
+++ b/test/test-utils.js
@@ -83,7 +83,8 @@ function render(ui, renderOptions) {
messages={locale.messages}
formats={locale.formats}
defaultFormats={defaultFormats}
- key={locale.key}>
+ key={locale.key}
+ >
{children}
@@ -93,7 +94,8 @@ function render(ui, renderOptions) {
+ fonts={fonts}
+ >
diff --git a/test/unit/components/SideBar/LastBlockTime.spec.js b/test/unit/components/SideBar/LastBlockTime.spec.js
index 53d31496de..7f8214da72 100644
--- a/test/unit/components/SideBar/LastBlockTime.spec.js
+++ b/test/unit/components/SideBar/LastBlockTime.spec.js
@@ -23,7 +23,8 @@ const Wrapper = ({ lastBlockTimestamp, setTimeout, clearTimeout }) => {
messages={locale.messages}
formats={locale.formats}
defaultFormats={defaultFormats}
- key={locale.key}>
+ key={locale.key}
+ >
{
expect(mockSignTransactionAttempt).not.toHaveBeenCalled();
expect(mockSignTransactionAttemptTrezor).toHaveBeenCalledWith(
testUnsignedTransaction,
- testConstructTxResponse
+ [testConstructTxResponse.changeIndex]
);
await wait(() => expect(mockOnSubmit).toHaveBeenCalled());
});
diff --git a/test/unit/components/shared/VerticalAccordion.spec.js b/test/unit/components/shared/VerticalAccordion.spec.js
index ba7c3625ac..98bf6180cc 100644
--- a/test/unit/components/shared/VerticalAccordion.spec.js
+++ b/test/unit/components/shared/VerticalAccordion.spec.js
@@ -19,7 +19,8 @@ const TestVerticalAccordionContainer = ({ disabled = false }) => {
headerClassName={testHeaderClassName}
arrowClassName={testArrowClassName}
show={show}
- onToggleAccordion={() => setShow((e) => !e)}>
+ onToggleAccordion={() => setShow((e) => !e)}
+ >
);
diff --git a/test/unit/components/views/GovernancePage/TreasurySpending/TreasurySpending.spec.js b/test/unit/components/views/GovernancePage/TreasurySpending/TreasurySpending.spec.js
index 7bb49a5fc0..5fbb793783 100644
--- a/test/unit/components/views/GovernancePage/TreasurySpending/TreasurySpending.spec.js
+++ b/test/unit/components/views/GovernancePage/TreasurySpending/TreasurySpending.spec.js
@@ -97,8 +97,8 @@ const vote = async (
expectedPiKey
) => {
// vote on yes
- const yesRadioBtn = within(container).getByText(policy).parentNode
- .previousSibling;
+ const yesRadioBtn =
+ within(container).getByText(policy).parentNode.previousSibling;
const updatePrefBtn = within(container).getByRole("button", {
name: "Update Preference"
});