Skip to content

Commit

Permalink
chore: add ledger
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Oct 27, 2023
1 parent 316c92d commit e92f169
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 202 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@
"@btckit/types": "0.0.19",
"@leather-wallet/prettier-config": "0.0.1",
"@ls-lint/ls-lint": "2.1.0",
"@pandacss/dev": "0.16.0",
"@pandacss/dev": "0.17.0",
"@playwright/test": "1.38.1",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.11",
"@redux-devtools/cli": "3.0.2",
Expand Down
2 changes: 0 additions & 2 deletions src/app/common/transactions/stacks/broadcast-transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ export async function broadcastStacksTransaction(options: BroadcastTransactionOp
throw new Error('Invalid txid for transaction');
}

logger.info('Transaction broadcast', response);

return {
txId: response.txid,
txRaw,
Expand Down
1 change: 1 addition & 0 deletions src/app/features/ledger/hooks/use-ledger-navigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function useLedgerNavigate() {
toConnectAndSignTransactionStep(transaction: StacksTransaction) {
return navigate(RouteUrls.ConnectLedger, {
replace: true,
relative: 'path',
state: { tx: bytesToHex(transaction.serialize()) },
});
},
Expand Down
20 changes: 6 additions & 14 deletions src/app/pages/home/components/account-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Flex, FlexProps } from 'leather-styles/jsx';

import { RouteUrls } from '@shared/route-urls';

import { useWalletType } from '@app/common/use-wallet-type';
import { ArrowDown } from '@app/components/icons/arrow-down';
import { Plus2 } from '@app/components/icons/plus2';
import { SwapIcon } from '@app/components/icons/swap-icon';
Expand All @@ -18,7 +17,6 @@ export function AccountActions(props: FlexProps) {
const navigate = useNavigate();
const location = useLocation();
const isBitcoinEnabled = useConfigBitcoinEnabled();
const { whenWallet } = useWalletType();

const receivePath = isBitcoinEnabled
? RouteUrls.Receive
Expand All @@ -27,7 +25,6 @@ export function AccountActions(props: FlexProps) {
return (
<Flex justify="space-between" {...props}>
<SendButton />

<ActionButton
data-testid={HomePageSelectors.ReceiveCryptoAssetBtn}
icon={<ArrowDown />}
Expand All @@ -46,17 +43,12 @@ export function AccountActions(props: FlexProps) {
label="Buy"
onClick={() => navigate(RouteUrls.Fund)}
/>
{whenWallet({
software: (
<ActionButton
data-testid={''}
icon={<SwapIcon />}
label="Swap"
onClick={() => navigate(RouteUrls.Swap)}
/>
),
ledger: null,
})}
<ActionButton
data-testid={''}
icon={<SwapIcon />}
label="Swap"
onClick={() => navigate(RouteUrls.Swap)}
/>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export const sendCryptoAssetFormRoutes = (
{editNonceDrawerRoute}
{recipientAccountsDrawerRoute}
</Route>
<Route path="/send/stx/confirm" element={<StacksSendFormConfirmation />}>
<Route
path={`${RouteUrls.SendCryptoAssetForm.replace(':symbol', 'stx')}/confirm`}
element={<StacksSendFormConfirmation />}
>
{ledgerStacksTxSigningRoutes}
</Route>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,27 @@ import { defaultFeesMinValues } from '@app/query/stacks/fees/fees.hooks';
import { useStacksPendingTransactions } from '@app/query/stacks/mempool/mempool.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useGenerateStacksContractCallUnsignedTx } from '@app/store/transactions/contract-call.hooks';
import { useSignTransactionSoftwareWallet } from '@app/store/transactions/transaction.hooks';
import { useSignStacksTransaction } from '@app/store/transactions/transaction.hooks';

import { SwapContainerLayout } from './components/swap-container.layout';
import { SwapForm } from './components/swap-form';
import { generateSwapRoutes } from './generate-swap-routes';
import { useAlexBroadcastSwap } from './hooks/use-alex-broadcast-swap';
import { oneHundredMillion, useAlexSwap } from './hooks/use-alex-swap';
import { useStacksBroadcastSwap } from './hooks/use-stacks-broadcast-swap';
import { SwapAsset, SwapFormValues } from './hooks/use-swap-form';
import { SwapContext, SwapProvider } from './swap.context';
import { migratePositiveBalancesToTop, sortSwappableAssetsBySymbol } from './swap.utils';

export function SwapContainer() {
export const alexSwapRoutes = generateSwapRoutes(<AlexSwapContainer />);

export function AlexSwapContainer() {
const [isSendingMax, setIsSendingMax] = useState(false);
const navigate = useNavigate();
const { setIsLoading } = useLoading(LoadingKeys.SUBMIT_SWAP_TRANSACTION);
const currentAccount = useCurrentStacksAccount();
const generateUnsignedTx = useGenerateStacksContractCallUnsignedTx();
const signSoftwareWalletTx = useSignTransactionSoftwareWallet();
const signTx = useSignStacksTransaction();
const { transactions: pendingTransactions } = useStacksPendingTransactions();

const isSponsoredByAlex = !pendingTransactions.length;
Expand Down Expand Up @@ -163,7 +166,7 @@ export function SwapContainer() {
const unsignedTx = await generateUnsignedTx(payload, tempFormValues);
if (!unsignedTx) return logger.error('Attempted to generate unsigned tx, but tx is undefined');

const signedTx = signSoftwareWalletTx(unsignedTx);
const signedTx = await signTx(unsignedTx);
if (!signedTx) return logger.error('Attempted to generate raw tx, but signed tx is undefined');
const txRaw = bytesToHex(signedTx.serialize());

Expand Down
25 changes: 25 additions & 0 deletions src/app/pages/swap/generate-swap-routes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Route } from 'react-router-dom';

import { RouteUrls } from '@shared/route-urls';

import { ledgerStacksTxSigningRoutes } from '@app/features/ledger/flows/stacks-tx-signing/ledger-sign-tx.routes';
import { AccountGate } from '@app/routes/account-gate';

import { Swap } from './swap';
import { SwapChooseAsset } from './swap-choose-asset/swap-choose-asset';
import { SwapError } from './swap-error/swap-error';
import { SwapReview } from './swap-review/swap-review';

export function generateSwapRoutes(container: React.ReactNode) {
return (
<Route element={<AccountGate>{container}</AccountGate>}>
<Route path={RouteUrls.Swap} element={<Swap />}>
<Route path={RouteUrls.SwapChooseAsset} element={<SwapChooseAsset />} />
</Route>
<Route path={RouteUrls.SwapError} element={<SwapError />} />
<Route path={RouteUrls.SwapReview} element={<SwapReview />}>
{ledgerStacksTxSigningRoutes}
</Route>
</Route>
);
}
27 changes: 16 additions & 11 deletions src/app/pages/swap/swap-review/swap-review.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Outlet } from 'react-router-dom';

import { LoadingKeys, useLoading } from '@app/common/hooks/use-loading';
import { useRouteHeader } from '@app/common/hooks/use-route-header';
import { LeatherButton } from '@app/components/button/button';
Expand All @@ -17,16 +19,19 @@ export function SwapReview() {
useRouteHeader(<ModalHeader defaultGoBack hideActions title="Review" />, true);

return (
<SwapReviewLayout>
<SwapContentLayout>
<SwapAssetsPair />
<SwapDetails />
</SwapContentLayout>
<SwapFooterLayout>
<LeatherButton aria-busy={isLoading} onClick={onSubmitSwap} width="100%">
Swap
</LeatherButton>
</SwapFooterLayout>
</SwapReviewLayout>
<>
<SwapReviewLayout>
<SwapContentLayout>
<SwapAssetsPair />
<SwapDetails />
</SwapContentLayout>
<SwapFooterLayout>
<LeatherButton aria-busy={isLoading} type="button" onClick={onSubmitSwap} fullWidth>
Swap
</LeatherButton>
</SwapFooterLayout>
</SwapReviewLayout>
<Outlet />
</>
);
}
27 changes: 0 additions & 27 deletions src/app/pages/swap/swap.routes.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions src/app/routes/app-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { RpcSignStacksTransaction } from '@app/pages/rpc-sign-stacks-transaction
import { BroadcastError } from '@app/pages/send/broadcast-error/broadcast-error';
import { LockBitcoinSummary } from '@app/pages/send/locked-bitcoin-summary/locked-bitcoin-summary';
import { sendCryptoAssetFormRoutes } from '@app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes';
import { swapRoutes } from '@app/pages/swap/swap.routes';
import { alexSwapRoutes } from '@app/pages/swap/alex-swap-container';
import { UnauthorizedRequest } from '@app/pages/unauthorized-request/unauthorized-request';
import { Unlock } from '@app/pages/unlock';
import { ViewSecretKey } from '@app/pages/view-secret-key/view-secret-key';
Expand Down Expand Up @@ -235,7 +235,7 @@ function useAppRoutes() {
}}
/>

{swapRoutes}
{alexSwapRoutes}

{/* Catch-all route redirects to onboarding */}

Expand Down
56 changes: 56 additions & 0 deletions src/app/store/publish-subscribe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { StacksTransaction } from '@stacks/transactions';

type PubTypeFn<E> = <Key extends string & keyof E>(
event: Key,
// Ensures if we have an event with no payload, the second arg can be empty,
// rather than `undefined`
...message: null extends E[Key] ? [data?: never] : [data: E[Key]]
) => void;

type SubTypeFn<E> = <Key extends string & keyof E>(
event: Key,
fn: (message: E[Key]) => void
) => void;

type MessageFn<E> = <Key extends string & keyof E>(message: E[Key]) => void;

interface PubSubType<E> {
publish: PubTypeFn<E>;
subscribe: SubTypeFn<E>;
unsubscribe: SubTypeFn<E>;
}
function PublishSubscribe<E>(): PubSubType<E> {
const handlers: { [key: string]: MessageFn<any>[] } = {};

return {
publish(event, msg?) {
handlers[event].forEach(h => h(msg));
},

subscribe(event, callback) {
const list = handlers[event] ?? [];
list.push(callback);
handlers[event] = list;
},

unsubscribe(event, callback) {
let list = handlers[event] ?? [];
list = list.filter(h => h !== callback);
handlers[event] = list;
},
};
}

// Global app events. Only add events if your feature isn't capable of
// communicating internally.
export interface GlobalAppEvents {
ledgerStacksTxSigned: {
unsignedTx: string;
signedTx: StacksTransaction;
};
ledgerStacksTxSigningCancelled: {
unsignedTx: string;
};
}

export const appEvents = PublishSubscribe<GlobalAppEvents>();
Loading

0 comments on commit e92f169

Please sign in to comment.