From 78c6f9114603766400f43a425f9f3c64e824419d Mon Sep 17 00:00:00 2001 From: KevinK Date: Mon, 17 Jul 2023 14:51:51 +0800 Subject: [PATCH 1/5] feat(sdk): refactor addAddress to getAddress, add derivationpath --- packages/sdk/src/addresses/index.ts | 21 ++++++++++++++++----- packages/sdk/src/utils/index.ts | 26 ++++++++++++++++++++++++-- packages/sdk/src/wallet/Ordit.ts | 14 +++----------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/packages/sdk/src/addresses/index.ts b/packages/sdk/src/addresses/index.ts index 13c38c02..002ebbfd 100644 --- a/packages/sdk/src/addresses/index.ts +++ b/packages/sdk/src/addresses/index.ts @@ -3,7 +3,7 @@ import BIP32Factory, { BIP32Interface } from "bip32"; import { Network } from "../config/types"; import { getWalletKeys } from "../keys"; -import { createTransaction, getNetwork, hdNodeToChild, toXOnly } from "../utils"; +import {createTransaction, getDerivationPath, getNetwork, getPathLevels, toXOnly} from "../utils"; import { AddressFormats, addressFormats, addressNameToType, AddressTypes, addressTypeToName } from "./formats"; export function getAddressFormat(address: string, network: Network) { @@ -119,25 +119,33 @@ export async function getAddresses({ export function getAccountDataFromHdNode({ hdNode, format = "legacy", - network = "testnet" + network = "testnet", + accountIndex = 0, + index = 0 }: GetAccountDataFromHdNodeOptions) { if (!hdNode) { throw new Error("Invalid options provided."); } const addressType = addressNameToType[format]; - // - const child = hdNodeToChild(hdNode, format, 0); + + const fullDerivationPath = getDerivationPath(format, accountIndex, index) + const child = hdNode.derivePath(fullDerivationPath) + + console.log({fullDerivationPath ,pathLevles: getPathLevels(fullDerivationPath)}) + const pubKey = format === "taproot" ? toXOnly(child.publicKey) : child.publicKey; const paymentObj = createTransaction(pubKey, addressType, network); const address = paymentObj.address!; + const account: Account = { address, pub: child.publicKey.toString("hex"), priv: child.privateKey!.toString("hex"), format, - type: addressType + type: addressType, + derivationPath: fullDerivationPath }; if (format === "taproot") { @@ -174,6 +182,7 @@ export type Address = { export type Account = Address & { priv: string; type: AddressTypes; + derivationPath: string }; type GetAddressesOptions = { @@ -189,6 +198,8 @@ type GetAccountDataFromHdNodeOptions = { hdNode: BIP32Interface; format?: AddressFormats; network?: Network; + accountIndex?: number; + index?: number; }; type GetAllAccountsFromHDNodeOptions = Omit; diff --git a/packages/sdk/src/utils/index.ts b/packages/sdk/src/utils/index.ts index 6d63c93e..079638de 100644 --- a/packages/sdk/src/utils/index.ts +++ b/packages/sdk/src/utils/index.ts @@ -38,8 +38,30 @@ export function createTransaction( return bitcoin.payments[type]({ pubkey: key, network: networkObj }); } -export function hdNodeToChild(node: BIP32Interface, formatType: AddressFormats = "legacy", index = 0) { - const fullDerivationPath = DERIVATION_PATHS_WITHOUT_INDEX[formatType] + index; +export function getDerivationPath(formatType:AddressFormats, accountIndex = 0 , index = 0 ){ + const pathFormat = { + legacy: `m/44'/0'/${accountIndex}'/0/${index}`, + segwit: `m/49'/0'/${accountIndex}'/0/${index}`, + bech32: `m/84'/0'/${accountIndex}'/0/${index}`, + taproot: `m/86'/0'/${accountIndex}'/0/${index}` + } + return pathFormat[formatType] + +} + +export function getPathLevels(fullDerivationPath: string){ + const [, purpose, coinType, account,change,addressIndex] = fullDerivationPath.split("/") + return { + purpose: purpose.replace("'", ""), + coinType: coinType.replace("'", ""), + account: account.replace("'",""), + change, + addressIndex + } +} + +export function hdNodeToChild(node: BIP32Interface, formatType: AddressFormats = "legacy", index = 0, accountIndex= 0) { + const fullDerivationPath = getDerivationPath(formatType, accountIndex, index) return node.derivePath(fullDerivationPath); } diff --git a/packages/sdk/src/wallet/Ordit.ts b/packages/sdk/src/wallet/Ordit.ts index 55630e3e..f58c0039 100644 --- a/packages/sdk/src/wallet/Ordit.ts +++ b/packages/sdk/src/wallet/Ordit.ts @@ -37,6 +37,7 @@ export class Ordit { #hdNode: BIP32Interface | null = null; publicKey: string; allAddresses: ReturnType | ReturnType = []; + currentAccountIndex: number | undefined selectedAddressType: AddressFormats | undefined; selectedAddress: string | undefined; @@ -145,19 +146,10 @@ export class Ordit { } } - addAddress(type: AddressFormats, count = 1) { + getAddress(type: AddressFormats, accountIndex: number, addressIndex:number) { if (!this.#hdNode) throw new Error("No HD node found. Please reinitialize with BIP39 words or seed."); - const accounts: Account[] = []; - for (let i = 0; i < count; i++) { - const account = getAccountDataFromHdNode({ hdNode: this.#hdNode, format: type, network: this.#network }); - - accounts.push(account); - } - - this.allAddresses.push(...accounts); - - return accounts; + return getAccountDataFromHdNode({ hdNode: this.#hdNode, format: type, network: this.#network, accountIndex, index:addressIndex }); } signPsbt(value: string, { finalized = true }: { finalized?: boolean }) { From adcd88ac47aef4e63c5ddc6bb5b84aef76635caf Mon Sep 17 00:00:00 2001 From: KevinK Date: Mon, 17 Jul 2023 14:54:22 +0800 Subject: [PATCH 2/5] remove log --- packages/sdk/src/addresses/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/sdk/src/addresses/index.ts b/packages/sdk/src/addresses/index.ts index 002ebbfd..67ca2752 100644 --- a/packages/sdk/src/addresses/index.ts +++ b/packages/sdk/src/addresses/index.ts @@ -132,8 +132,6 @@ export function getAccountDataFromHdNode({ const fullDerivationPath = getDerivationPath(format, accountIndex, index) const child = hdNode.derivePath(fullDerivationPath) - console.log({fullDerivationPath ,pathLevles: getPathLevels(fullDerivationPath)}) - const pubKey = format === "taproot" ? toXOnly(child.publicKey) : child.publicKey; const paymentObj = createTransaction(pubKey, addressType, network); From 3f5b7e1e5ec53b45b20e3732024e288a0a73f148 Mon Sep 17 00:00:00 2001 From: KevinK Date: Mon, 17 Jul 2023 15:35:23 +0800 Subject: [PATCH 3/5] remove unused field --- packages/sdk/src/wallet/Ordit.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sdk/src/wallet/Ordit.ts b/packages/sdk/src/wallet/Ordit.ts index f58c0039..3cf8d750 100644 --- a/packages/sdk/src/wallet/Ordit.ts +++ b/packages/sdk/src/wallet/Ordit.ts @@ -37,7 +37,6 @@ export class Ordit { #hdNode: BIP32Interface | null = null; publicKey: string; allAddresses: ReturnType | ReturnType = []; - currentAccountIndex: number | undefined selectedAddressType: AddressFormats | undefined; selectedAddress: string | undefined; From b65ae2fbaa635d7f6e84a75a97839aeeaee8742a Mon Sep 17 00:00:00 2001 From: KevinK Date: Mon, 17 Jul 2023 17:38:32 +0800 Subject: [PATCH 4/5] fix lint issues --- packages/sdk/src/addresses/index.ts | 8 ++++---- packages/sdk/src/utils/index.ts | 24 ++++++++++++++---------- packages/sdk/src/wallet/Ordit.ts | 10 ++++++++-- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/sdk/src/addresses/index.ts b/packages/sdk/src/addresses/index.ts index 67ca2752..870b7cf6 100644 --- a/packages/sdk/src/addresses/index.ts +++ b/packages/sdk/src/addresses/index.ts @@ -3,7 +3,7 @@ import BIP32Factory, { BIP32Interface } from "bip32"; import { Network } from "../config/types"; import { getWalletKeys } from "../keys"; -import {createTransaction, getDerivationPath, getNetwork, getPathLevels, toXOnly} from "../utils"; +import { createTransaction, getDerivationPath, getNetwork, toXOnly } from "../utils"; import { AddressFormats, addressFormats, addressNameToType, AddressTypes, addressTypeToName } from "./formats"; export function getAddressFormat(address: string, network: Network) { @@ -129,8 +129,8 @@ export function getAccountDataFromHdNode({ const addressType = addressNameToType[format]; - const fullDerivationPath = getDerivationPath(format, accountIndex, index) - const child = hdNode.derivePath(fullDerivationPath) + const fullDerivationPath = getDerivationPath(format, accountIndex, index); + const child = hdNode.derivePath(fullDerivationPath); const pubKey = format === "taproot" ? toXOnly(child.publicKey) : child.publicKey; const paymentObj = createTransaction(pubKey, addressType, network); @@ -180,7 +180,7 @@ export type Address = { export type Account = Address & { priv: string; type: AddressTypes; - derivationPath: string + derivationPath: string; }; type GetAddressesOptions = { diff --git a/packages/sdk/src/utils/index.ts b/packages/sdk/src/utils/index.ts index 079638de..d6e95f1c 100644 --- a/packages/sdk/src/utils/index.ts +++ b/packages/sdk/src/utils/index.ts @@ -38,30 +38,34 @@ export function createTransaction( return bitcoin.payments[type]({ pubkey: key, network: networkObj }); } -export function getDerivationPath(formatType:AddressFormats, accountIndex = 0 , index = 0 ){ +export function getDerivationPath(formatType: AddressFormats, accountIndex = 0, index = 0) { const pathFormat = { legacy: `m/44'/0'/${accountIndex}'/0/${index}`, segwit: `m/49'/0'/${accountIndex}'/0/${index}`, bech32: `m/84'/0'/${accountIndex}'/0/${index}`, taproot: `m/86'/0'/${accountIndex}'/0/${index}` - } - return pathFormat[formatType] - + }; + return pathFormat[formatType]; } -export function getPathLevels(fullDerivationPath: string){ - const [, purpose, coinType, account,change,addressIndex] = fullDerivationPath.split("/") +export function getPathLevels(fullDerivationPath: string) { + const [, purpose, coinType, account, change, addressIndex] = fullDerivationPath.split("/"); return { purpose: purpose.replace("'", ""), coinType: coinType.replace("'", ""), - account: account.replace("'",""), + account: account.replace("'", ""), change, addressIndex - } + }; } -export function hdNodeToChild(node: BIP32Interface, formatType: AddressFormats = "legacy", index = 0, accountIndex= 0) { - const fullDerivationPath = getDerivationPath(formatType, accountIndex, index) +export function hdNodeToChild( + node: BIP32Interface, + formatType: AddressFormats = "legacy", + index = 0, + accountIndex = 0 +) { + const fullDerivationPath = getDerivationPath(formatType, accountIndex, index); return node.derivePath(fullDerivationPath); } diff --git a/packages/sdk/src/wallet/Ordit.ts b/packages/sdk/src/wallet/Ordit.ts index 3cf8d750..083b0370 100644 --- a/packages/sdk/src/wallet/Ordit.ts +++ b/packages/sdk/src/wallet/Ordit.ts @@ -145,10 +145,16 @@ export class Ordit { } } - getAddress(type: AddressFormats, accountIndex: number, addressIndex:number) { + getAddress(type: AddressFormats, accountIndex: number, addressIndex: number) { if (!this.#hdNode) throw new Error("No HD node found. Please reinitialize with BIP39 words or seed."); - return getAccountDataFromHdNode({ hdNode: this.#hdNode, format: type, network: this.#network, accountIndex, index:addressIndex }); + return getAccountDataFromHdNode({ + hdNode: this.#hdNode, + format: type, + network: this.#network, + accountIndex, + index: addressIndex + }); } signPsbt(value: string, { finalized = true }: { finalized?: boolean }) { From f05ed15db106a7cbda00983fc881923c31cb0145 Mon Sep 17 00:00:00 2001 From: KevinK Date: Tue, 18 Jul 2023 10:08:26 +0800 Subject: [PATCH 5/5] resolve comment + rename to fit BIP44 specs --- packages/sdk/src/addresses/index.ts | 30 +++++++++++++++++++---------- packages/sdk/src/utils/index.ts | 27 ++++++++------------------ packages/sdk/src/wallet/Ordit.ts | 6 +++--- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/packages/sdk/src/addresses/index.ts b/packages/sdk/src/addresses/index.ts index 870b7cf6..96c14783 100644 --- a/packages/sdk/src/addresses/index.ts +++ b/packages/sdk/src/addresses/index.ts @@ -120,8 +120,8 @@ export function getAccountDataFromHdNode({ hdNode, format = "legacy", network = "testnet", - accountIndex = 0, - index = 0 + account = 0, + addressIndex = 0 }: GetAccountDataFromHdNodeOptions) { if (!hdNode) { throw new Error("Invalid options provided."); @@ -129,7 +129,7 @@ export function getAccountDataFromHdNode({ const addressType = addressNameToType[format]; - const fullDerivationPath = getDerivationPath(format, accountIndex, index); + const fullDerivationPath = getDerivationPath(format, account, addressIndex); const child = hdNode.derivePath(fullDerivationPath); const pubKey = format === "taproot" ? toXOnly(child.publicKey) : child.publicKey; @@ -137,20 +137,24 @@ export function getAccountDataFromHdNode({ const address = paymentObj.address!; - const account: Account = { + const accountData: Account = { address, pub: child.publicKey.toString("hex"), priv: child.privateKey!.toString("hex"), format, type: addressType, - derivationPath: fullDerivationPath + derivationPath: { + account, + addressIndex, + path: fullDerivationPath + } }; if (format === "taproot") { - account.xkey = toXOnly(child.publicKey).toString("hex"); + accountData.xkey = toXOnly(child.publicKey).toString("hex"); } - return account; + return accountData; } export function getAllAccountsFromHdNode({ hdNode, network = "testnet" }: GetAllAccountsFromHDNodeOptions) { @@ -177,10 +181,16 @@ export type Address = { pub: string; }; +export type Derivation = { + account: number; + addressIndex: number; + path: string +} + export type Account = Address & { priv: string; type: AddressTypes; - derivationPath: string; + derivationPath: Derivation; }; type GetAddressesOptions = { @@ -196,8 +206,8 @@ type GetAccountDataFromHdNodeOptions = { hdNode: BIP32Interface; format?: AddressFormats; network?: Network; - accountIndex?: number; - index?: number; + account?: number; + addressIndex?: number; }; type GetAllAccountsFromHDNodeOptions = Omit; diff --git a/packages/sdk/src/utils/index.ts b/packages/sdk/src/utils/index.ts index d6e95f1c..4a5c3a36 100644 --- a/packages/sdk/src/utils/index.ts +++ b/packages/sdk/src/utils/index.ts @@ -38,34 +38,23 @@ export function createTransaction( return bitcoin.payments[type]({ pubkey: key, network: networkObj }); } -export function getDerivationPath(formatType: AddressFormats, accountIndex = 0, index = 0) { +export function getDerivationPath(formatType: AddressFormats, account = 0, addressIndex = 0) { const pathFormat = { - legacy: `m/44'/0'/${accountIndex}'/0/${index}`, - segwit: `m/49'/0'/${accountIndex}'/0/${index}`, - bech32: `m/84'/0'/${accountIndex}'/0/${index}`, - taproot: `m/86'/0'/${accountIndex}'/0/${index}` + legacy: `m/44'/0'/${account}'/0/${addressIndex}`, + segwit: `m/49'/0'/${account}'/0/${addressIndex}`, + bech32: `m/84'/0'/${account}'/0/${addressIndex}`, + taproot: `m/86'/0'/${account}'/0/${addressIndex}` }; return pathFormat[formatType]; } -export function getPathLevels(fullDerivationPath: string) { - const [, purpose, coinType, account, change, addressIndex] = fullDerivationPath.split("/"); - return { - purpose: purpose.replace("'", ""), - coinType: coinType.replace("'", ""), - account: account.replace("'", ""), - change, - addressIndex - }; -} - export function hdNodeToChild( node: BIP32Interface, formatType: AddressFormats = "legacy", - index = 0, - accountIndex = 0 + addressIndex = 0, + account = 0 ) { - const fullDerivationPath = getDerivationPath(formatType, accountIndex, index); + const fullDerivationPath = getDerivationPath(formatType, account, addressIndex); return node.derivePath(fullDerivationPath); } diff --git a/packages/sdk/src/wallet/Ordit.ts b/packages/sdk/src/wallet/Ordit.ts index 083b0370..10d7cdb0 100644 --- a/packages/sdk/src/wallet/Ordit.ts +++ b/packages/sdk/src/wallet/Ordit.ts @@ -145,15 +145,15 @@ export class Ordit { } } - getAddress(type: AddressFormats, accountIndex: number, addressIndex: number) { + generateAddress(type: AddressFormats, account: number, addressIndex: number) { if (!this.#hdNode) throw new Error("No HD node found. Please reinitialize with BIP39 words or seed."); return getAccountDataFromHdNode({ hdNode: this.#hdNode, format: type, network: this.#network, - accountIndex, - index: addressIndex + account, + addressIndex }); }