Skip to content

Commit

Permalink
feat: create connect ledger component
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Sep 25, 2020
1 parent 8de28a1 commit e0d1905
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 153 deletions.
2 changes: 1 addition & 1 deletion app/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
AddressBalanceResponse,
} from '@blockstack/stacks-blockchain-api-types';

const api = 'https://sidecar.staging.blockstack.xyz/sidecar';
const api = 'https://stacks-node-api-latest.argon.blockstack.xyz/extended';

async function getAddressBalance(address: string) {
return axios.get<AddressBalanceResponse>(api + `/v1/address/${address}/balances`);
Expand Down
11 changes: 10 additions & 1 deletion app/components/home/stacking-promo-card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from 'react';
import { Box, Flex, Text, Button } from '@blockstack/ui';

import btcPodium from '../../assets/images/btc-podium.svg';
import { openExternalLink } from '../../utils/external-links';
import { BUY_STX_URL } from '../../constants';

export const StackingPromoCard = () => {
return (
Expand All @@ -18,7 +21,13 @@ export const StackingPromoCard = () => {
<Text display="block" mt="tight" textAlign="center" maxWidth="320px" mx="auto">
You’ll earn Bitcoin when you temporarily lock 100,000 STX or more
</Text>
<Button size="md" mt="base" mx="auto" width="272px">
<Button
size="md"
mt="base"
mx="auto"
width="272px"
onClick={() => openExternalLink(BUY_STX_URL)}
>
Buy STX
</Button>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
registerHandler,
deregisterHandler,
} from './transaction-list-context-menu';
import { makeExplorerLink } from '../../../utils/explorer';
import { makeExplorerLink } from '../../../utils/external-links';
import { getRecipientAddress } from '../../../utils/tx-utils';

const dateOptions = {
Expand Down Expand Up @@ -56,10 +56,7 @@ export const TransactionListItem: FC<TransactionListItemProps> = ({ tx, address,

useLayoutEffect(() => {
const el = containerRef.current;
const contextMenuHandler = (e: Event) => {
e.preventDefault();
createTxListContextMenu({ tx, copy });
};
const contextMenuHandler = () => createTxListContextMenu({ tx, copy });
registerHandler(el, contextMenuHandler);
return () => deregisterHandler(el, contextMenuHandler);
}, [tx, copy]);
Expand Down
36 changes: 36 additions & 0 deletions app/components/ledger/ledger-connect-instructions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { FC } from 'react';
import { Box, Flex, CheckmarkCircleIcon } from '@blockstack/ui';

import { LedgerConnectStep } from '../../pages/onboarding';
import { LedgerStepText } from './ledger-step-text';

interface LedgerConnectInstructions {
step: LedgerConnectStep;
}

export const LedgerConnectInstructions: FC<LedgerConnectInstructions> = ({ step }) => {
const hasConnected = (step: LedgerConnectStep) => step > LedgerConnectStep.Disconnected;
const hasOpenedApp = (step: LedgerConnectStep) => step > LedgerConnectStep.ConnectedAppClosed;
const hasAddress = (step: LedgerConnectStep) => step === LedgerConnectStep.HasAddress;

return (
<Box border="1px solid #F0F0F5" mt="extra-loose" borderRadius="8px">
<Flex height="56px" alignItems="center" px="extra-loose" borderBottom="1px solid #F0F0F5">
<LedgerStepText step={LedgerConnectStep.Disconnected}>Connect your Ledger</LedgerStepText>
{hasConnected(step) && <CheckmarkCircleIcon color="blue" size="16px" ml="tight" />}
</Flex>
<Flex height="56px" alignItems="center" px="extra-loose" borderBottom="1px solid #F0F0F5">
<LedgerStepText step={LedgerConnectStep.ConnectedAppClosed}>
Open the Stacks app
</LedgerStepText>
{hasOpenedApp(step) && <CheckmarkCircleIcon color="blue" size="16px" ml="tight" />}
</Flex>
<Flex height="56px" alignItems="center" px="extra-loose">
<LedgerStepText step={LedgerConnectStep.ConnectedAppOpen}>
Confirm your Ledger address
</LedgerStepText>
{hasAddress(step) && <CheckmarkCircleIcon color="blue" size="16px" ml="tight" />}
</Flex>
</Box>
);
};
24 changes: 24 additions & 0 deletions app/components/ledger/ledger-step-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { FC } from 'react';
import { Text } from '@blockstack/ui';
import { LedgerConnectStep } from '../../pages/onboarding/04-connect-ledger/connect-ledger';

interface LedgerStepTextProps {
step: LedgerConnectStep;
}
export const LedgerStepText: FC<LedgerStepTextProps> = ({ step, children }) => {
return (
<>
<Text
color="ink"
fontWeight={500}
mr="base-tight"
display="inline-block"
width="10px"
textAlign="center"
>
{step + 1}
</Text>
{children}
</>
);
};
2 changes: 2 additions & 0 deletions app/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ type Environments = 'development' | 'testing' | 'production';

export const ENV = (process.env.NODE_ENV ?? 'production') as Environments;

export const BUY_STX_URL = 'https://coinmarketcap.com/currencies/blockstack/markets';

export const features = {
stackingEnabled: false,
};
5 changes: 5 additions & 0 deletions app/crypto/key-generation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { memoizeWith, identity } from 'ramda';
import argon2, { ArgonType } from 'argon2-browser';

import { delay } from '../utils/delay';

export async function deriveKey({ pass, salt }: { pass: string; salt: string }) {
// Without this additional delay of 1ms, an odd behaviour with the argon2 library
// causes the promise to be render blocking
await delay(1);
const result = await argon2.hash({
pass,
salt,
Expand Down
5 changes: 1 addition & 4 deletions app/modals/transaction/decrypt-wallet-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import React, { FC } from 'react';
import { Box, Input, Text } from '@blockstack/ui';
import { ErrorLabel } from '../../components/error-label';
import { ErrorText } from '../../components/error-text';
import { useSelector } from 'react-redux';
import { selectDecryptionError } from '../../store/keys';
import { RootState } from '../../store';

interface DecryptWalletFormProps {
hasSubmitted: boolean;
decryptionError?: string;
decryptionError: string | null;
onSetPassword(password: string): void;
}

Expand Down
65 changes: 30 additions & 35 deletions app/modals/transaction/transaction-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
modalStyle,
} from './transaction-modal-layout';
import { validateAddressChain } from '../../crypto/validate-address-net';
import { broadcastStxTransaction } from '../../store/transaction';
import { broadcastStxTransaction, selectMostRecentlyTxError } from '../../store/transaction';
import { toHumanReadableStx, stxToMicroStx } from '../../utils/unit-convert';
import { ErrorLabel } from '../../components/error-label';
import { ErrorText } from '../../components/error-text';
Expand Down Expand Up @@ -52,23 +52,19 @@ export const TransactionModal: FC<TxModalProps> = ({ balance, address }) => {
const [fee, setFee] = useState(new BN(0));
const [amount, setAmount] = useState(new BigNumber(0));
const [password, setPassword] = useState('');
const [hasSubmitted, setHasSubmitted] = useState(false);
const [total, setTotal] = useState(new BigNumber(0));
const [decryptionError, setDecryptionError] = useState('');
const [decryptionError, setDecryptionError] = useState<string | null>(null);
const [isDecrypting, setIsDecrypting] = useState(false);
const [loading, setLoading] = useState(false);
const { txModalOpen, encryptedMnemonic, salt } = useSelector((state: RootState) => ({
txModalOpen: selectTxModalOpen(state),
salt: selectSalt(state),
encryptedMnemonic: selectEncryptedMnemonic(state),
}));
// const forceUpdate = useForceUpdate();

const [hasSubmitted, setHasSubmitted] = useState(false);
const handlePasswordInput = (e: React.FormEvent<HTMLInputElement>) => {
e.preventDefault();
const pass = e.currentTarget.value;
setPassword(pass);
};
const { txModalOpen, encryptedMnemonic, salt, broadcastError } = useSelector(
(state: RootState) => ({
txModalOpen: selectTxModalOpen(state),
salt: selectSalt(state),
encryptedMnemonic: selectEncryptedMnemonic(state),
broadcastError: selectMostRecentlyTxError(state),
})
);

const broadcastTx = async () => {
if (!password || !encryptedMnemonic || !salt) return;
Expand All @@ -92,7 +88,7 @@ export const TransactionModal: FC<TxModalProps> = ({ balance, address }) => {
broadcastStxTransaction({ signedTx: tx, amount, onBroadcastSuccess: closeModalResetForm })
);
} catch (e) {
console.log('');
console.log(e);
setDecryptionError(e);
}
setIsDecrypting(false);
Expand Down Expand Up @@ -146,12 +142,14 @@ export const TransactionModal: FC<TxModalProps> = ({ balance, address }) => {
.required(),
}),
onSubmit: async () => {
// if (!mnemonic) return;
setLoading(true);
setDecryptionError(null);
const demoTx = await makeSTXTokenTransfer({
recipient: form.values.recipient,
network: stacksNetwork,
amount: new BN(stxToMicroStx(form.values.amount).toString()),
//
// TODO: find common burn address
senderKey: 'f0bc18b8c5adc39c26e0fe686c71c7ab3cc1755a3a19e6e1eb84b55f2ede95da01',
});
const { amount, fee } = {
Expand All @@ -176,7 +174,12 @@ export const TransactionModal: FC<TxModalProps> = ({ balance, address }) => {
const txFormStepMap: { [step in TxModalStep]: ModalComponents } = {
[TxModalStep.DescribeTx]: () => ({
header: <TxModalHeader onSelectClose={closeModalResetForm}>Send STX</TxModalHeader>,
body: <TxModalForm balance={balance} form={form} />,
body: (
<>
ST4VFKC1WG386T43ZSMWTVM9TQGCXHR3R1VF99RV
<TxModalForm balance={balance} form={form} />
</>
),
footer: (
<TxModalFooter>
<Button mode="tertiary" onClick={closeModalResetForm} {...buttonStyle}>
Expand Down Expand Up @@ -240,23 +243,15 @@ export const TransactionModal: FC<TxModalProps> = ({ balance, address }) => {
[TxModalStep.ConfirmAndSend]: () => ({
header: <TxModalHeader onSelectClose={closeModalResetForm}>Confirm and send</TxModalHeader>,
body: (
// <Box mx="extra-loose" mt="extra-loose">
// <Text textStyle="body.large">Enter your password to confirm your transaction</Text>
// <Input onChange={handlePasswordInput} mt="base-loose" />
// {hasSubmitted && decryptionError && (
// <ErrorLabel>
// <ErrorText>Password entered is incorrect</ErrorText>
// </ErrorLabel>
// )}
// <Text textStyle="body.small" mt="base-tight" mb="base-loose" display="block">
// Forgot password? Reset your wallet to set a new password.
// </Text>
// </Box>
<DecryptWalletForm
onSetPassword={password => setPassword(password)}
hasSubmitted={hasSubmitted}
decryptionError={decryptionError}
/>
<>
2b458638acb14f46af49384fe1d4b913
<DecryptWalletForm
onSetPassword={password => setPassword(password)}
hasSubmitted={hasSubmitted}
decryptionError={decryptionError}
/>
{JSON.stringify(broadcastError)}
</>
),
footer: (
<TxModalFooter>
Expand Down
2 changes: 1 addition & 1 deletion app/pages/home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Spinner } from '@blockstack/ui';

import { RootState } from '../../store';
import { getAddressTransactions } from '../../store/transaction/transaction.actions';
import { openInExplorer } from '../../utils/explorer';
import { openInExplorer } from '../../utils/external-links';
import { selectAddress } from '../../store/keys/keys.reducer';
import { getAddressDetails } from '../../store/address/address.actions';
import { selectAddressBalance } from '../../store/address/address.reducer';
Expand Down
Loading

0 comments on commit e0d1905

Please sign in to comment.