-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ (signer-btc): Create Prepare Wallet Policy task
- Loading branch information
1 parent
633ed6f
commit 811ca20
Showing
5 changed files
with
217 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@ledgerhq/device-signer-kit-bitcoin": minor | ||
--- | ||
|
||
PrepareWalletPolicy task |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
packages/signer/signer-btc/src/internal/app-binder/task/PrepareWalletPolicyTask.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import { | ||
CommandResultFactory, | ||
type InternalApi, | ||
isSuccessCommandResult, | ||
UnknownDeviceExchangeError, | ||
} from "@ledgerhq/device-management-kit"; | ||
|
||
import { | ||
DefaultDescriptorTemplate, | ||
DefaultWallet, | ||
type Wallet, | ||
} from "@api/model/Wallet"; | ||
import { PrepareWalletPolicyTask } from "@internal/app-binder/task/PrepareWalletPolicyTask"; | ||
import { DataStore } from "@internal/data-store/model/DataStore"; | ||
import { type DataStoreService } from "@internal/data-store/service/DataStoreService"; | ||
import { type WalletBuilder } from "@internal/wallet/service/WalletBuilder"; | ||
const fromDefaultWalletMock = jest.fn(); | ||
const merklizeWalletMock = jest.fn(); | ||
|
||
describe("PrepareWalletPolicyTask", () => { | ||
let internalApi: { sendCommand: jest.Mock }; | ||
const walletBuilder = { | ||
fromDefaultWallet: fromDefaultWalletMock, | ||
} as unknown as WalletBuilder; | ||
const dataStoreService = { | ||
merklizeWallet: merklizeWalletMock, | ||
} as unknown as DataStoreService; | ||
beforeEach(() => { | ||
internalApi = { | ||
sendCommand: jest.fn(), | ||
}; | ||
}); | ||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it("should return a filled data store", async () => { | ||
// given | ||
const defaultWallet = new DefaultWallet( | ||
"49'/0'/0'", | ||
DefaultDescriptorTemplate.LEGACY, | ||
); | ||
const task = new PrepareWalletPolicyTask( | ||
internalApi as unknown as InternalApi, | ||
walletBuilder, | ||
dataStoreService, | ||
); | ||
internalApi.sendCommand.mockResolvedValueOnce( | ||
Promise.resolve( | ||
CommandResultFactory({ | ||
data: { | ||
masterFingerprint: Uint8Array.from([0x42, 0x21, 0x12, 0x24]), | ||
}, | ||
}), | ||
), | ||
); | ||
internalApi.sendCommand.mockResolvedValueOnce( | ||
Promise.resolve( | ||
CommandResultFactory({ | ||
data: { | ||
extendedPublicKey: "xPublicKey", | ||
}, | ||
}), | ||
), | ||
); | ||
const wallet = {} as Wallet; | ||
fromDefaultWalletMock.mockReturnValue(wallet); | ||
// when | ||
const result = await task.run(defaultWallet); | ||
// then | ||
if (isSuccessCommandResult(result)) { | ||
expect(fromDefaultWalletMock).toHaveBeenCalledWith( | ||
Uint8Array.from([0x42, 0x21, 0x12, 0x24]), | ||
"xPublicKey", | ||
defaultWallet, | ||
); | ||
expect(merklizeWalletMock).toHaveBeenCalledWith(new DataStore(), wallet); | ||
expect(result.data).toBeInstanceOf(DataStore); | ||
} else { | ||
fail("Expected a success result, but the result was an error"); | ||
} | ||
}); | ||
|
||
it("should return an error if getMasterFingerprint failed", async () => { | ||
// given | ||
const defaultWallet = new DefaultWallet( | ||
"49'/0'/0'", | ||
DefaultDescriptorTemplate.LEGACY, | ||
); | ||
const task = new PrepareWalletPolicyTask( | ||
internalApi as unknown as InternalApi, | ||
walletBuilder, | ||
dataStoreService, | ||
); | ||
const error = new UnknownDeviceExchangeError("Failed"); | ||
internalApi.sendCommand.mockResolvedValueOnce( | ||
Promise.resolve( | ||
CommandResultFactory({ | ||
error, | ||
}), | ||
), | ||
); | ||
// when | ||
const result = await task.run(defaultWallet); | ||
// then | ||
if (isSuccessCommandResult(result) === false) { | ||
expect(result.error).toStrictEqual(error); | ||
} else { | ||
fail("Expected an error, but the result was successful"); | ||
} | ||
}); | ||
|
||
it("should return an error if getExtendedPublicKey failed", async () => { | ||
// given | ||
const defaultWallet = new DefaultWallet( | ||
"49'/0'/0'", | ||
DefaultDescriptorTemplate.LEGACY, | ||
); | ||
const task = new PrepareWalletPolicyTask( | ||
internalApi as unknown as InternalApi, | ||
walletBuilder, | ||
dataStoreService, | ||
); | ||
const error = new UnknownDeviceExchangeError("Failed"); | ||
internalApi.sendCommand.mockResolvedValueOnce( | ||
Promise.resolve( | ||
CommandResultFactory({ | ||
data: { | ||
masterFingerprint: Uint8Array.from([0x42, 0x21, 0x12, 0x24]), | ||
}, | ||
}), | ||
), | ||
); | ||
internalApi.sendCommand.mockResolvedValueOnce( | ||
Promise.resolve( | ||
CommandResultFactory({ | ||
error, | ||
}), | ||
), | ||
); | ||
// when | ||
const result = await task.run(defaultWallet); | ||
// then | ||
if (isSuccessCommandResult(result) === false) { | ||
expect(result.error).toStrictEqual(error); | ||
} else { | ||
fail("Expected an error, but the result was successful"); | ||
} | ||
}); | ||
}); |
55 changes: 55 additions & 0 deletions
55
packages/signer/signer-btc/src/internal/app-binder/task/PrepareWalletPolicyTask.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { | ||
type CommandResult, | ||
CommandResultFactory, | ||
type InternalApi, | ||
isSuccessCommandResult, | ||
} from "@ledgerhq/device-management-kit"; | ||
|
||
import { type DefaultWallet } from "@api/model/Wallet"; | ||
import { GetExtendedPublicKeyCommand } from "@internal/app-binder/command/GetExtendedPublicKeyCommand"; | ||
import { GetMasterFingerprintCommand } from "@internal/app-binder/command/GetMasterFingerprintCommand"; | ||
import { DataStore } from "@internal/data-store/model/DataStore"; | ||
import { type DataStoreService } from "@internal/data-store/service/DataStoreService"; | ||
import { type WalletBuilder } from "@internal/wallet/service/WalletBuilder"; | ||
|
||
export class PrepareWalletPolicyTask { | ||
constructor( | ||
private readonly _api: InternalApi, | ||
private readonly _walletBuilder: WalletBuilder, | ||
private readonly _dataStoreService: DataStoreService, | ||
) {} | ||
|
||
async run(defaultWallet: DefaultWallet): Promise<CommandResult<DataStore>> { | ||
// request master fingerprint | ||
const getMasterFingerPrintResult = await this._api.sendCommand( | ||
new GetMasterFingerprintCommand(), | ||
); | ||
if (!isSuccessCommandResult(getMasterFingerPrintResult)) { | ||
return getMasterFingerPrintResult; | ||
} | ||
|
||
// request extended public key for derivation path | ||
const getExtendedPublicKeyResult = await this._api.sendCommand( | ||
new GetExtendedPublicKeyCommand({ | ||
derivationPath: defaultWallet.derivationPath, | ||
checkOnDevice: false, | ||
}), | ||
); | ||
if (!isSuccessCommandResult(getExtendedPublicKeyResult)) { | ||
return getExtendedPublicKeyResult; | ||
} | ||
// create default wallet with wallet policy service | ||
const wallet = this._walletBuilder.fromDefaultWallet( | ||
getMasterFingerPrintResult.data.masterFingerprint, | ||
getExtendedPublicKeyResult.data.extendedPublicKey, | ||
defaultWallet, | ||
); | ||
// feed the data store | ||
const store = new DataStore(); | ||
this._dataStoreService.merklizeWallet(store, wallet); | ||
|
||
return CommandResultFactory({ | ||
data: store, | ||
}); | ||
} | ||
} |