Skip to content

Commit

Permalink
✨ (signer-btc): Create SignPsbt DA & task & s
Browse files Browse the repository at this point in the history
  • Loading branch information
jdabbech-ledger committed Jan 2, 2025
1 parent 429473a commit 038939d
Show file tree
Hide file tree
Showing 25 changed files with 1,306 additions and 34 deletions.
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
17 changes: 7 additions & 10 deletions packages/signer/signer-btc/src/api/SignerBtc.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
// 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";

export interface SignerBtc {
getExtendedPublicKey: (
derivationPath: string,
options: AddressOptions,
) => GetExtendedPublicKeyReturnType;
) => GetExtendedPublicKeyDAReturnType;
signMessage: (
derivationPath: string,
message: string,
) => SignMessageDAReturnType;
signPsbt: (wallet: Wallet, psbt: Psbt) => SignPsbtDAReturnType;
// getAddress: (wallet: Wallet, options?: AddressOptions) => Promise<string>;
// signPsbt: (wallet: Wallet, psbt: Psbt) => Promise<Psbt>;
// signTransaction: (wallet: Wallet, psbt: Psbt) => Promise<Uint8Array>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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 Signature } from "@api/model/Signature";
import { type Wallet } from "@api/model/Wallet";
import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors";

export type SignPsbtDAOutput = Signature;

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;
readonly signature: Signature | null;
};

export type SignPsbtDAReturnType = ExecuteDeviceActionReturnType<
SignPsbtDAOutput,
SignPsbtDAError,
SignPsbtDAIntermediateValue
>;
5 changes: 3 additions & 2 deletions packages/signer/signer-btc/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export type {
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";
11 changes: 10 additions & 1 deletion packages/signer/signer-btc/src/internal/DefaultSignerBtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import {
} from "@ledgerhq/device-management-kit";
import { type Container } from "inversify";

import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionType";
import { type SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes";
import { type AddressOptions } from "@api/model/AddressOptions";
import { type Psbt } from "@api/model/Psbt";
import { type Wallet } from "@api/model/Wallet";
import { type SignerBtc } from "@api/SignerBtc";
import { useCasesTypes } from "@internal/use-cases/di/useCasesTypes";
import { type GetExtendedPublicKeyUseCase } from "@internal/use-cases/get-extended-public-key/GetExtendedPublicKeyUseCase";
import { type SignPsbtUseCase } from "@internal/use-cases/sign-psbt/SignPsbtUseCase";

import { type SignMessageUseCase } from "./use-cases/sign-message/SignMessageUseCase";
import { makeContainer } from "./di";
Expand All @@ -25,6 +28,12 @@ export class DefaultSignerBtc implements SignerBtc {
this._container = makeContainer({ dmk, sessionId });
}

signPsbt(wallet: Wallet, psbt: Psbt) {
return this._container
.get<SignPsbtUseCase>(useCasesTypes.SignPsbtUseCase)
.execute(wallet, psbt);
}

getExtendedPublicKey(
derivationPath: string,
{ checkOnDevice = false }: AddressOptions,
Expand Down
22 changes: 19 additions & 3 deletions packages/signer/signer-btc/src/internal/app-binder/BtcAppBinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import { inject, injectable } from "inversify";

import {
GetExtendedPublicKeyDAInput,
GetExtendedPublicKeyReturnType,
GetExtendedPublicKeyDAReturnType,
} from "@api/app-binder/GetExtendedPublicKeyDeviceActionTypes";
import { SignMessageDAReturnType } from "@api/index";
import { SignMessageDAReturnType } from "@api/app-binder/SignMessageDeviceActionTypes";
import { SignPsbtDAReturnType } from "@api/app-binder/SignPsbtDeviceActionTypes";
import { Psbt } from "@api/model/Psbt";
import { Wallet } from "@api/model/Wallet";
import { GetExtendedPublicKeyCommand } from "@internal/app-binder/command/GetExtendedPublicKeyCommand";
import { SignPsbtDeviceAction } from "@internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction";
import { externalTypes } from "@internal/externalTypes";

import { SignMessageDeviceAction } from "./device-action/SignMessage/SignMessageDeviceAction";
Expand All @@ -25,7 +29,7 @@ export class BtcAppBinder {

getExtendedPublicKey(
args: GetExtendedPublicKeyDAInput,
): GetExtendedPublicKeyReturnType {
): GetExtendedPublicKeyDAReturnType {
return this.dmk.executeDeviceAction({
sessionId: this.sessionId,
deviceAction: new SendCommandInAppDeviceAction({
Expand Down Expand Up @@ -54,4 +58,16 @@ export class BtcAppBinder {
}),
});
}

signPsbt(args: { psbt: Psbt; wallet: Wallet }): SignPsbtDAReturnType {
return this.dmk.executeDeviceAction({
sessionId: this.sessionId,
deviceAction: new SignPsbtDeviceAction({
input: {
psbt: args.psbt,
wallet: args.wallet,
},
}),
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ const SIGN_PSBT_APDU = Uint8Array.from([
describe("SignPsbtCommand", () => {
const args: SignPsbtCommandArgs = {
globalCommitments: GLOBAL_COMMITMENTS,
inputsCount: 0,
inputsCommitments: INPUTS_COMMITMENTS,
outputsCount: 0,
outputsCommitments: OUTPUTS_COMMITMENTS,
walletId: WALLET_ID,
walletHmac: WALLET_HMAC,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { BtcCommandUtils } from "@internal/utils/BtcCommandUtils";

export type SignPsbtCommandArgs = {
globalCommitments: Uint8Array;
inputsCount: number;
inputsCommitments: Uint8Array;
outputsCount: number;
outputsCommitments: Uint8Array;
walletId: Uint8Array;
walletHmac: Uint8Array;
Expand All @@ -44,6 +46,7 @@ export class SignPsbtCommand
) {}

getApdu(): Apdu {
console.log("sign psbt command args", this._args);
const builder = new ApduBuilder({
cla: 0xe1,
ins: 0x04,
Expand All @@ -52,15 +55,19 @@ export class SignPsbtCommand
});
const {
globalCommitments,
inputsCount,
inputsCommitments,
outputsCount,
outputsCommitments,
walletHmac,
walletId,
} = this._args;

return builder
.addBufferToData(globalCommitments)
.add8BitUIntToData(inputsCount)
.addBufferToData(inputsCommitments)
.add8BitUIntToData(outputsCount)
.addBufferToData(outputsCommitments)
.addBufferToData(walletId)
.addBufferToData(walletHmac)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe("BtcAppCommandError", () => {
});

it("should set the correct customErrorCode", () => {
const errorCode: BtcErrorCodes = "6A86";
const errorCode: BtcErrorCodes = "6a86";
const error = new BtcAppCommandError({
message: "Either P1 or P2 is incorrect",
errorCode,
Expand All @@ -45,7 +45,7 @@ describe("BtcAppCommandError", () => {
});

it("should correlate error codes with messages from bitcoinAppErrors", () => {
const errorCode: BtcErrorCodes = "6E00";
const errorCode: BtcErrorCodes = "6e00";
const expectedMessage = BTC_APP_ERRORS[errorCode].message;

const error = new BtcAppCommandError({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@ import {
} from "@ledgerhq/device-management-kit";

export type BtcErrorCodes =
| "6a80"
| "6a82"
| "6985"
| "6A86"
| "6A87"
| "6D00"
| "6E00"
| "B000"
| "B007"
| "B008";
| "6a86"
| "6a87"
| "6d00"
| "6e00"
| "b000"
| "b007"
| "b008";

export const BTC_APP_ERRORS: CommandErrors<BtcErrorCodes> = {
"6a80": { message: "Incorrect data" },
"6a82": { message: "Request not supported" },
"6985": { message: "Rejected by user" },
"6A86": { message: "Either P1 or P2 is incorrect" },
"6A87": { message: "Lc or minimum APDU length is incorrect" },
"6D00": { message: "No command exists with the provided INS" },
"6E00": { message: "Bad CLA used for this application" },
B000: { message: "Wrong response length (buffer size problem)" },
B007: { message: "Aborted due to unexpected state reached" },
B008: { message: "Invalid signature or HMAC" },
"6a86": { message: "Either P1 or P2 is incorrect" },
"6a87": { message: "Lc or minimum APDU length is incorrect" },
"6d00": { message: "No command exists with the provided INS" },
"6e00": { message: "Bad CLA used for this application" },
b000: { message: "Wrong response length (buffer size problem)" },
b007: { message: "Aborted due to unexpected state reached" },
b008: { message: "Invalid signature or HMAC" },
};

export class BtcAppCommandError extends DeviceExchangeError<BtcErrorCodes> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const PROTOCOL_VERSION = 1;
export const PROTOCOL_VERSION = 0;

export const SHA256_SIZE = 32;

Expand Down
Loading

0 comments on commit 038939d

Please sign in to comment.