Skip to content

Commit

Permalink
chore(wallet): allow to specify custom account and index (#120)
Browse files Browse the repository at this point in the history
* chore(wallet): allow to specify custom account and index

* chore(wallet): allow discovery of missing account/index

* chore(wallet): allow discovery of missing account/index

* chore(wallet): remove derivationPath from account as it is part of address

* chore(wallet): resolved comments

* chore(wallet): resolved comments
  • Loading branch information
thedoublejay authored Jul 8, 2024
1 parent d1c706c commit ece311f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 29 deletions.
37 changes: 28 additions & 9 deletions packages/sdk/src/addresses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export function getAddressType(address: string, network: Network): AddressTypes
export function getAddressesFromPublicKey(
pubKey: string | Buffer,
network: Network = "testnet",
format: AddressTypes | "all" = "all"
format: AddressTypes | "all" = "all",
accountIndex = 0,
addressIndex = 0
) {
if (!Buffer.isBuffer(pubKey)) {
pubKey = Buffer.from(pubKey, "hex")
Expand Down Expand Up @@ -66,15 +68,25 @@ export function getAddressesFromPublicKey(
address: paymentObj.address,
xkey: childNodeXOnlyPubkey.toString("hex"),
format: addressTypeToName[addrType],
pub: keys.publicKey.toString("hex")
pub: keys.publicKey.toString("hex"),
derivationPath: {
account: accountIndex,
addressIndex,
path: getDerivationPath(addressTypeToName[addrType], accountIndex, addressIndex)
}
})
} else {
const paymentObj = createTransaction(keys.publicKey, addrType, network)

addresses.push({
address: paymentObj.address,
format: addressTypeToName[addrType],
pub: keys.publicKey.toString("hex")
pub: keys.publicKey.toString("hex"),
derivationPath: {
account: accountIndex,
addressIndex,
path: getDerivationPath(addressTypeToName[addrType], accountIndex, addressIndex)
}
})
}
})
Expand All @@ -86,7 +98,12 @@ export function getAddressesFromPublicKey(
address: paymentObj.address,
format: addressTypeToName[format],
pub: keys.publicKey.toString("hex"),
xkey: format === "p2tr" ? childNodeXOnlyPubkey.toString("hex") : undefined
xkey: format === "p2tr" ? childNodeXOnlyPubkey.toString("hex") : undefined,
derivationPath: {
account: accountIndex,
addressIndex,
path: getDerivationPath(addressTypeToName[format], accountIndex, addressIndex)
}
})
}

Expand Down Expand Up @@ -143,18 +160,20 @@ export function getAccountDataFromHdNode({
return accountData
}

export function getAllAccountsFromHdNode({ hdNode, network = "testnet" }: GetAllAccountsFromHDNodeOptions) {
export function getAllAccountsFromHdNode({ hdNode, network = "testnet", account = 0, addressIndex = 0 }: GetAllAccountsFromHDNodeOptions) {
const accounts: Account[] = []
const addressTypesList = Object.values(addressTypeToName) as AddressFormats[]

addressTypesList.forEach((addrType) => {
const account = getAccountDataFromHdNode({
const walletAccount = getAccountDataFromHdNode({
hdNode,
format: addrType,
network
network,
account,
addressIndex
})

accounts.push(account)
accounts.push(walletAccount)
})

return accounts
Expand All @@ -165,6 +184,7 @@ export type Address = {
xkey?: string
format: string
pub: string
derivationPath: Derivation
}

export type Derivation = {
Expand All @@ -176,7 +196,6 @@ export type Derivation = {
export type Account = Address & {
priv: string
type: AddressTypes
derivationPath: Derivation
child: BIP32Interface
}

Expand Down
46 changes: 26 additions & 20 deletions packages/sdk/src/wallet/Ordit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import ECPairFactory, { ECPairInterface } from "ecpair"
import {
Account,
AddressFormats,
addressNameToType,
addressNameToType, DerivationIndex,
getAccountDataFromHdNode,
getAddressesFromPublicKey,
getAllAccountsFromHdNode,
getNetwork,
mintFromCollection,
publishCollection,
publishCollection, SigningMessageOptions,
tweakSigner
} from ".."
import { Network } from "../config/types"
Expand All @@ -37,7 +37,7 @@ export class Ordit {
selectedAddressType: AddressFormats | undefined
selectedAddress: string | undefined

constructor({ wif, seed, privateKey, bip39, network = "testnet", type = "legacy" }: WalletOptions) {
constructor({ wif, seed, privateKey, bip39, network = "testnet", type = "legacy", account = 0, addressIndex = 0 }: WalletOptions) {
this.#network = network
const networkObj = getNetwork(network)
const format = addressNameToType[type]
Expand All @@ -48,7 +48,7 @@ export class Ordit {

this.publicKey = keyPair.publicKey.toString("hex")

const accounts = getAddressesFromPublicKey(keyPair.publicKey, network, format)
const accounts = getAddressesFromPublicKey(keyPair.publicKey, network, format, account, addressIndex)
this.#initialize(accounts)
} else if (privateKey) {
const pkBuffer = Buffer.from(privateKey, "hex")
Expand All @@ -57,15 +57,15 @@ export class Ordit {

this.publicKey = keyPair.publicKey.toString("hex")

const accounts = getAddressesFromPublicKey(keyPair.publicKey, network, format)
const accounts = getAddressesFromPublicKey(keyPair.publicKey, network, format, account, addressIndex)
this.#initialize(accounts)
} else if (seed) {
const seedBuffer = Buffer.from(seed, "hex")
const hdNode = bip32.fromSeed(seedBuffer, networkObj)

this.#hdNode = hdNode

const accounts = getAllAccountsFromHdNode({ hdNode, network })
const accounts = getAllAccountsFromHdNode({ hdNode, network, account, addressIndex })

const pkBuf = Buffer.from(accounts[0].priv, "hex")
this.#keyPair = ECPair.fromPrivateKey(pkBuf, { network: networkObj })
Expand All @@ -79,7 +79,7 @@ export class Ordit {

this.#hdNode = hdNode

const accounts = getAllAccountsFromHdNode({ hdNode, network })
const accounts = getAllAccountsFromHdNode({ hdNode, network, account, addressIndex })
this.#keyPair = accounts[0].child

this.publicKey = this.#keyPair.publicKey.toString("hex")
Expand All @@ -98,17 +98,12 @@ export class Ordit {
this.#network = value
}

getAddressByType(type: AddressFormats) {
getAddressByType(type: AddressFormats, derivationIndex: DerivationIndex) {
if (!this.#initialized || !this.allAddresses.length) {
throw new OrditSDKError("Wallet not fully initialized.")
}
const result = this.allAddresses.filter((address) => address.format === type)

if (!result) {
throw new OrditSDKError(`Address of type ${type} not found in the instance.`)
}

return result
return this.allAddresses.find((address) => address.format === type && address.derivationPath.account === derivationIndex.accountIndex
&& address.derivationPath.addressIndex === derivationIndex.addressIndex);
}

getAllAddresses() {
Expand All @@ -119,11 +114,18 @@ export class Ordit {
return this.allAddresses
}

setDefaultAddress(type: AddressFormats, index = 0) {
setDefaultAddress(type: AddressFormats, { accountIndex = 0, addressIndex = 0 }: DerivationIndex) {
if (this.selectedAddressType === type) return
let addressToSelect: Account;

const result = this.getAddressByType(type) as Account[]
const addressToSelect = result[index]
const account = this.getAddressByType(type, { accountIndex, addressIndex }) as Account
if (!account) {
addressToSelect = this.generateAddress(type, accountIndex, addressIndex);
// Push to current list of addresses
this.allAddresses.push(addressToSelect);
} else {
addressToSelect = account;
}

if (!addressToSelect)
throw new OrditSDKError("Address not found. Please add an address with the type and try again.")
Expand Down Expand Up @@ -233,9 +235,11 @@ export class Ordit {
return psbt.toHex()
}

signMessage(message: string, type?: AddressFormats) {
signMessage(message: string, type?: AddressFormats, opts?: SigningMessageOptions) {
const addressType = type || this.selectedAddressType
const node = this.allAddresses.find((wallet) => wallet.format === addressType) as Account
const accountIndexToSign: number = opts?.accountIndex === undefined ? 0 : opts?.accountIndex;
const addressIndexToSign: number = opts?.addressIndex === undefined ? 0 : opts?.addressIndex;
const node = this.getAddressByType(addressType!, { accountIndex: accountIndexToSign, addressIndex: addressIndexToSign }) as Account
const signature = AddressUtils.isP2PKH(node.address!)
? sign(message, node.child.privateKey!)
: Signer.sign(node.child.toWIF(), node.address!, message, getNetwork(this.#network))
Expand Down Expand Up @@ -266,6 +270,8 @@ export type WalletOptions = {
bip39?: string
network?: Network
type?: AddressFormats
account?: number;
addressIndex?: number;
}

export type Address = ReturnType<typeof getAddressesFromPublicKey>[0]
Expand Down
7 changes: 7 additions & 0 deletions packages/sdk/src/wallet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ export type GetWalletOptions = {
format: AddressTypes | "all"
safeMode?: OnOffUnion
}

export interface DerivationIndex {
accountIndex: number
addressIndex: number
}

export type SigningMessageOptions = Partial<DerivationIndex>

0 comments on commit ece311f

Please sign in to comment.