From 0663f38e20ec03e76beb0965c4df2e7ded9cab2b Mon Sep 17 00:00:00 2001 From: jdabbech-ledger Date: Wed, 8 Jan 2025 16:26:15 +0100 Subject: [PATCH] :sparkles: (signer-btc): Get PSBT signature --- .../app-binder/SignPsbtDeviceActionTypes.ts | 7 +++--- .../SignPsbt/SignPsbtDeviceAction.test.ts | 12 ++-------- .../SignPsbt/SignPsbtDeviceAction.ts | 5 ++-- .../app-binder/task/ContinueTask.test.ts | 9 ++++--- .../internal/app-binder/task/ContinueTask.ts | 24 ++++++++++--------- .../app-binder/task/SignMessageTask.ts | 3 +-- .../app-binder/task/SignPsbtTask.test.ts | 1 + .../internal/app-binder/task/SignPsbtTask.ts | 13 ++++++---- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/packages/signer/signer-btc/src/api/app-binder/SignPsbtDeviceActionTypes.ts b/packages/signer/signer-btc/src/api/app-binder/SignPsbtDeviceActionTypes.ts index 8c928a3ac..2d7bdf573 100644 --- a/packages/signer/signer-btc/src/api/app-binder/SignPsbtDeviceActionTypes.ts +++ b/packages/signer/signer-btc/src/api/app-binder/SignPsbtDeviceActionTypes.ts @@ -7,11 +7,11 @@ import { } 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; +// @toDo Update this return value to Psbt once it would be updated in SignPsbtTask +export type SignPsbtDAOutput = Uint8Array[]; export type SignPsbtDAInput = { psbt: Psbt; @@ -36,7 +36,8 @@ export type SignPsbtDAState = DeviceActionState< export type SignPsbtDAInternalState = { readonly error: SignPsbtDAError | null; - readonly signature: Signature | null; + // [SHOULD] be psbt instead of signature + readonly signature: Uint8Array[] | null; }; export type SignPsbtDAReturnType = ExecuteDeviceActionReturnType< diff --git a/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.test.ts b/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.test.ts index d199d99a5..3e97da352 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.test.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.test.ts @@ -56,11 +56,7 @@ describe("SignPsbtDeviceAction", () => { .mockReturnValue(extractDependenciesMock()); signPersonalPsbtMock.mockResolvedValueOnce( CommandResultFactory({ - data: { - v: 0x1c, - r: "0x8a540510e13b0f2b11a451275716d29e08caad07e89a1c84964782fb5e1ad788", - s: "0x64a0de235b270fbe81e8e40688f4a9f9ad9d283d690552c9331d7773ceafa513", - }, + data: [Uint8Array.from([0x01, 0x02, 0x03])], }), ); @@ -86,11 +82,7 @@ describe("SignPsbtDeviceAction", () => { status: DeviceActionStatus.Pending, }, { - output: { - v: 0x1c, - r: "0x8a540510e13b0f2b11a451275716d29e08caad07e89a1c84964782fb5e1ad788", - s: "0x64a0de235b270fbe81e8e40688f4a9f9ad9d283d690552c9331d7773ceafa513", - }, + output: [Uint8Array.from([0x01, 0x02, 0x03])], status: DeviceActionStatus.Completed, }, ]; diff --git a/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.ts b/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.ts index 39d929c15..4f32cc61a 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/device-action/SignPsbt/SignPsbtDeviceAction.ts @@ -20,7 +20,6 @@ import { type SignPsbtDAOutput, } from "@api/app-binder/SignPsbtDeviceActionTypes"; import { type Psbt } from "@api/model/Psbt"; -import { type Signature } from "@api/model/Signature"; import { type Wallet as ApiWallet } from "@api/model/Wallet"; import { type BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors"; import { SignPsbtTask } from "@internal/app-binder/task/SignPsbtTask"; @@ -28,7 +27,7 @@ import { SignPsbtTask } from "@internal/app-binder/task/SignPsbtTask"; export type MachineDependencies = { readonly signPsbt: (arg0: { input: { wallet: ApiWallet; psbt: Psbt }; - }) => Promise>; + }) => Promise>; }; export type ExtractMachineDependencies = ( @@ -206,7 +205,7 @@ export class SignPsbtDeviceAction extends XStateDeviceAction< extractDependencies(internalApi: InternalApi): MachineDependencies { const signPsbt = async (arg0: { input: { wallet: ApiWallet; psbt: Psbt }; - }): Promise> => { + }): Promise> => { return await new SignPsbtTask(internalApi, arg0.input).run(); }; return { diff --git a/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.test.ts b/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.test.ts index c382515f4..9e9f70a5a 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.test.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.test.ts @@ -55,9 +55,10 @@ describe("ContinueTask", () => { // when const task = new ContinueTask( api as unknown as InternalApi, + {} as DataStore, clientCommandInterpreter, ); - await task.run({} as DataStore, fromResult); + await task.run(fromResult); // then expect( clientCommandInterpreter.getClientCommandPayload, @@ -79,9 +80,10 @@ describe("ContinueTask", () => { // when const task = new ContinueTask( api as unknown as InternalApi, + {} as DataStore, clientCommandInterpreter, ); - const result = await task.run({} as DataStore, fromResult); + const result = await task.run(fromResult); // then expect(api.sendCommand).toHaveBeenCalledTimes(0); expect(result).toStrictEqual( @@ -101,9 +103,10 @@ describe("ContinueTask", () => { // when const task = new ContinueTask( api as unknown as InternalApi, + {} as DataStore, clientCommandInterpreter, ); - const result = await task.run({} as DataStore, fromResult); + const result = await task.run(fromResult); // then expect( clientCommandInterpreter.getClientCommandPayload, diff --git a/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.ts b/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.ts index f5034af9c..a155a86e6 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/task/ContinueTask.ts @@ -20,36 +20,33 @@ import { BtcCommandUtils } from "@internal/utils/BtcCommandUtils"; export class ContinueTask { private readonly _clientCommandInterpreter: ClientCommandInterpreter; + private readonly _context: ClientCommandContext; constructor( private readonly _api: InternalApi, + dataStore: DataStore, clientCommandInterpreter?: ClientCommandInterpreter, ) { + this._context = { + dataStore, + queue: [], + yieldedResults: [], + }; this._clientCommandInterpreter = clientCommandInterpreter || new ClientCommandInterpreter(); } async run( - dataStore: DataStore, fromResult: CommandResult, ): Promise> { let currentResponse: CommandResult = fromResult; - const commandHandlersContext: ClientCommandContext = { - dataStore, - queue: [], - yieldedResults: [], - }; - while ( this.isApduResult(currentResponse) && BtcCommandUtils.isContinueResponse(currentResponse.data) ) { currentResponse = await this._clientCommandInterpreter - .getClientCommandPayload( - currentResponse.data.data, - commandHandlersContext, - ) + .getClientCommandPayload(currentResponse.data.data, this._context) .caseOf({ Left: (error) => Promise.resolve( @@ -67,6 +64,11 @@ export class ContinueTask { } return currentResponse; } + + getYieldedResults() { + return this._context.yieldedResults; + } + private isApduResult = ( response: CommandResult, ): response is CommandSuccessResult => { diff --git a/packages/signer/signer-btc/src/internal/app-binder/task/SignMessageTask.ts b/packages/signer/signer-btc/src/internal/app-binder/task/SignMessageTask.ts index 2e07f1a04..8199db8fe 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/task/SignMessageTask.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/task/SignMessageTask.ts @@ -66,8 +66,7 @@ export class SendSignMessageTask { messageMerkleRoot: merkleRoot, }), ); - const response = await new ContinueTask(this.api).run( - dataStore, + const response = await new ContinueTask(this.api, dataStore).run( signMessageFirstCommandResponse, ); if (isSuccessCommandResult(response)) { diff --git a/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.test.ts b/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.test.ts index aea873220..35f23b895 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.test.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.test.ts @@ -32,6 +32,7 @@ jest.mock("@internal/app-binder/task/BuildPsbtTask", () => ({ jest.mock("@internal/app-binder/task/ContinueTask", () => ({ ContinueTask: jest.fn().mockImplementation(() => ({ run: mockRunContinue, + getYieldedResults: jest.fn(() => []), })), })); jest.mock("@internal/app-binder/task/PrepareWalletPolicyTask", () => ({ diff --git a/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.ts b/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.ts index 17c75bc6a..7e652eeee 100644 --- a/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.ts +++ b/packages/signer/signer-btc/src/internal/app-binder/task/SignPsbtTask.ts @@ -1,4 +1,6 @@ import { + CommandResult, + CommandResultFactory, type InternalApi, isSuccessCommandResult, } from "@ledgerhq/device-management-kit"; @@ -7,13 +9,13 @@ import { injectable } from "inversify"; import { Psbt } from "@api/model/Psbt"; import { Wallet as ApiWallet } from "@api/model/Wallet"; import { SignPsbtCommand } from "@internal/app-binder/command/SignPsbtCommand"; +import { BtcErrorCodes } from "@internal/app-binder/command/utils/bitcoinAppErrors"; import { BuildPsbtTask } from "@internal/app-binder/task/BuildPsbtTask"; import { ContinueTask } from "@internal/app-binder/task/ContinueTask"; import { PrepareWalletPolicyTask } from "@internal/app-binder/task/PrepareWalletPolicyTask"; import { DataStore } from "@internal/data-store/model/DataStore"; import { PsbtCommitment } from "@internal/data-store/service/DataStoreService"; import { Sha256HasherService } from "@internal/merkle-tree/service/Sha256HasherService"; -import { BtcCommandUtils } from "@internal/utils/BtcCommandUtils"; import { Wallet as InternalWallet } from "@internal/wallet/model/Wallet"; import { DefaultWalletSerializer } from "@internal/wallet/service/DefaultWalletSerializer"; import type { WalletSerializer } from "@internal/wallet/service/WalletSerializer"; @@ -51,7 +53,7 @@ export class SignPsbtTask { inputsCount: number, outputsCount: number, wallet: InternalWallet, - ) { + ): Promise> { const signPsbtCommandResult = await this._api.sendCommand( new SignPsbtCommand({ globalCommitments: psbtCommitment.globalCommitment, @@ -64,11 +66,12 @@ export class SignPsbtTask { }), ); - const continueTask = new ContinueTask(this._api); - const result = await continueTask.run(dataStore, signPsbtCommandResult); + const continueTask = new ContinueTask(this._api, dataStore); + const result = await continueTask.run(signPsbtCommandResult); if (isSuccessCommandResult(result)) { - return BtcCommandUtils.getSignature(result); + const signatureList = continueTask.getYieldedResults(); + return CommandResultFactory({ data: signatureList }); } return result; }