Skip to content

Commit

Permalink
feat: add bitcoin.getAddress and bitcoin.getPublicKey [LIVE-14300] (#393
Browse files Browse the repository at this point in the history
)

* feat: add bitcoin.getAddress and bitcoin.getPublicKey [LIVE-14300]

* chore: update workflows
  • Loading branch information
Justkant authored Oct 8, 2024
1 parent da96450 commit 9261475
Show file tree
Hide file tree
Showing 24 changed files with 7,097 additions and 5,097 deletions.
9 changes: 9 additions & 0 deletions .changeset/heavy-pandas-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@ledgerhq/wallet-api-tools": minor
"@ledgerhq/wallet-api-simulator": minor
"@ledgerhq/wallet-api-client": minor
"@ledgerhq/wallet-api-server": minor
"@ledgerhq/wallet-api-core": minor
---

feat: add bitcoin.getAddress and bitcoin.getPublicKey
4 changes: 2 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
with:
version: 8
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 20
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 20
Expand Down
2 changes: 2 additions & 0 deletions apps/wallet-api-tools/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"transaction.signAndBroadcast",
"storage.set",
"storage.get",
"bitcoin.getAddress",
"bitcoin.getPublicKey",
"bitcoin.getXPub",
"wallet.capabilities",
"wallet.userId",
Expand Down
32 changes: 31 additions & 1 deletion apps/wallet-api-tools/src/CommandSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,36 @@ const data: Group[] = [
},
],
},
{
name: "bitcoin",
options: [
{
label: "getAddress",
value: {
method: "bitcoin.getAddress",
params: {
accountId: "",
derivationPath: "",
},
},
},
],
},
{
name: "bitcoin",
options: [
{
label: "getPublicKey",
value: {
method: "bitcoin.getPublicKey",
params: {
accountId: "",
derivationPath: "",
},
},
},
],
},
{
name: "bitcoin",
options: [
Expand Down Expand Up @@ -313,7 +343,7 @@ export function CommandSelector({ onSelectCommand }: CommandSelectorProps) {
<DropdownMenu.Trigger asChild>
<button
aria-label="Customise options"
className="py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
className="rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
>
Commands
</button>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"node": ">=16",
"pnpm": ">=7"
},
"packageManager": "pnpm@8.15.3",
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4",
"dependencies": {
"@tsconfig/recommended": "^1.0.3"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/TransportWalletAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class TransportWalletAPI extends Transport {
* Exchange with the device using APDU protocol.
* @param apdu
* @returns a promise of apdu response
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
override async exchange(apdu: Buffer): Promise<Buffer> {
const apduHex = apdu.toString("hex");
Expand All @@ -78,7 +78,7 @@ export class TransportWalletAPI extends Transport {
/**
* Close the current transport communication.
*
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
override async close(): Promise<void> {
const deviceCloseResult = await this.walletApi.request("device.close", {
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/modules/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class AccountModule {
* @param params - Filters for currencies
*
* @returns The list of accounts on the connected wallet
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
async list(params?: {
/**
Expand All @@ -43,7 +43,7 @@ export class AccountModule {
* @param params - Parameters of the request.
*
* @returns The account selected by the user
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
async request(params?: {
/**
Expand Down
58 changes: 56 additions & 2 deletions packages/client/src/modules/Bitcoin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { schemaBitcoinGetXPub } from "@ledgerhq/wallet-api-core";
import {
schemaBitcoinGetAddress,
schemaBitcoinGetPublicKey,
schemaBitcoinGetXPub,
} from "@ledgerhq/wallet-api-core";
import type { WalletAPIClient } from "../WalletAPIClient";

export class BitcoinModule {
Expand All @@ -8,12 +12,62 @@ export class BitcoinModule {
this.client = client;
}

/**
*
* @param accountId id of the bitcoin account
* @param derivationPath The derivation path is a relative derivation path from the account
* e.g to get the first public address of an account, one will request for the “0/0“ derivation path
* @returns the address of the account for a given derivation path
*
* @throws {@link ServerError} if an error occurred on server side
*/
async getAddress(
accountId: string,
derivationPath?: string,
): Promise<string> {
const getAddressResult = await this.client.request("bitcoin.getAddress", {
accountId,
derivationPath,
});

const safeResults = schemaBitcoinGetAddress.result.parse(getAddressResult);

return safeResults.address;
}

/**
*
* @param accountId id of the bitcoin account
* @param derivationPath The derivation path is a relative derivation path from the account
* e.g to get the first public key of an account, one will request for the “0/0“ derivation path
* @returns a raw hexadecimal public key of a bitcoin account at the given derivation path
*
* @throws {@link ServerError} if an error occurred on server side
*/
async getPublicKey(
accountId: string,
derivationPath?: string,
): Promise<string> {
const getPublicKeyResult = await this.client.request(
"bitcoin.getPublicKey",
{
accountId,
derivationPath,
},
);

const safeResults =
schemaBitcoinGetPublicKey.result.parse(getPublicKeyResult);

return safeResults.publicKey;
}

/**
*
* @param accountId id of the bitcoin account
* @returns the xpub of the account
*
* @throws {@link ServerError} if an error occured on server side
* @throws {@link ServerError} if an error occurred on server side
*/
async getXPub(accountId: string): Promise<string> {
const getXPupResult = await this.client.request("bitcoin.getXPub", {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/modules/Currency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class CurrencyModule {
* @param params - Filters for currencies
*
* @returns The list of corresponding cryptocurrencies
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*
* @beta Filtering not yet implemented
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/modules/Custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class CustomModule {
* @param data - Data to send
*
* @returns Message signed
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
protected request<D, R>(method: `custom.${string}`, data: D): Promise<R> {
return this.client.request(method, data) as Promise<R>;
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/modules/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class MessageModule {
* @param message - Message the user should sign
*
* @returns Message signed
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
async sign(
accountId: string,
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/modules/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class TransactionModule {
* @param options - Extra parameters
*
* @returns The raw signed transaction
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
async sign(
accountId: string,
Expand Down Expand Up @@ -54,7 +54,7 @@ export class TransactionModule {
* @param options - Extra parameters
*
* @returns The transaction hash
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*/
async signAndBroadcast(
accountId: string,
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/modules/Wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class WalletModule {
*
* @returns the userId
*
* @throws {@link ServerError} if an error occured on server side
* @throws {@link ServerError} if an error occurred on server side
*/
async userId(): Promise<string> {
const userIdResult = await this.client.request("wallet.userId", {});
Expand All @@ -31,7 +31,7 @@ export class WalletModule {
*
* @returns The wallet infos
*
* @throws {@link ServerError} if an error occured on server side
* @throws {@link ServerError} if an error occurred on server side
*/
async info(): Promise<WalletInfo["result"]> {
const infoResult = await this.client.request("wallet.info", {});
Expand All @@ -45,7 +45,7 @@ export class WalletModule {
* List the wallet's implemented methodIds
*
* @returns The list of implemented method ids
* @throws {@link RpcError} if an error occured on server side
* @throws {@link RpcError} if an error occurred on server side
*
* @beta Filtering not yet implemented
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/spec/rpcHandlers/WalletHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type {
AccountListHandler,
AccountReceiveHandler,
AccountRequestHandler,
BitcoinGetAddressHandler,
BitcoinGetPublicKeyHandler,
BitcoinGetXPubHandler,
CurrencyListHandler,
CustomRequestHandler,
Expand Down Expand Up @@ -42,6 +44,8 @@ export type WalletHandlers<GenericCustomHandlers = UnknownCustomHandlers> = {
"transaction.signAndBroadcast": TransactionSignAndBroadcastHandler;
"storage.set": StorageSetHandler;
"storage.get": StorageGetHandler;
"bitcoin.getAddress": BitcoinGetAddressHandler;
"bitcoin.getPublicKey": BitcoinGetPublicKeyHandler;
"bitcoin.getXPub": BitcoinGetXPubHandler;
"wallet.capabilities": WalletCapabilitiesHandler;
"wallet.userId": WalletUserIdHandler;
Expand Down
24 changes: 24 additions & 0 deletions packages/core/src/spec/types/BitcoinGetAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { z } from "zod";

const schemaBitcoinGetAddressParams = z.object({
accountId: z.string(),
derivationPath: z.string().optional(),
});

const schemaBitcoinGetAddressResults = z.object({
address: z.string(),
});

export const schemaBitcoinGetAddress = {
params: schemaBitcoinGetAddressParams,
result: schemaBitcoinGetAddressResults,
};

export type BitcoinGetAddress = {
params: z.infer<typeof schemaBitcoinGetAddressParams>;
result: z.infer<typeof schemaBitcoinGetAddressResults>;
};

export type BitcoinGetAddressHandler = (
params: BitcoinGetAddress["params"],
) => BitcoinGetAddress["result"];
24 changes: 24 additions & 0 deletions packages/core/src/spec/types/BitcoinGetPublicKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { z } from "zod";

const schemaBitcoinGetPublicKeyParams = z.object({
accountId: z.string(),
derivationPath: z.string().optional(),
});

const schemaBitcoinGetPublicKeyResults = z.object({
publicKey: z.string(),
});

export const schemaBitcoinGetPublicKey = {
params: schemaBitcoinGetPublicKeyParams,
result: schemaBitcoinGetPublicKeyResults,
};

export type BitcoinGetPublicKey = {
params: z.infer<typeof schemaBitcoinGetPublicKeyParams>;
result: z.infer<typeof schemaBitcoinGetPublicKeyResults>;
};

export type BitcoinGetPublicKeyHandler = (
params: BitcoinGetPublicKey["params"],
) => BitcoinGetPublicKey["result"];
2 changes: 2 additions & 0 deletions packages/core/src/spec/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from "./AccountList";
export * from "./AccountReceive";
export * from "./AccountRequest";
export * from "./BitcoinGetAddress";
export * from "./BitcoinGetPublicKey";
export * from "./BitcoinGetXPub";
export * from "./CurrencyList";
export * from "./CustomRequest";
Expand Down
Loading

0 comments on commit 9261475

Please sign in to comment.