mirror of
https://github.com/zhigang1992/wallet.git
synced 2026-04-29 13:15:32 +08:00
refactor: psbt error handling, closes #3804
This commit is contained in:
51
src/app/common/psbt/use-psbt-request-params.ts
Normal file
51
src/app/common/psbt/use-psbt-request-params.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import * as btc from '@scure/btc-signer';
|
||||
|
||||
import { undefinedIfLengthZero } from '@shared/utils';
|
||||
|
||||
import { useRejectIfLedgerWallet } from '@app/common/rpc-helpers';
|
||||
|
||||
import { useDefaultRequestParams } from '../hooks/use-default-request-search-params';
|
||||
|
||||
export function usePsbtRequestSearchParams() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const { origin, tabId } = useDefaultRequestParams();
|
||||
const requestToken = searchParams.get('request');
|
||||
return useMemo(
|
||||
() => ({
|
||||
origin,
|
||||
tabId: tabId ?? 1,
|
||||
requestToken,
|
||||
}),
|
||||
[origin, requestToken, tabId]
|
||||
);
|
||||
}
|
||||
|
||||
export function useRpcSignPsbtParams() {
|
||||
useRejectIfLedgerWallet('signPsbt');
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const { origin, tabId } = useDefaultRequestParams();
|
||||
const requestId = searchParams.get('requestId');
|
||||
const psbtHex = searchParams.get('hex');
|
||||
const allowedSighash = searchParams.getAll('allowedSighash');
|
||||
const signAtIndex = searchParams.getAll('signAtIndex');
|
||||
|
||||
if (!requestId || !psbtHex || !origin) throw new Error('Invalid params');
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
origin,
|
||||
tabId: tabId ?? 0,
|
||||
requestId,
|
||||
psbtHex,
|
||||
allowedSighash: undefinedIfLengthZero(
|
||||
allowedSighash.map(h => Number(h)) as btc.SignatureHash[]
|
||||
),
|
||||
signAtIndex: undefinedIfLengthZero(signAtIndex.map(h => Number(h))),
|
||||
}),
|
||||
[allowedSighash, origin, psbtHex, requestId, signAtIndex, tabId]
|
||||
);
|
||||
}
|
||||
@@ -9,9 +9,12 @@ import { isString } from '@shared/utils';
|
||||
import { useCurrentAccountNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
|
||||
import { useCurrentAccountTaprootSigner } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
|
||||
|
||||
import { useSignPsbtError } from './use-sign-psbt-error';
|
||||
|
||||
export type DecodedPsbt = ReturnType<typeof btc.RawPSBTV0.decode>;
|
||||
|
||||
export function usePsbtSigner() {
|
||||
const signPsbtError = useSignPsbtError();
|
||||
const createNativeSegwitSigner = useCurrentAccountNativeSegwitSigner();
|
||||
const createTaprootSigner = useCurrentAccountTaprootSigner();
|
||||
|
||||
@@ -27,7 +30,7 @@ export function usePsbtSigner() {
|
||||
try {
|
||||
taprootSigner?.signIndex(tx, idx, allowedSighash);
|
||||
} catch (e2) {
|
||||
logger.error('Error signing tx at provided index', e1, e2);
|
||||
signPsbtError(`Error signing PSBT at provided index, ${e1}, ${e2}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -38,7 +41,7 @@ export function usePsbtSigner() {
|
||||
try {
|
||||
taprootSigner?.sign(tx);
|
||||
} catch (e2) {
|
||||
logger.error('Error signing PSBT', e1, e2);
|
||||
signPsbtError(`Error signing PSBT, ${e1}, ${e2}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -51,16 +54,16 @@ export function usePsbtSigner() {
|
||||
try {
|
||||
return btc.RawPSBTV0.decode(bytes);
|
||||
} catch (e0) {
|
||||
logger.info('Failed to decode as PSBT v0, trying V2', e0);
|
||||
}
|
||||
try {
|
||||
return btc.RawPSBTV2.decode(bytes);
|
||||
} catch (e2) {
|
||||
logger.error('Error parsing psbt version', e2);
|
||||
logger.error(`Failed to decode as PSBT v0, trying v2, ${e0}`);
|
||||
try {
|
||||
return btc.RawPSBTV2.decode(bytes);
|
||||
} catch (e2) {
|
||||
signPsbtError(`Failed to decode PSBT as v0 and v2, ${e0}, ${e2}`);
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
}),
|
||||
[nativeSegwitSigner, taprootSigner]
|
||||
[nativeSegwitSigner, signPsbtError, taprootSigner]
|
||||
);
|
||||
}
|
||||
|
||||
39
src/app/features/psbt-signer/hooks/use-sign-psbt-error.tsx
Normal file
39
src/app/features/psbt-signer/hooks/use-sign-psbt-error.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { RpcErrorCode } from '@btckit/types';
|
||||
|
||||
import { finalizePsbt } from '@shared/actions/finalize-psbt';
|
||||
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods';
|
||||
|
||||
import {
|
||||
usePsbtRequestSearchParams,
|
||||
useRpcSignPsbtParams,
|
||||
} from '@app/common/psbt/use-psbt-request-params';
|
||||
|
||||
export function useSignPsbtError() {
|
||||
const { requestToken, tabId } = usePsbtRequestSearchParams();
|
||||
const { requestId, tabId: rpcTabId } = useRpcSignPsbtParams();
|
||||
|
||||
return useCallback(
|
||||
(errorMsg: string) => {
|
||||
if (requestToken)
|
||||
finalizePsbt({
|
||||
requestPayload: requestToken,
|
||||
tabId,
|
||||
data: errorMsg,
|
||||
});
|
||||
chrome.tabs.sendMessage(
|
||||
rpcTabId,
|
||||
makeRpcErrorResponse('signPsbt', {
|
||||
id: requestId,
|
||||
error: {
|
||||
message: errorMsg,
|
||||
code: RpcErrorCode.INTERNAL_ERROR,
|
||||
},
|
||||
})
|
||||
);
|
||||
window.close();
|
||||
},
|
||||
[requestId, requestToken, rpcTabId, tabId]
|
||||
);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useDefaultRequestParams } from '@app/common/hooks/use-default-request-search-params';
|
||||
|
||||
export function usePsbtRequestSearchParams() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const { origin, tabId } = useDefaultRequestParams();
|
||||
const requestToken = searchParams.get('request');
|
||||
return useMemo(
|
||||
() => ({
|
||||
origin,
|
||||
tabId: tabId ?? 1,
|
||||
requestToken,
|
||||
}),
|
||||
[origin, requestToken, tabId]
|
||||
);
|
||||
}
|
||||
@@ -3,13 +3,12 @@ import { useMemo, useState } from 'react';
|
||||
import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
|
||||
|
||||
import { finalizePsbt } from '@shared/actions/finalize-psbt';
|
||||
import { logger } from '@shared/logger';
|
||||
import { ensureArray, isUndefined } from '@shared/utils';
|
||||
|
||||
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
|
||||
import { getPsbtPayloadFromToken } from '@app/common/psbt/requests';
|
||||
import { usePsbtRequestSearchParams } from '@app/common/psbt/use-psbt-request-params';
|
||||
import { usePsbtSigner } from '@app/features/psbt-signer/hooks/use-psbt-signer';
|
||||
import { usePsbtRequestSearchParams } from '@app/pages/psbt-request/psbt-request.hooks';
|
||||
|
||||
export function usePsbtRequest() {
|
||||
const { requestToken, tabId } = usePsbtRequestSearchParams();
|
||||
@@ -18,6 +17,7 @@ export function usePsbtRequest() {
|
||||
const analytics = useAnalytics();
|
||||
return useMemo(() => {
|
||||
if (!requestToken) throw new Error('Cannot decode psbt without request token');
|
||||
|
||||
const payload = getPsbtPayloadFromToken(requestToken);
|
||||
const payloadTxBytes = hexToBytes(payload.hex);
|
||||
const appName = payload?.appDetails?.name;
|
||||
@@ -34,7 +34,7 @@ export function usePsbtRequest() {
|
||||
payloadTxBytes,
|
||||
onDenyPsbtSigning() {
|
||||
void analytics.track('request_psbt_cancel');
|
||||
finalizePsbt({ requestPayload: requestToken ?? '', tabId, data: 'cancel' });
|
||||
finalizePsbt({ requestPayload: requestToken, tabId, data: 'PSBT request was canceled' });
|
||||
},
|
||||
onSignPsbt() {
|
||||
setIsLoading(true);
|
||||
@@ -42,8 +42,6 @@ export function usePsbtRequest() {
|
||||
|
||||
const tx = getPsbtAsTransaction(payload.hex);
|
||||
|
||||
if (!tx) return logger.error('No psbt to sign');
|
||||
|
||||
const indexOrIndexes = payload?.signAtIndex;
|
||||
const allowedSighash = payload?.allowedSighash;
|
||||
|
||||
|
||||
@@ -1,45 +1,13 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { RpcErrorCode } from '@btckit/types';
|
||||
import { bytesToHex } from '@noble/hashes/utils';
|
||||
import * as btc from '@scure/btc-signer';
|
||||
|
||||
import { makeRpcErrorResponse, makeRpcSuccessResponse } from '@shared/rpc/rpc-methods';
|
||||
import { isDefined, undefinedIfLengthZero } from '@shared/utils';
|
||||
import { isDefined } from '@shared/utils';
|
||||
|
||||
import { useDefaultRequestParams } from '@app/common/hooks/use-default-request-search-params';
|
||||
import { useRejectIfLedgerWallet } from '@app/common/rpc-helpers';
|
||||
import { useRpcSignPsbtParams } from '@app/common/psbt/use-psbt-request-params';
|
||||
import { usePsbtSigner } from '@app/features/psbt-signer/hooks/use-psbt-signer';
|
||||
import { PsbtSigner } from '@app/features/psbt-signer/psbt-signer';
|
||||
|
||||
function useRpcSignPsbtParams() {
|
||||
useRejectIfLedgerWallet('signPsbt');
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const { origin, tabId } = useDefaultRequestParams();
|
||||
const requestId = searchParams.get('requestId');
|
||||
const psbtHex = searchParams.get('hex');
|
||||
const allowedSighash = searchParams.getAll('allowedSighash');
|
||||
const signAtIndex = searchParams.getAll('signAtIndex');
|
||||
|
||||
if (!requestId || !psbtHex || !origin) throw new Error('Invalid params');
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
origin,
|
||||
tabId: tabId ?? 0,
|
||||
requestId,
|
||||
psbtHex,
|
||||
allowedSighash: undefinedIfLengthZero(
|
||||
allowedSighash.map(h => Number(h)) as btc.SignatureHash[]
|
||||
),
|
||||
signAtIndex: undefinedIfLengthZero(signAtIndex.map(h => Number(h))),
|
||||
}),
|
||||
[allowedSighash, origin, psbtHex, requestId, signAtIndex, tabId]
|
||||
);
|
||||
}
|
||||
|
||||
function useRpcSignPsbt() {
|
||||
const { origin, tabId, requestId, psbtHex, allowedSighash, signAtIndex } = useRpcSignPsbtParams();
|
||||
const { signPsbt, signPsbtAtIndex, getDecodedPsbt, getPsbtAsTransaction } = usePsbtSigner();
|
||||
@@ -78,6 +46,7 @@ function useRpcSignPsbt() {
|
||||
},
|
||||
})
|
||||
);
|
||||
window.close();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user