Skip to content

Commit 98d58d4

Browse files
committed
multi: Allow trezor ticket purchasing on testnet.
Add purchaseTicketsV3 which purchases tickets using a watching only trezor wallet from a vsp with api v3. Errors if not on testnet. Add separate payVSPFee function that will pay a tickets fee if not already paid, and throws if already paid. Correct purchase ticket button for watching only wallets. It no longer asks for a password. Connect purchasing through trezor when isTrezor is true. Add vsp v3 endpoints "feeaddress" and "payfee" to allowed external requests. Change wallet/control.js to not require an unlocked wallet when signTx is false. Add headers to OPTIONS externalRequest. These are required by CORS when making POST requests.
1 parent 372e7f6 commit 98d58d4

File tree

22 files changed

+517
-29
lines changed

22 files changed

+517
-29
lines changed

app/actions/TrezorActions.js

Lines changed: 397 additions & 5 deletions
Large diffs are not rendered by default.

app/components/Snackbar/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ const Snackbar = () => {
7878
className={snackbarClasses(message || "")}
7979
onMouseEnter={clearHideTimer}
8080
onMouseLeave={enableHideTimer}
81-
style={{ bottom: "0px" }}>
81+
style={{ bottom: "0px" }}
82+
>
8283
<Notification
8384
{...{
8485
topNotification: i === 0,
@@ -143,7 +144,8 @@ const Snackbar = () => {
143144
onMouseEnter={clearHideTimer}
144145
onMouseLeave={enableHideTimer}
145146
style={s.style}
146-
ref={(ref) => animatedNotifRef(s.key, ref)}>
147+
ref={(ref) => animatedNotifRef(s.key, ref)}
148+
>
147149
<Notification
148150
{...{
149151
topNotification: i === 0,

app/components/buttons/SendTransactionButton/hooks.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ export function useSendTransactionButton() {
1414
dispatch(ca.signTransactionAttempt(passphrase, rawTx, acct));
1515
};
1616
const onAttemptSignTransactionTrezor = (rawUnsigTx, constructTxResponse) =>
17-
dispatch(tza.signTransactionAttemptTrezor(rawUnsigTx, constructTxResponse));
17+
dispatch(
18+
tza.signTransactionAttemptTrezor(rawUnsigTx, [
19+
constructTxResponse.changeIndex
20+
])
21+
);
1822

1923
return {
2024
unsignedTransaction,

app/components/views/GetStartedPage/SetupWallet/hooks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ export const useWalletSetup = (settingUpWalletRef) => {
175175
<ExternalLink
176176
href={
177177
"https://docs.decred.org/wallets/decrediton/migrations"
178-
}>
178+
}
179+
>
179180
<T id="getstarted.setAccountsPass.docs" m="Decred docs" />
180181
</ExternalLink>
181182
)

app/components/views/TicketsPage/PurchaseTab/PurchaseTabPage.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export function PurchaseTabPage({
7272
isVSPListingEnabled,
7373
onEnableVSPListing,
7474
getRunningIndicator,
75+
isPurchasingTicketsTrezor,
7576
...props
7677
}) {
7778
return (
@@ -115,7 +116,9 @@ export function PurchaseTabPage({
115116
isLoading,
116117
rememberedVspHost,
117118
toggleRememberVspHostCheckBox,
118-
getRunningIndicator
119+
getRunningIndicator,
120+
isPurchasingTicketsTrezor,
121+
isWatchingOnly
119122
}}
120123
/>
121124
)}

app/components/views/TicketsPage/PurchaseTab/PurchaseTicketsForm/PurchaseTicketsForm.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const PurchaseTicketsForm = ({
3636
rememberedVspHost,
3737
toggleRememberVspHostCheckBox,
3838
notMixedAccounts,
39-
getRunningIndicator
39+
getRunningIndicator,
40+
isPurchasingTicketsTrezor
4041
}) => {
4142
const intl = useIntl();
4243
return (
@@ -149,7 +150,10 @@ const PurchaseTicketsForm = ({
149150
</div>
150151
<div className={styles.buttonsArea}>
151152
{isWatchingOnly ? (
152-
<PiUiButton disabled={!isValid} onClick={onPurchaseTickets}>
153+
<PiUiButton
154+
disabled={!isValid}
155+
loading={isPurchasingTicketsTrezor}
156+
onClick={onPurchaseTickets}>
153157
{purchaseLabel()}
154158
</PiUiButton>
155159
) : isLoading ? (

app/components/views/TicketsPage/PurchaseTab/hooks.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useCallback, useMemo } from "react";
33
import { useSettings } from "hooks";
44
import { EXTERNALREQUEST_STAKEPOOL_LISTING } from "constants";
55

6+
import { purchaseTicketsAttempt as trezorPurchseTicketsAttempt } from "actions/TrezorActions.js";
67
import * as vspa from "actions/VSPActions";
78
import * as ca from "actions/ControlActions.js";
89
import * as sel from "selectors";
@@ -21,6 +22,8 @@ export const usePurchaseTab = () => {
2122
const ticketAutoBuyerRunning = useSelector(sel.getTicketAutoBuyerRunning);
2223
const isLoading = useSelector(sel.purchaseTicketsRequestAttempt);
2324
const notMixedAccounts = useSelector(sel.getNotMixedAccounts);
25+
const isTrezor = useSelector(sel.isTrezor);
26+
const isPurchasingTicketsTrezor = useSelector(sel.isPurchasingTicketsTrezor);
2427

2528
const rememberedVspHost = useSelector(sel.getRememberedVspHost);
2629
const visibleAccounts = useSelector(sel.visibleAccounts);
@@ -54,9 +57,16 @@ export const usePurchaseTab = () => {
5457
[dispatch]
5558
);
5659
const purchaseTicketsAttempt = useCallback(
57-
(passphrase, account, numTickets, vsp) =>
58-
dispatch(ca.purchaseTicketsAttempt(passphrase, account, numTickets, vsp)),
59-
[dispatch]
60+
(passphrase, account, numTickets, vsp) => {
61+
if (isTrezor) {
62+
dispatch(trezorPurchseTicketsAttempt(account, numTickets, vsp));
63+
} else {
64+
dispatch(
65+
ca.purchaseTicketsAttempt(passphrase, account, numTickets, vsp)
66+
);
67+
}
68+
},
69+
[dispatch, isTrezor]
6070
);
6171

6272
const setRememberedVspHost = useCallback(
@@ -140,6 +150,7 @@ export const usePurchaseTab = () => {
140150
vsp,
141151
setVSP,
142152
numTicketsToBuy,
143-
setNumTicketsToBuy
153+
setNumTicketsToBuy,
154+
isPurchasingTicketsTrezor
144155
};
145156
};

app/helpers/msgTx.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ export function decodeRawTransaction(rawTx) {
268268
position += 4;
269269
tx.expiry = rawTx.readUInt32LE(position);
270270
position += 4;
271+
tx.prefixOffset = position;
271272
}
272273

273274
if (tx.serType !== SERTYPE_NOWITNESS) {

app/helpers/trezor.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ export const addressPath = (index, branch, account, coinType) => {
2828
};
2929

3030
// walletTxToBtcjsTx is a aux function to convert a tx decoded by the decred wallet (ie,
31-
// returned from wallet.decoreRawTransaction call) into a bitcoinjs-compatible
31+
// returned from wallet.decodeRawTransaction call) into a bitcoinjs-compatible
3232
// transaction (to be used in trezor).
3333
export const walletTxToBtcjsTx = async (
3434
walletService,
3535
chainParams,
3636
tx,
3737
inputTxs,
38-
changeIndex
38+
changeIndexes
3939
) => {
4040
const inputs = tx.inputs.map(async (inp) => {
4141
const addr = inp.outpointAddress;
@@ -81,7 +81,7 @@ export const walletTxToBtcjsTx = async (
8181
const addrValidResp = await wallet.validateAddress(walletService, addr);
8282
if (!addrValidResp.isValid) throw "Not a valid address: " + addr;
8383
let address_n = null;
84-
if (i === changeIndex && addrValidResp.isMine) {
84+
if (changeIndexes.includes(i) && addrValidResp.isMine) {
8585
const addrIndex = addrValidResp.index;
8686
const addrBranch = addrValidResp.isInternal ? 1 : 0;
8787
address_n = addressPath(
@@ -124,7 +124,10 @@ export const walletTxToRefTx = async (walletService, tx) => {
124124
const outputs = tx.outputs.map(async (outp) => {
125125
const addr = outp.decodedScript.address;
126126
const addrValidResp = await wallet.validateAddress(walletService, addr);
127-
if (!addrValidResp.isValid) throw new Error("Not a valid address: " + addr);
127+
// Scripts with zero value can be ignored as they are not a concern when
128+
// spending from an outpoint.
129+
if (outp.value != 0 && !addrValidResp.isValid)
130+
throw new Error("Not a valid address: " + addr);
128131
return {
129132
amount: outp.value,
130133
script_pubkey: rawToHex(outp.script),

app/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ const render = () =>
561561
<ThemeProvider
562562
themes={themes}
563563
defaultThemeName={defaultThemeName}
564-
fonts={fonts}>
564+
fonts={fonts}
565+
>
565566
<Provider store={store}>
566567
<ConnectedRouter history={history}>
567568
<Switch>

0 commit comments

Comments
 (0)