Skip to content

Commit

Permalink
Merge pull request #3945 from hirosystems/release/fix-ledger-activity
Browse files Browse the repository at this point in the history
Release/fix ledger activity
  • Loading branch information
fbwoolf authored Jun 28, 2023
2 parents e24d8bf + fa2a097 commit 5013df9
Show file tree
Hide file tree
Showing 19 changed files with 250 additions and 70 deletions.
1 change: 1 addition & 0 deletions src/app/components/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function Tabs({
{tabs.map((tab, index) => (
<TabButton
onClick={() => onTabClick(index)}
data-testid={`tab-${tab.slug}`}
isActive={activeTab === index}
key={tab.slug}
label={tab.label}
Expand Down
18 changes: 13 additions & 5 deletions src/app/features/activity-list/activity-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ import { PendingTransactionList } from './components/pending-transaction-list/pe
import { SubmittedTransactionList } from './components/submitted-transaction-list/submitted-transaction-list';
import { TransactionList } from './components/transaction-list/transaction-list';

// TODO: temporary really ugly fix while we address conditional data problem of
// bitcoin sometimes being undefined
function useBitcoinAddress() {
try {
return useCurrentAccountNativeSegwitIndexZeroSigner().address;
} catch (e) {
return '';
}
}

export function ActivityList() {
const nativeSegwitSigner = useCurrentAccountNativeSegwitIndexZeroSigner();
const bitcoinAddress = useBitcoinAddress();
const { isInitialLoading: isInitialLoadingBitcoinTransactions, data: bitcoinTransactions } =
useGetBitcoinTransactionsByAddressQuery(nativeSegwitSigner.address);
const { data: bitcoinPendingTxs = [] } = useBitcoinPendingTransactions(
nativeSegwitSigner.address
);
useGetBitcoinTransactionsByAddressQuery(bitcoinAddress);
const { data: bitcoinPendingTxs = [] } = useBitcoinPendingTransactions(bitcoinAddress);
const {
isInitialLoading: isInitialLoadingStacksTransactions,
data: stacksTransactionsWithTransfers,
Expand Down
6 changes: 3 additions & 3 deletions src/app/pages/rpc-send-transfer/rpc-send-transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import BigNumber from 'bignumber.js';
import { createMoney } from '@shared/models/money.model';

import { formatMoneyPadded } from '@app/common/money/format-money';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitIndexZeroSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';

import { SendTransferActions } from './components/send-transfer-actions';
import { SendTransferDetails } from './components/send-transfer-details';
import { SendTransferHeader } from './components/send-transfer-header';
import { useRpcSendTransfer } from './use-rpc-send-transfer';

export function RpcSendTransfer() {
const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const nativeSegwitSigner = useCurrentAccountNativeSegwitIndexZeroSigner();
const { address, amount, onChooseTransferFee, origin } = useRpcSendTransfer();

const amountAsMoney = createMoney(new BigNumber(amount), 'BTC');
Expand All @@ -24,7 +24,7 @@ export function RpcSendTransfer() {
<SendTransferDetails
address={address}
amount={formattedMoney}
currentAddress={bitcoinAddress}
currentAddress={nativeSegwitSigner.address}
/>
<SendTransferActions action="Continue" onApprove={onChooseTransferFee} />
</>
Expand Down
6 changes: 2 additions & 4 deletions src/app/pages/rpc-sign-psbt/rpc-sign-psbt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,23 @@ function useRpcSignPsbtParams() {
const { origin, tabId } = useDefaultRequestParams();
const requestId = searchParams.get('requestId');
const psbtHex = searchParams.get('hex');
const publicKey = searchParams.get('publicKey');
const allowedSighash = searchParams.getAll('allowedSighash');
const signAtIndex = searchParams.getAll('signAtIndex');

if (!requestId || !psbtHex || !publicKey || !origin) throw new Error('Invalid params');
if (!requestId || !psbtHex || !origin) throw new Error('Invalid params');

return useMemo(
() => ({
origin,
tabId: tabId ?? 0,
requestId,
psbtHex,
publicKey,
allowedSighash: undefinedIfLengthZero(
allowedSighash.map(h => Number(h)) as btc.SignatureHash[]
),
signAtIndex: undefinedIfLengthZero(signAtIndex.map(h => Number(h))),
}),
[allowedSighash, origin, psbtHex, publicKey, requestId, signAtIndex, tabId]
[allowedSighash, origin, psbtHex, requestId, signAtIndex, tabId]
);
}

Expand Down
4 changes: 0 additions & 4 deletions src/app/query/bitcoin/ordinals/ordinals-aware-utxo.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { isTypedArray } from '@shared/utils';
import { Prettify } from '@shared/utils/type-utils';

import { QueryPrefixes } from '@app/query/query-prefixes';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';

import { TaprootUtxo } from './use-taproot-address-utxos.query';

Expand Down Expand Up @@ -59,14 +58,11 @@ const queryOptions = {
} as const;

export function useOrdinalsAwareUtxoQueries(utxos: TaprootUtxo[] | btc.TransactionInputRequired[]) {
const network = useCurrentNetwork();

return useQueries({
queries: utxos.map(utxo => {
const txId = isTypedArray(utxo.txid) ? bytesToHex(utxo.txid) : utxo.txid;
const txIndex = 'index' in utxo ? utxo.index : utxo.vout;
return {
enabled: network.chain.bitcoin.network === 'mainnet',
queryKey: makeOrdinalsAwareUtxoQueryKey(txId, txIndex),
queryFn: () => fetchOrdinalsAwareUtxo(txId, txIndex),
select: (resp: OrdApiInscriptionTxOutput) =>
Expand Down
36 changes: 31 additions & 5 deletions src/background/messaging/rpc-methods/send-transfer.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,62 @@
import { RpcErrorCode, SendTransferRequest } from '@btckit/types';

import { RouteUrls } from '@shared/route-urls';
import {
getRpcSendTransferParamErrors,
validateRpcSendTransferParams,
} from '@shared/rpc/methods/send-transfer';
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
import { isDefined, isUndefined } from '@shared/utils';

import {
RequestParams,
getTabIdFromPort,
listenForPopupClose,
makeSearchParamsWithDefaults,
triggerRequestWindowOpen,
} from '../messaging-utils';

export async function rpcSendTransfer(message: SendTransferRequest, port: chrome.runtime.Port) {
if (!message.params || !message.params.address || !message.params.amount) {
if (isUndefined(message.params)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('sendTransfer', {
id: message.id,
error: { code: RpcErrorCode.INVALID_REQUEST, message: 'Parameters undefined' },
})
);
return;
}

if (!validateRpcSendTransferParams(message.params)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('sendTransfer', {
id: message.id,
error: {
code: RpcErrorCode.INVALID_PARAMS,
message:
'Invalid parameters. See the btckit spec for more information: https://btckit.org/docs/spec',
message: getRpcSendTransferParamErrors(message.params),
},
})
);
return;
}
const { urlParams, tabId } = makeSearchParamsWithDefaults(port, [

const requestParams: RequestParams = [
['address', message.params.address],
['amount', message.params.amount],
['network', (message.params as any).network ?? 'mainnet'],
['requestId', message.id],
]);
];

if (isDefined((message.params as any).account)) {
requestParams.push(['accountIndex', (message.params as any).account.toString()]);
}

const { urlParams, tabId } = makeSearchParamsWithDefaults(port, requestParams);

const { id } = await triggerRequestWindowOpen(RouteUrls.RpcSendTransfer, urlParams);

listenForPopupClose({
tabId,
id,
Expand Down
45 changes: 36 additions & 9 deletions src/background/messaging/rpc-methods/sign-message.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,52 @@
import { RpcErrorCode } from '@btckit/types';
import { PaymentTypes, RpcErrorCode } from '@btckit/types';
import { SignMessageRequest } from '@btckit/types/dist/types/methods/sign-message';

import { isSupportedMessageSigningPaymentType } from '@shared/crypto/bitcoin/bip322/bip322-utils';
import { RouteUrls } from '@shared/route-urls';
import {
getRpcSignMessageParamErrors,
validateRpcSignMessageParams,
} from '@shared/rpc/methods/sign-message';
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
import { isString } from '@shared/utils';
import { isDefined, isUndefined } from '@shared/utils';

import {
RequestParams,
getTabIdFromPort,
listenForPopupClose,
makeSearchParamsWithDefaults,
triggerRequestWindowOpen,
} from '../messaging-utils';

export async function rpcSignMessage(message: SignMessageRequest, port: chrome.runtime.Port) {
if (!message.params || !isString(message.params.message)) {
if (isUndefined(message.params)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('signMessage', {
id: message.id,
error: { code: RpcErrorCode.INVALID_REQUEST, message: 'Parameters undefined' },
})
);
return;
}

if (!validateRpcSignMessageParams(message.params)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('signMessage', {
id: message.id,
error: {
code: RpcErrorCode.INVALID_PARAMS,
message:
'Invalid parameters. Message signing requires a message. See the btckit spec for more information: https://btckit.org/docs/spec',
message: getRpcSignMessageParamErrors(message.params),
},
})
);
return;
}
const paymentType = (message.params as any).paymentType ?? 'p2wpkh';

const paymentType: Extract<'p2tr' | 'p2wpkh', PaymentTypes> =
(message.params as any).paymentType ?? 'p2wpkh';

if (!isSupportedMessageSigningPaymentType(paymentType)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
Expand All @@ -43,12 +61,21 @@ export async function rpcSignMessage(message: SignMessageRequest, port: chrome.r
);
return;
}
const { urlParams, tabId } = makeSearchParamsWithDefaults(port, [

const requestParams: RequestParams = [
['message', message.params.message],
['requestId', message.id],
['network', (message.params as any).network ?? 'mainnet'],
['paymentType', paymentType],
]);
['requestId', message.id],
];

if (isDefined((message.params as any).account)) {
requestParams.push(['accountIndex', (message.params as any).account.toString()]);
}

const { urlParams, tabId } = makeSearchParamsWithDefaults(port, requestParams);
const { id } = await triggerRequestWindowOpen(RouteUrls.RpcSignBip322Message, urlParams);

listenForPopupClose({
tabId,
id,
Expand Down
28 changes: 18 additions & 10 deletions src/background/messaging/rpc-methods/sign-psbt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
validateRpcSignPsbtParams,
} from '@shared/rpc/methods/sign-psbt';
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
import { ensureArray, isDefined } from '@shared/utils';
import { ensureArray, isDefined, isUndefined } from '@shared/utils';

import {
RequestParams,
Expand All @@ -29,17 +29,25 @@ function validatePsbt(hex: string) {
}

export async function rpcSignPsbt(message: SignPsbtRequest, port: chrome.runtime.Port) {
if (isUndefined(message.params)) {
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('signPsbt', {
id: message.id,
error: { code: RpcErrorCode.INVALID_REQUEST, message: 'Parameters undefined' },
})
);
return;
}

if (!validateRpcSignPsbtParams(message.params)) {
const errors = getRpcSignPsbtParamErrors(message.params);
chrome.tabs.sendMessage(
getTabIdFromPort(port),
makeRpcErrorResponse('signPsbt', {
id: message.id,
error: {
code: RpcErrorCode.INVALID_PARAMS,
message:
'Invalid parameters: ' +
errors.map(e => `Error in path ${e.path}, ${e.message}.`).join(' '),
message: getRpcSignPsbtParamErrors(message.params),
},
})
);
Expand All @@ -58,19 +66,18 @@ export async function rpcSignPsbt(message: SignPsbtRequest, port: chrome.runtime
}

const requestParams: RequestParams = [
['requestId', message.id],
['hex', message.params.hex],
['publicKey', message.params.publicKey],
['network', message.params.network ?? 'mainnet'],
['requestId', message.id],
];

if (isDefined(message.params.account)) {
requestParams.push(['accountIndex', message.params.account.toString()]);
}

if (isDefined(message.params.allowedSighash))
message.params.allowedSighash.forEach(hash =>
requestParams.push(['allowedSighash', (hash ?? btc.SignatureHash.ALL).toString()])
if (isDefined(message.params.allowedSighash) && message.params.allowedSighash.length)
message.params.allowedSighash.forEach((hash: any) =>
requestParams.push(['allowedSighash', hash.toString()])
);

if (isDefined(message.params.signAtIndex))
Expand All @@ -81,6 +88,7 @@ export async function rpcSignPsbt(message: SignPsbtRequest, port: chrome.runtime
const { urlParams, tabId } = makeSearchParamsWithDefaults(port, requestParams);

const { id } = await triggerRequestWindowOpen(RouteUrls.RpcSignPsbt, urlParams);

listenForPopupClose({
tabId,
id,
Expand Down
2 changes: 1 addition & 1 deletion src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export enum WalletDefaultNetworkConfigurationIds {

export type DefaultNetworkConfigurations = keyof typeof WalletDefaultNetworkConfigurationIds;

export const networkModes = ['mainnet', 'testnet'] as const;
const networkModes = ['mainnet', 'testnet'] as const;

export type NetworkModes = (typeof networkModes)[number];

Expand Down
26 changes: 26 additions & 0 deletions src/shared/rpc/methods/send-transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as yup from 'yup';

import { WalletDefaultNetworkConfigurationIds } from '@shared/constants';

import {
accountSchema,
formatValidationErrors,
getRpcParamErrors,
validateRpcParams,
} from './validation.utils';

const rpcSendTransferParamsSchema = yup.object().shape({
account: accountSchema,
address: yup.string().required(),
amount: yup.string().required(),
network: yup.string().oneOf(Object.values(WalletDefaultNetworkConfigurationIds)),
});

// TODO: Import param types from btckit when updated
export function validateRpcSendTransferParams(obj: unknown) {
return validateRpcParams(obj, rpcSendTransferParamsSchema);
}

export function getRpcSendTransferParamErrors(obj: unknown) {
return formatValidationErrors(getRpcParamErrors(obj, rpcSendTransferParamsSchema));
}
Loading

0 comments on commit 5013df9

Please sign in to comment.