Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ (signer-btc) [DSDK-485]: Implement getWalletAddress device action #597

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/blue-lemons-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-management-kit": patch
---

Fix CommandUtils static calls
5 changes: 5 additions & 0 deletions .changeset/breezy-plums-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/signer-utils": patch
---

Create CommandErrorHelper to handle command errors
5 changes: 5 additions & 0 deletions .changeset/fuzzy-eagles-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-signer-kit-bitcoin": minor
---

Implement get wallet device action and sample app getWalletAddress
5 changes: 5 additions & 0 deletions .changeset/happy-zoos-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-management-kit": minor
---

Implement getWalletAddress task
5 changes: 5 additions & 0 deletions .changeset/nervous-points-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-signer-kit-bitcoin": minor
---

Create SignPsbt API
5 changes: 5 additions & 0 deletions .changeset/odd-spies-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-management-kit": patch
---

Expose CommandSuccessResult
5 changes: 5 additions & 0 deletions .changeset/young-horses-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ledgerhq/device-signer-kit-bitcoin": patch
---

Use CommandErrorHelper in BTC commands
2 changes: 1 addition & 1 deletion apps/sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"@ledgerhq/device-management-kit": "workspace:*",
"@ledgerhq/device-management-kit-flipper-plugin-client": "workspace:*",
"@ledgerhq/device-mockserver-client": "workspace:*",
"@ledgerhq/device-signer-kit-bitcoin": "workspace:*",
"@ledgerhq/device-signer-kit-ethereum": "workspace:*",
"@ledgerhq/device-signer-kit-solana": "workspace:*",
"@ledgerhq/device-signer-kit-bitcoin": "workspace:*",
"@ledgerhq/device-transport-kit-mockserver": "workspace:*",
"@ledgerhq/device-transport-kit-web-ble": "workspace:*",
"@ledgerhq/device-transport-kit-web-hid": "workspace:*",
Expand Down
80 changes: 80 additions & 0 deletions apps/sample/src/components/SignerBtcView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import React, { useMemo } from "react";
import {
DefaultDescriptorTemplate,
DefaultWallet,
type GetExtendedDAIntermediateValue,
type GetExtendedPublicKeyDAError,
type GetExtendedPublicKeyDAOutput,
type GetWalletAddressDAError,
type GetWalletAddressDAIntermediateValue,
type GetWalletAddressDAOutput,
SignerBtcBuilder,
type SignMessageDAError,
type SignMessageDAIntermediateValue,
type SignMessageDAOutput,
type SignPsbtDAError,
type SignPsbtDAIntermediateValue,
type SignPsbtDAOutput,
} from "@ledgerhq/device-signer-kit-bitcoin";

import { DeviceActionsList } from "@/components/DeviceActionsView/DeviceActionsList";
Expand Down Expand Up @@ -78,6 +86,78 @@ export const SignerBtcView: React.FC<{ sessionId: string }> = ({
SignMessageDAError,
SignMessageDAIntermediateValue
>,
{
title: "Sign psbt",
description:
"Perform all the actions necessary to sign a PSBT with the device",
executeDeviceAction: ({ derivationPath, psbt }) => {
if (!signer) {
throw new Error("Signer not initialized");
}

return signer.signPsbt(
new DefaultWallet(
derivationPath,
DefaultDescriptorTemplate.NATIVE_SEGWIT,
),
psbt,
);
},
initialValues: {
derivationPath: DEFAULT_DERIVATION_PATH,
psbt: "70736274ff0104010101fb0402000000010204020000000105010100011004000000000103040100000001007102000000013daeeb9a92e7b5af90c787d53f0e60d2cf4cfd47bca9a0d8bc77a7464b024c0b00000000000000000002ff0300000000000016001402fe597c6ec0e2982712929bcf079a4e11d37e8d950b0000000000001600144dc432cb6a26c52a1e6ddd2bcf0ee49199fae0cc000000002206031869567d5e88d988ff7baf6827983f89530ddd79dbaeadaa6ec538a8f03dea8b18f5acc2fd540000800000008000000080000000000000000001011fff0300000000000016001402fe597c6ec0e2982712929bcf079a4e11d37e8d010e200cf08d04fa11ff024d5a50165ba65e495409b50ba6657788dfa15274adb682df010f0400000000000103086b01000000000000010416001429159115f12bb6a7e977439c83d3f8d555d72d5f00",
},
deviceModelId,
} satisfies DeviceActionProps<
SignPsbtDAOutput,
{
psbt: string;
derivationPath: string;
},
SignPsbtDAError,
SignPsbtDAIntermediateValue
>,
{
title: "Get wallet address",
description:
"Perform all the actions necessary to get the device's Bitcoin wallet address",
executeDeviceAction: ({
checkOnDevice,
change,
addressIndex,
derivationPath,
}) => {
if (!signer) {
throw new Error("Signer not initialized");
}

return signer.getWalletAddress(
new DefaultWallet(
derivationPath,
DefaultDescriptorTemplate.NATIVE_SEGWIT,
),
addressIndex,
{ checkOnDevice, change },
);
},
initialValues: {
checkOnDevice: false,
change: false,
derivationPath: DEFAULT_DERIVATION_PATH,
addressIndex: 0,
},
deviceModelId,
} satisfies DeviceActionProps<
GetWalletAddressDAOutput,
{
checkOnDevice: boolean;
change: boolean;
addressIndex: number;
derivationPath: string;
},
GetWalletAddressDAError,
GetWalletAddressDAIntermediateValue
>,
],
[deviceModelId, signer],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export enum CommandResultStatus {
Error = "ERROR",
Success = "SUCCESS",
}
type CommandSuccessResult<Data> = {
export type CommandSuccessResult<Data> = {
status: CommandResultStatus.Success;
data: Data;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export class CommandUtils {
}

static isSuccessResponse({ statusCode }: ApduResponse) {
if (!this.isValidStatusCode(statusCode)) {
if (!CommandUtils.isValidStatusCode(statusCode)) {
return false;
}

return statusCode[0] === 0x90 && statusCode[1] === 0x00;
}

static isLockedDeviceResponse({ statusCode }: ApduResponse) {
if (!this.isValidStatusCode(statusCode)) {
if (!CommandUtils.isValidStatusCode(statusCode)) {
return false;
}

Expand Down
1 change: 1 addition & 0 deletions packages/device-management-kit/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type { Command } from "@api/command/Command";
export type {
CommandErrorResult,
CommandResult,
CommandSuccessResult,
} from "@api/command/model/CommandResult";
export type { SendCommandUseCaseArgs } from "@api/command/use-case/SendCommandUseCase";
export type { DeviceModelId } from "@api/device/DeviceModel";
Expand Down
26 changes: 15 additions & 11 deletions packages/signer/signer-btc/src/api/SignerBtc.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
// import { type AddressOptions } from "@api/model/AddressOptions";
// import { type Psbt } from "@api/model/Psbt";
// import { type Signature } from "@api/model/Signature";
// import { type Wallet } from "@api/model/Wallet";
import { type GetExtendedPublicKeyDAReturnType } from "@api/app-binder/GetExtendedPublicKeyDeviceActionTypes";
import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes";
import { type SignPsbtDAReturnType } from "@api/app-binder/SignPsbtDeviceActionTypes";
import { type AddressOptions } from "@api/model/AddressOptions";
import {
type GetExtendedPublicKeyReturnType,
type SignMessageDAReturnType,
} from "@root/src";
import { type Psbt } from "@api/model/Psbt";
import { type Wallet } from "@api/model/Wallet";

import { type GetWalletAddressDAReturnType } from "./app-binder/GetWalletAddressDeviceActionTypes";
import { WalletAddressOptions } from "./model/WalletAddressOptions";

export interface SignerBtc {
getExtendedPublicKey: (
derivationPath: string,
options: AddressOptions,
) => GetExtendedPublicKeyReturnType;
) => GetExtendedPublicKeyDAReturnType;
signMessage: (
derivationPath: string,
message: string,
) => SignMessageDAReturnType;
// getAddress: (wallet: Wallet, options?: AddressOptions) => Promise<string>;
// signPsbt: (wallet: Wallet, psbt: Psbt) => Promise<Psbt>;
signPsbt: (wallet: Wallet, psbt: Psbt) => SignPsbtDAReturnType;
getWalletAddress: (
wallet: Wallet,
addressIndex: number,
options: WalletAddressOptions,
) => GetWalletAddressDAReturnType;
// signTransaction: (wallet: Wallet, psbt: Psbt) => Promise<Uint8Array>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
type GetExtendedPublicKeyCommandArgs,
type GetExtendedPublicKeyCommandResponse,
} from "@internal/app-binder/command/GetExtendedPublicKeyCommand";
import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors";

type GetExtendedPublicKeyDARequiredInteraction =
| UserInteractionRequired.None
Expand All @@ -18,14 +19,15 @@ type GetExtendedPublicKeyDARequiredInteraction =
export type GetExtendedPublicKeyDAOutput =
SendCommandInAppDAOutput<GetExtendedPublicKeyCommandResponse>;

export type GetExtendedPublicKeyDAError = SendCommandInAppDAError;
export type GetExtendedPublicKeyDAError =
SendCommandInAppDAError<BtcErrorCodes>;

export type GetExtendedDAIntermediateValue =
SendCommandInAppDAIntermediateValue<GetExtendedPublicKeyDARequiredInteraction>;

export type GetExtendedPublicKeyDAInput = GetExtendedPublicKeyCommandArgs;

export type GetExtendedPublicKeyReturnType = ExecuteDeviceActionReturnType<
export type GetExtendedPublicKeyDAReturnType = ExecuteDeviceActionReturnType<
GetExtendedPublicKeyDAOutput,
GetExtendedPublicKeyDAError,
GetExtendedDAIntermediateValue
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
type CommandErrorResult,
type DeviceActionState,
type ExecuteDeviceActionReturnType,
type OpenAppDAError,
type OpenAppDARequiredInteraction,
} from "@ledgerhq/device-management-kit";

import { type WalletAddress } from "@api/model/Wallet";
import { type Wallet as ApiWallet } from "@api/model/Wallet";
import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors";

export type GetWalletAddressDAOutput = WalletAddress;

export type GetWalletAddressDAInput = {
checkOnDevice: boolean;
wallet: ApiWallet;
change: boolean;
addressIndex: number;
};

export type GetWalletAddressDAError =
| OpenAppDAError
| CommandErrorResult<BtcErrorCodes>["error"];

type GetWalletAddressDARequiredInteraction = OpenAppDARequiredInteraction;

export type GetWalletAddressDAIntermediateValue = {
requiredUserInteraction: GetWalletAddressDARequiredInteraction;
};

export type GetWalletAddressDAState = DeviceActionState<
GetWalletAddressDAOutput,
GetWalletAddressDAError,
GetWalletAddressDAIntermediateValue
>;

export type GetWalletAddressDAInternalState = {
readonly error: GetWalletAddressDAError | null;
readonly walletAddress: WalletAddress | null;
};

export type GetWalletAddressDAReturnType = ExecuteDeviceActionReturnType<
GetWalletAddressDAOutput,
GetWalletAddressDAError,
GetWalletAddressDAIntermediateValue
>;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@ledgerhq/device-management-kit";

import { type Signature } from "@api/model/Signature";
import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors";

export type SignMessageDAOutput = Signature;

Expand All @@ -16,7 +17,9 @@ export type SignMessageDAInput = {
readonly message: string;
};

export type SignMessageDAError = OpenAppDAError | CommandErrorResult["error"];
export type SignMessageDAError =
| OpenAppDAError
| CommandErrorResult<BtcErrorCodes>["error"];

type SignMessageDARequiredInteraction =
| OpenAppDARequiredInteraction
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
type CommandErrorResult,
type DeviceActionState,
type ExecuteDeviceActionReturnType,
type OpenAppDAError,
type OpenAppDARequiredInteraction,
} from "@ledgerhq/device-management-kit";

import { type Psbt } from "@api/model/Psbt";
import { type Wallet } from "@api/model/Wallet";
import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors";

// @toDo Update this return value to Psbt once it would be updated in SignPsbtTask
export type SignPsbtDAOutput = Uint8Array[];

export type SignPsbtDAInput = {
psbt: Psbt;
wallet: Wallet;
};

export type SignPsbtDAError =
| OpenAppDAError
| CommandErrorResult<BtcErrorCodes>["error"];

type SignPsbtDARequiredInteraction = OpenAppDARequiredInteraction;

export type SignPsbtDAIntermediateValue = {
requiredUserInteraction: SignPsbtDARequiredInteraction;
};

export type SignPsbtDAState = DeviceActionState<
SignPsbtDAOutput,
SignPsbtDAError,
SignPsbtDAIntermediateValue
>;

export type SignPsbtDAInternalState = {
readonly error: SignPsbtDAError | null;
// [SHOULD] be psbt instead of signature
readonly signature: Uint8Array[] | null;
};

export type SignPsbtDAReturnType = ExecuteDeviceActionReturnType<
SignPsbtDAOutput,
SignPsbtDAError,
SignPsbtDAIntermediateValue
>;
6 changes: 4 additions & 2 deletions packages/signer/signer-btc/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export { type SignerBtc } from "./SignerBtc";
export { SignerBtcBuilder } from "./SignerBtcBuilder";
export * from "@api/app-binder/GetExtendedPublicKeyDeviceActionTypes";
export * from "@api/app-binder/GetWalletAddressDeviceActionTypes";
export type {
SignMessageDAError,
SignMessageDAInput,
SignMessageDAIntermediateValue,
SignMessageDAOutput,
SignMessageDAState,
} from "@api/app-binder/SignMessageDeviceActionType";
export * from "@api/app-binder/SignMessageDeviceActionType";
} from "@api/app-binder/SignMessageDeviceActionTypes";
export * from "@api/app-binder/SignPsbtDeviceActionTypes";
export { DefaultDescriptorTemplate, DefaultWallet } from "@api/model/Wallet";
export * from "@api/SignerBtc";
export * from "@api/SignerBtcBuilder";
4 changes: 4 additions & 0 deletions packages/signer/signer-btc/src/api/model/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ export class WalletPolicy {
}

export type Wallet = DefaultWallet | RegisteredWallet;

export type WalletAddress = {
address: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type WalletAddressOptions = {
checkOnDevice?: boolean;
change?: boolean;
};
Loading