diff --git a/apps/sample/src/components/DeviceActionsView/DeviceActionResponse.tsx b/apps/sample/src/components/DeviceActionsView/DeviceActionResponse.tsx index e143bd473..4c30add87 100644 --- a/apps/sample/src/components/DeviceActionsView/DeviceActionResponse.tsx +++ b/apps/sample/src/components/DeviceActionsView/DeviceActionResponse.tsx @@ -7,6 +7,7 @@ import { } from "@ledgerhq/device-management-kit"; import { Flex, Icons, Tag, Text, Tooltip } from "@ledgerhq/react-ui"; import styled from "styled-components"; +import { inspect } from "util"; import { type FieldType } from "@/hooks/useForm"; @@ -91,11 +92,11 @@ export function DeviceActionResponse< wordBreak: "break-word", }} > - {JSON.stringify( - isError ? props.error : props.deviceActionState, - null, - 2, - )} + {isError + ? inspect(props.error, { depth: null }) + : props.deviceActionState.status === DeviceActionStatus.Error + ? inspect(props.deviceActionState.error, { depth: null }) + : JSON.stringify(props.deviceActionState, null, 2)} {!isError && props.deviceActionState.status === DeviceActionStatus.Pending ? ( diff --git a/apps/sample/src/components/DeviceActionsView/DeviceActionTester.tsx b/apps/sample/src/components/DeviceActionsView/DeviceActionTester.tsx index ea78a83d7..f2037a7b1 100644 --- a/apps/sample/src/components/DeviceActionsView/DeviceActionTester.tsx +++ b/apps/sample/src/components/DeviceActionsView/DeviceActionTester.tsx @@ -45,6 +45,12 @@ export type DeviceActionProps< debug?: boolean, ) => ExecuteDeviceActionReturnType; initialValues: Input; + InputValuesComponent?: React.FC<{ + initialValues: Input; + onChange: (values: Input) => void; + valueSelector?: ValueSelector; + disabled?: boolean; + }>; validateValues?: (args: Input) => boolean; valueSelector?: ValueSelector; deviceModelId: DeviceModelId; @@ -94,6 +100,7 @@ export function DeviceActionTester< executeDeviceAction, valueSelector, validateValues, + InputValuesComponent, } = props; const nonce = useRef(-1); @@ -204,12 +211,21 @@ export function DeviceActionTester< rowGap={3} pointerEvents={loading ? "none" : "auto"} > - + {InputValuesComponent ? ( + + ) : ( + + )} = { + [DefaultDescriptorTemplate.TAPROOT]: "86'/0'/0'", + [DefaultDescriptorTemplate.NATIVE_SEGWIT]: "84'/0'/0'", + [DefaultDescriptorTemplate.NESTED_SEGWIT]: "49'/0'/0'", + [DefaultDescriptorTemplate.LEGACY]: "44'/0'/0'", +}; + +const descriptorTemplateToLabel = { + [DefaultDescriptorTemplate.TAPROOT]: "Taproot", + [DefaultDescriptorTemplate.NATIVE_SEGWIT]: "Native Segwit", + [DefaultDescriptorTemplate.NESTED_SEGWIT]: "Nested Segwit", + [DefaultDescriptorTemplate.LEGACY]: "Legacy", +}; + +export const SignPsbtDAInputValuesForm: React.FC<{ + initialValues: SignPsbtInputValuesType; + onChange: (values: SignPsbtInputValuesType) => void; + disabled?: boolean; +}> = ({ initialValues, onChange, disabled }) => { + const { formValues, setFormValues, setFormValue } = useForm(initialValues); + + useEffect(() => { + onChange(formValues); + }, [formValues, onChange]); + + const onWalletDescriptorTemplateChange = useCallback( + (value: DefaultDescriptorTemplate) => { + const newValues = { + path: descriptorTemplateToDerivationPath[value], + descriptorTemplate: value, + }; + setFormValues((prev) => ({ ...prev, ...newValues })); + }, + [setFormValues], + ); + + return ( + + + Wallet address type + ({ + label: descriptorTemplateToLabel[value], + value, + }), + )} + value={{ + label: descriptorTemplateToLabel[formValues.descriptorTemplate], + value: formValues.descriptorTemplate, + }} + isMulti={false} + isSearchable={false} + onChange={(newVal) => + newVal && onWalletDescriptorTemplateChange(newVal.value) + } + /> + + + setFormValue("path", newVal)} + disabled={disabled} + data-testid="input-text_path" + /> + + setFormValue("psbt", newVal)} + disabled={disabled} + data-testid="input-text_psbt" + /> + + ); +}; diff --git a/apps/sample/src/components/SignerBtcView/index.tsx b/apps/sample/src/components/SignerBtcView/index.tsx index 32c94ae0f..26700ddcc 100644 --- a/apps/sample/src/components/SignerBtcView/index.tsx +++ b/apps/sample/src/components/SignerBtcView/index.tsx @@ -16,6 +16,7 @@ import { import { DeviceActionsList } from "@/components/DeviceActionsView/DeviceActionsList"; import { type DeviceActionProps } from "@/components/DeviceActionsView/DeviceActionTester"; +import { SignPsbtDAInputValuesForm } from "@/components/SignerBtcView/SignPsbtDAInputValusForm"; import { useDmk } from "@/providers/DeviceManagementKitProvider"; const DEFAULT_DERIVATION_PATH = "84'/0'/0'"; @@ -87,29 +88,29 @@ export const SignerBtcView: React.FC<{ sessionId: string }> = ({ title: "Sign psbt", description: "Perform all the actions necessary to sign a PSBT with the device", - executeDeviceAction: ({ derivationPath, psbt }) => { + executeDeviceAction: ({ descriptorTemplate, psbt, path }) => { if (!signer) { throw new Error("Signer not initialized"); } return signer.signPsbt( - new DefaultWallet( - derivationPath, - DefaultDescriptorTemplate.NATIVE_SEGWIT, - ), + new DefaultWallet(path, descriptorTemplate), psbt, ); }, + InputValuesComponent: SignPsbtDAInputValuesForm, initialValues: { - derivationPath: DEFAULT_DERIVATION_PATH, + descriptorTemplate: DefaultDescriptorTemplate.NATIVE_SEGWIT, psbt: "", + path: DEFAULT_DERIVATION_PATH, }, deviceModelId, } satisfies DeviceActionProps< SignPsbtDAOutput, { psbt: string; - derivationPath: string; + path: string; + descriptorTemplate: DefaultDescriptorTemplate; }, SignPsbtDAError, SignPsbtDAIntermediateValue diff --git a/apps/sample/src/hooks/useForm.tsx b/apps/sample/src/hooks/useForm.tsx index fcc818c3f..1943a1a91 100644 --- a/apps/sample/src/hooks/useForm.tsx +++ b/apps/sample/src/hooks/useForm.tsx @@ -15,5 +15,6 @@ export function useForm>( return { formValues, setFormValue, + setFormValues, }; } diff --git a/apps/sample/src/styles/globalstyles.tsx b/apps/sample/src/styles/globalstyles.tsx index d7db8e5e7..89341ef5a 100644 --- a/apps/sample/src/styles/globalstyles.tsx +++ b/apps/sample/src/styles/globalstyles.tsx @@ -12,7 +12,7 @@ export const GlobalStyle = createGlobalStyle` background-color: #000000; } body { - user-select: none; + user-select: text; } .no-scrollbar { &::-webkit-scrollbar {