diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index b91a57b3..109651a9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -11,18 +11,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] concurrency: group: ${{ github.head_ref }}-publish cancel-in-progress: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: Cache pnpm modules - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-pnpm-modules with: @@ -30,9 +30,9 @@ jobs: key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}-${{ hashFiles('**/package.json') }} restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}- - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: - version: 6.20.4 + version: 8.15.9 - name: Install dependencies run: pnpm install - name: Publish diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c7b3cfa..dabb55ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,13 +15,13 @@ jobs: group: ${{ github.head_ref }}-test cancel-in-progress: true steps: - - uses: actions/checkout@v2 - - uses: pnpm/action-setup@v2 + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v3 with: version: 8.8.0 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: "18" cache: "pnpm" - name: Build run: | diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 7e9fab0b..5fb806c3 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} diff --git a/.github/workflows/validators.yml b/.github/workflows/validators.yml index 0770b2ae..81887c9c 100644 --- a/.github/workflows/validators.yml +++ b/.github/workflows/validators.yml @@ -9,13 +9,13 @@ jobs: compile: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: pnpm/action-setup@v2 + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v3 with: version: 8.8.0 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: "16" + node-version: "18" cache: "pnpm" - name: Build run: | diff --git a/packages/ark/source/address.service.ts b/packages/ark/source/address.service.ts index 10a2f5d6..d1667508 100644 --- a/packages/ark/source/address.service.ts +++ b/packages/ark/source/address.service.ts @@ -29,6 +29,18 @@ export class AddressService extends Services.AbstractAddressService { }; } + public override async fromBip44Mnemonic( + mnemonic: string, + path: string, + ): Promise { + abort_unless(BIP39.compatible(mnemonic), "The given value is not BIP39 compliant."); + + return { + address: BaseAddress.fromBip44Mnemonic(mnemonic, path, this.#config.network), + type: "bip44", + }; + } + public override async fromMultiSignature({ min, publicKeys, diff --git a/packages/ark/source/crypto/identities/address.ts b/packages/ark/source/crypto/identities/address.ts index d6759576..645369c1 100644 --- a/packages/ark/source/crypto/identities/address.ts +++ b/packages/ark/source/crypto/identities/address.ts @@ -11,6 +11,10 @@ export class Address { return Address.fromPublicKey(PublicKey.fromPassphrase(passphrase), network); } + public static fromBip44Mnemonic(mnemonic: string, path: string, network?: Network): string { + return Address.fromPublicKey(PublicKey.fromBip44Mnemonic(mnemonic, path), network); + } + public static fromPublicKey(publicKey: string, network?: Network): string { if (!PublicKey.verify(publicKey)) { throw new PublicKeyError(publicKey); diff --git a/packages/ark/source/crypto/identities/keys.ts b/packages/ark/source/crypto/identities/keys.ts index 05aead02..93108b99 100644 --- a/packages/ark/source/crypto/identities/keys.ts +++ b/packages/ark/source/crypto/identities/keys.ts @@ -1,4 +1,4 @@ -import { Hash, secp256k1, WIF } from "@ardenthq/sdk-cryptography"; +import { Hash, secp256k1, WIF, BIP39, HDKey } from "@ardenthq/sdk-cryptography"; import { Network } from "../interfaces/networks.js"; import { KeyPair } from "./contracts.js"; @@ -10,6 +10,15 @@ export class Keys { return Keys.fromPrivateKey(Hash.sha256(Buffer.from(passphrase, "utf8")), compressed); } + public static fromBip44Mnemonic(mnemonic: string, path: string, compressed = true): KeyPair { + const seed = BIP39.toSeed(mnemonic); + + const hd = HDKey.fromSeed(Buffer.from(seed)); + const child = hd.derive(path); + + return Keys.fromPrivateKey(child.privateKey, compressed); + } + public static fromPrivateKey(privateKey: Buffer | string, compressed = true): KeyPair { privateKey = privateKey instanceof Buffer ? privateKey : Buffer.from(privateKey, "hex"); diff --git a/packages/ark/source/crypto/identities/private-key.ts b/packages/ark/source/crypto/identities/private-key.ts index 492d3723..909f69fe 100644 --- a/packages/ark/source/crypto/identities/private-key.ts +++ b/packages/ark/source/crypto/identities/private-key.ts @@ -6,6 +6,10 @@ export class PrivateKey { return Keys.fromPassphrase(passphrase).privateKey; } + public static fromBip44Mnemonic(passphrase: string, path: string): string { + return Keys.fromBip44Mnemonic(passphrase, path).privateKey; + } + public static fromWIF(wif: string, network?: Network): string { return Keys.fromWIF(wif, network).privateKey; } diff --git a/packages/ark/source/crypto/identities/public-key.ts b/packages/ark/source/crypto/identities/public-key.ts index af06f1d5..87c4ee6b 100644 --- a/packages/ark/source/crypto/identities/public-key.ts +++ b/packages/ark/source/crypto/identities/public-key.ts @@ -11,6 +11,10 @@ export class PublicKey { return Keys.fromPassphrase(passphrase).publicKey; } + public static fromBip44Mnemonic(passphrase: string, path: string): string { + return Keys.fromBip44Mnemonic(passphrase, path).publicKey; + } + public static fromWIF(wif: string, network?: Network): string { return Keys.fromWIF(wif, network).publicKey; } diff --git a/packages/ark/source/crypto/transactions/builders/transaction.ts b/packages/ark/source/crypto/transactions/builders/transaction.ts index 5bcd1cba..9c5d85e3 100644 --- a/packages/ark/source/crypto/transactions/builders/transaction.ts +++ b/packages/ark/source/crypto/transactions/builders/transaction.ts @@ -102,6 +102,11 @@ export abstract class TransactionBuilder { + abort_unless(BIP39.compatible(mnemonic), "The given value is not BIP39 compliant."); + + return { + privateKey: BasePrivateKey.fromBip44Mnemonic(mnemonic, path), + }; + } + public override async fromSecret(secret: string): Promise { abort_if(BIP39.compatible(secret), "The given value is BIP39 compliant. Please use [fromMnemonic] instead."); diff --git a/packages/ark/source/public-key.service.ts b/packages/ark/source/public-key.service.ts index 73554604..c5782f07 100644 --- a/packages/ark/source/public-key.service.ts +++ b/packages/ark/source/public-key.service.ts @@ -26,6 +26,17 @@ export class PublicKeyService extends Services.AbstractPublicKeyService { }; } + public override async fromBip44Mnemonic( + mnemonic: string, + path: string, + ): Promise { + abort_unless(BIP39.compatible(mnemonic), "The given value is not BIP39 compliant."); + + return { + publicKey: BasePublicKey.fromBip44Mnemonic(mnemonic, path), + }; + } + public override async fromMultiSignature( min: number, publicKeys: string[], diff --git a/packages/ark/source/transaction.service.ts b/packages/ark/source/transaction.service.ts index e45ce8ac..1eeba9e6 100644 --- a/packages/ark/source/transaction.service.ts +++ b/packages/ark/source/transaction.service.ts @@ -197,9 +197,19 @@ export class TransactionService extends Services.AbstractTransactionService { if (input.signatory.actsWithMnemonic() || input.signatory.actsWithConfirmationMnemonic()) { address = (await this.#addressService.fromMnemonic(input.signatory.signingKey())).address; + senderPublicKey = (await this.#publicKeyService.fromMnemonic(input.signatory.signingKey())).publicKey; } + if (input.signatory.actsWithBip44Mnemonic()) { + const path = input.signatory.path(); + + address = (await this.#addressService.fromBip44Mnemonic(input.signatory.signingKey(), path)).address; + + senderPublicKey = (await this.#publicKeyService.fromBip44Mnemonic(input.signatory.signingKey(), path)) + .publicKey; + } + if (input.signatory.actsWithSecret() || input.signatory.actsWithConfirmationSecret()) { address = (await this.#addressService.fromSecret(input.signatory.signingKey())).address; senderPublicKey = (await this.#publicKeyService.fromSecret(input.signatory.signingKey())).publicKey; @@ -315,6 +325,10 @@ export class TransactionService extends Services.AbstractTransactionService { transaction.sign(input.signatory.signingKey()); } + if (input.signatory.actsWithBip44Mnemonic()) { + transaction.signWithBip44Mnemonic(input.signatory.signingKey(), input.signatory.path()); + } + if (input.signatory.actsWithConfirmationMnemonic()) { transaction.sign(input.signatory.signingKey()); transaction.secondSign(input.signatory.confirmKey()); diff --git a/packages/profiles/source/serialiser.ts b/packages/profiles/source/serialiser.ts index caa8f8cf..38cedb28 100644 --- a/packages/profiles/source/serialiser.ts +++ b/packages/profiles/source/serialiser.ts @@ -49,6 +49,7 @@ export class WalletSerialiser { [WalletData.LedgerModel]: this.#wallet.data().get(WalletData.LedgerModel), [WalletData.Status]: this.#wallet.data().get(WalletData.Status), [WalletData.IsPrimary]: this.#wallet.data().get(WalletData.IsPrimary, false), + [WalletData.AddressIndex]: this.#wallet.data().get(WalletData.AddressIndex), }, id: this.#wallet.id(), settings: this.#wallet.settings().all(), diff --git a/packages/profiles/source/signatory.factory.contract.ts b/packages/profiles/source/signatory.factory.contract.ts index a8a5b903..6150cb73 100644 --- a/packages/profiles/source/signatory.factory.contract.ts +++ b/packages/profiles/source/signatory.factory.contract.ts @@ -8,6 +8,7 @@ export interface SignatoryInput { secondSecret?: string; wif?: string; privateKey?: string; + path?: string; } export interface ISignatoryFactory { diff --git a/packages/profiles/source/signatory.factory.ts b/packages/profiles/source/signatory.factory.ts index 60711b95..c36d7d5e 100644 --- a/packages/profiles/source/signatory.factory.ts +++ b/packages/profiles/source/signatory.factory.ts @@ -18,11 +18,16 @@ export class SignatoryFactory implements ISignatoryFactory { secondSecret, wif, privateKey, + path, }: SignatoryInput): Promise { if (mnemonic && secondMnemonic) { return this.#wallet.signatory().confirmationMnemonic(mnemonic, secondMnemonic); } + if (mnemonic && path) { + return this.#wallet.signatory().bip44Mnemonic(mnemonic, path); + } + if (mnemonic) { return this.#wallet.signatory().mnemonic(mnemonic); } @@ -50,6 +55,12 @@ export class SignatoryFactory implements ISignatoryFactory { return this.#wallet.signatory().secret(await this.#wallet.signingKey().get(encryptionPassword)); } + if (this.#wallet.actsWithBip44MnemonicWithEncryption()) { + return this.#wallet + .signatory() + .bip44Mnemonic(await this.#wallet.signingKey().get(encryptionPassword), path as string); + } + return this.#wallet.signatory().mnemonic(await this.#wallet.signingKey().get(encryptionPassword)); } diff --git a/packages/profiles/source/wallet.contract.ts b/packages/profiles/source/wallet.contract.ts index 3889e01a..665cbb7b 100644 --- a/packages/profiles/source/wallet.contract.ts +++ b/packages/profiles/source/wallet.contract.ts @@ -688,6 +688,22 @@ export interface IReadWriteWallet { */ actsWithMnemonic(): boolean; + /** + * Determines if the wallet has been imported with a BIP44 mnemonic + * + * @return {*} {boolean} + * @memberof IReadWriteWallet + */ + actsWithBip44Mnemonic(): boolean; + + /** + * Determines if the wallet has been imported with a BIP44 mnemonic with encryption + * + * @return {*} {boolean} + * @memberof IReadWriteWallet + */ + actsWithBip44MnemonicWithEncryption(): boolean; + /** * Determines if the wallet has been imported with a address. * diff --git a/packages/profiles/source/wallet.enum.ts b/packages/profiles/source/wallet.enum.ts index bf9413ff..f1262f6b 100644 --- a/packages/profiles/source/wallet.enum.ts +++ b/packages/profiles/source/wallet.enum.ts @@ -30,6 +30,7 @@ export enum WalletData { LedgerModel = "LEDGER_MODEL", Status = "STATUS", IsPrimary = "IS_PRIMARY", + AddressIndex = "ADDRESS_INDEX", } /** diff --git a/packages/profiles/source/wallet.factory.ts b/packages/profiles/source/wallet.factory.ts index 728510e4..3fe106d7 100644 --- a/packages/profiles/source/wallet.factory.ts +++ b/packages/profiles/source/wallet.factory.ts @@ -1,7 +1,7 @@ /* istanbul ignore file */ import { Enums } from "@ardenthq/sdk"; -import { BIP38, BIP39, UUID } from "@ardenthq/sdk-cryptography"; +import { BIP38, BIP39, UUID, secp256k1, HDKey } from "@ardenthq/sdk-cryptography"; import { IAddressOptions, @@ -75,12 +75,32 @@ export class WalletFactory implements IWalletFactory { /** {@inheritDoc IWalletFactory.fromMnemonicWithBIP44} */ public async fromMnemonicWithBIP44(options: IMnemonicDerivativeOptions): Promise { - return this.#fromMnemonicWithDerivative({ - derivationType: "bip44", - featureFlag: Enums.FeatureFlag.AddressMnemonicBip44, - importMethod: WalletImportMethod.BIP44.MNEMONIC, - options, - }); + const wallet: IReadWriteWallet = new Wallet(UUID.random(), {}, this.#profile); + wallet.data().set(WalletData.ImportMethod, WalletImportMethod.BIP44.MNEMONIC); + wallet.data().set(WalletData.Status, WalletFlag.Cold); + + await wallet.mutator().coin(options.coin, options.network); + + const slip = wallet.config().get("network.constants.slip44"); + const account = options.levels.account ?? 0; + const change = options.levels.change ?? 0; + const addressIndex = options.levels.addressIndex ?? 0; + + const path = `m/44'/${slip}'/${account}'/${change}/${addressIndex}`; + + wallet.data().set(WalletData.AddressIndex, addressIndex); + wallet.data().set(WalletData.DerivationPath, path); + + const address = (await wallet.coin().address().fromBip44Mnemonic(options.mnemonic, path)).address; + + await wallet.mutator().address({ address }); + + if (options.password) { + wallet.data().set(WalletData.ImportMethod, WalletImportMethod.BIP44.MNEMONIC_WITH_ENCRYPTION); + await wallet.signingKey().set(options.mnemonic, options.password); + } + + return wallet; } /** {@inheritDoc IWalletFactory.fromMnemonicWithBIP49} */ diff --git a/packages/profiles/source/wallet.identifier.factory.ts b/packages/profiles/source/wallet.identifier.factory.ts index 740dadbb..372f6fd7 100644 --- a/packages/profiles/source/wallet.identifier.factory.ts +++ b/packages/profiles/source/wallet.identifier.factory.ts @@ -12,7 +12,7 @@ export class WalletIdentifierFactory { return this.#address(wallet); } - if (wallet.actsWithMnemonic()) { + if (wallet.actsWithMnemonic() || wallet.actsWithBip44Mnemonic()) { return this.#addressOrPublicKey(wallet); } @@ -20,7 +20,7 @@ export class WalletIdentifierFactory { return this.#addressOrPublicKey(wallet); } - if (wallet.actsWithMnemonicWithEncryption()) { + if (wallet.actsWithMnemonicWithEncryption() || wallet.actsWithBip44MnemonicWithEncryption()) { return this.#addressOrPublicKey(wallet); } diff --git a/packages/profiles/source/wallet.test.ts b/packages/profiles/source/wallet.test.ts index 68561312..87240971 100644 --- a/packages/profiles/source/wallet.test.ts +++ b/packages/profiles/source/wallet.test.ts @@ -454,6 +454,7 @@ describe("Wallet", ({ beforeAll, beforeEach, loader, nock, assert, stub, it }) = VOTES_AVAILABLE: 0, VOTES_USED: 0, IS_PRIMARY: false, + ADDRESS_INDEX: undefined, }); assert.object(actual.settings); assert.string(actual.settings.AVATAR); diff --git a/packages/profiles/source/wallet.ts b/packages/profiles/source/wallet.ts index a28822e3..fc1787db 100644 --- a/packages/profiles/source/wallet.ts +++ b/packages/profiles/source/wallet.ts @@ -312,7 +312,10 @@ export class Wallet implements IReadWriteWallet { /** {@inheritDoc IReadWriteWallet.isLedger} */ public isLedger(): boolean { - return this.data().get(WalletData.DerivationPath) !== undefined; + return ( + this.data().get(WalletData.DerivationPath) !== undefined && + this.data().get(WalletData.AddressIndex) === undefined + ); } /** {@inheritDoc IReadWriteWallet.isLedgerNanoX} */ @@ -573,12 +576,21 @@ export class Wallet implements IReadWriteWallet { public actsWithMnemonic(): boolean { return [ WalletImportMethod.BIP39.MNEMONIC, - WalletImportMethod.BIP44.MNEMONIC, WalletImportMethod.BIP49.MNEMONIC, WalletImportMethod.BIP84.MNEMONIC, ].includes(this.data().get(WalletData.ImportMethod)!); } + /** {@inheritDoc IReadWriteWallet.actsWithBip44Mnemonic} */ + public actsWithBip44Mnemonic(): boolean { + return this.data().get(WalletData.ImportMethod) === WalletImportMethod.BIP44.MNEMONIC; + } + + /** {@inheritDoc IReadWriteWallet.actsWithBip44Mnemonic} */ + public actsWithBip44MnemonicWithEncryption(): boolean { + return this.data().get(WalletData.ImportMethod) === WalletImportMethod.BIP44.MNEMONIC_WITH_ENCRYPTION; + } + /** {@inheritDoc IReadWriteWallet.actsWithAddress} */ public actsWithAddress(): boolean { return this.data().get(WalletData.ImportMethod) === WalletImportMethod.Address; @@ -607,7 +619,6 @@ export class Wallet implements IReadWriteWallet { public actsWithMnemonicWithEncryption(): boolean { return [ WalletImportMethod.BIP39.MNEMONIC_WITH_ENCRYPTION, - WalletImportMethod.BIP44.MNEMONIC_WITH_ENCRYPTION, WalletImportMethod.BIP49.MNEMONIC_WITH_ENCRYPTION, WalletImportMethod.BIP84.MNEMONIC_WITH_ENCRYPTION, ].includes(this.data().get(WalletData.ImportMethod)!); diff --git a/packages/sdk/source/abstract.signatory.ts b/packages/sdk/source/abstract.signatory.ts index da9430c4..38466307 100644 --- a/packages/sdk/source/abstract.signatory.ts +++ b/packages/sdk/source/abstract.signatory.ts @@ -6,6 +6,7 @@ export abstract class AbstractSignatory { readonly #publicKey: string; readonly #privateKey: string; readonly #options?: IdentityOptions; + readonly #path?: string; public constructor({ signingKey, @@ -13,18 +14,21 @@ export abstract class AbstractSignatory { publicKey, privateKey, options, + path, }: { signingKey: string; address: string; publicKey: string; privateKey: string; options?: IdentityOptions; + path?: string; }) { this.#signingKey = signingKey.normalize("NFD"); this.#address = address; this.#publicKey = publicKey; this.#privateKey = privateKey; this.#options = options; + this.#path = path; } public signingKey(): string { @@ -46,4 +50,8 @@ export abstract class AbstractSignatory { public options(): IdentityOptions | undefined { return this.#options; } + + public path(): string | undefined { + return this.#path; + } } diff --git a/packages/sdk/source/address.contract.ts b/packages/sdk/source/address.contract.ts index af213c2b..1561e426 100644 --- a/packages/sdk/source/address.contract.ts +++ b/packages/sdk/source/address.contract.ts @@ -8,6 +8,7 @@ export interface AddressDataTransferObject { export interface AddressService { fromMnemonic(mnemonic: string, options?: IdentityOptions): Promise; + fromBip44Mnemonic(mnemonic: string, path: string): Promise; fromMultiSignature( input: MultisignatureAddressInput, options?: IdentityOptions, diff --git a/packages/sdk/source/address.service.ts b/packages/sdk/source/address.service.ts index 4145b865..90a384ed 100644 --- a/packages/sdk/source/address.service.ts +++ b/packages/sdk/source/address.service.ts @@ -21,6 +21,10 @@ export class AbstractAddressService implements AddressService { throw new NotImplemented(this.constructor.name, this.fromMultiSignature.name); } + public async fromBip44Mnemonic(mnemonic: string, path: string): Promise { + throw new NotImplemented(this.constructor.name, this.fromMultiSignature.name); + } + public async fromMultiSignature( input: MultisignatureAddressInput, options?: IdentityOptions, diff --git a/packages/sdk/source/private-key.contract.ts b/packages/sdk/source/private-key.contract.ts index 97e498a4..ca3f5756 100644 --- a/packages/sdk/source/private-key.contract.ts +++ b/packages/sdk/source/private-key.contract.ts @@ -7,6 +7,7 @@ export interface PrivateKeyDataTransferObject { export interface PrivateKeyService { fromMnemonic(mnemonic: string, options?: IdentityOptions): Promise; + fromBip44Mnemonic(mnemonic: string, path: string): Promise; fromWIF(wif: string): Promise; fromSecret(secret: string): Promise; } diff --git a/packages/sdk/source/private-key.service.ts b/packages/sdk/source/private-key.service.ts index f8594de4..de01d537 100644 --- a/packages/sdk/source/private-key.service.ts +++ b/packages/sdk/source/private-key.service.ts @@ -21,6 +21,10 @@ export class AbstractPrivateKeyService implements PrivateKeyService { throw new NotImplemented(this.constructor.name, this.fromMnemonic.name); } + public async fromBip44Mnemonic(mnemonic: string, path: string): Promise { + throw new NotImplemented(this.constructor.name, this.fromMnemonic.name); + } + public async fromWIF(wif: string): Promise { throw new NotImplemented(this.constructor.name, this.fromWIF.name); } diff --git a/packages/sdk/source/public-key.contract.ts b/packages/sdk/source/public-key.contract.ts index 2627e0bc..c97f0e2e 100644 --- a/packages/sdk/source/public-key.contract.ts +++ b/packages/sdk/source/public-key.contract.ts @@ -7,6 +7,7 @@ export interface PublicKeyDataTransferObject { export interface PublicKeyService { fromMnemonic(mnemonic: string, options?: IdentityOptions): Promise; + fromBip44Mnemonic(mnemonic: string, path: string): Promise; fromMultiSignature(min: number, publicKeys: string[]): Promise; fromWIF(wif: string): Promise; fromSecret(secret: string): Promise; diff --git a/packages/sdk/source/public-key.service.ts b/packages/sdk/source/public-key.service.ts index cd6e115c..49465637 100644 --- a/packages/sdk/source/public-key.service.ts +++ b/packages/sdk/source/public-key.service.ts @@ -21,6 +21,10 @@ export class AbstractPublicKeyService implements PublicKeyService { throw new NotImplemented(this.constructor.name, this.fromMultiSignature.name); } + public async fromBip44Mnemonic(mnemonic: string, path: string): Promise { + throw new NotImplemented(this.constructor.name, this.fromMultiSignature.name); + } + public async fromMultiSignature(min: number, publicKeys: string[]): Promise { throw new NotImplemented(this.constructor.name, this.fromMultiSignature.name); } diff --git a/packages/sdk/source/signatory.contract.ts b/packages/sdk/source/signatory.contract.ts index d42abbf2..6c381ff5 100644 --- a/packages/sdk/source/signatory.contract.ts +++ b/packages/sdk/source/signatory.contract.ts @@ -5,6 +5,8 @@ import { Signatory } from "./signatories.js"; export interface SignatoryService { mnemonic(mnemonic: string, options?: IdentityOptions): Promise; + bip44Mnemonic(mnemonic: string, path: string): Promise; + confirmationMnemonic(mnemonic: string, confirmation: string, options?: IdentityOptions): Promise; wif(mnemonic: string): Promise; diff --git a/packages/sdk/source/signatory.service.ts b/packages/sdk/source/signatory.service.ts index 84ffb2c8..f01349b4 100644 --- a/packages/sdk/source/signatory.service.ts +++ b/packages/sdk/source/signatory.service.ts @@ -45,6 +45,18 @@ export class AbstractSignatoryService implements SignatoryService { ); } + public async bip44Mnemonic(mnemonic: string, path: string): Promise { + return new Signatory( + new MnemonicSignatory({ + address: (await this.#addressService.fromBip44Mnemonic(mnemonic, path)).address, + privateKey: (await this.#privateKeyService.fromBip44Mnemonic(mnemonic, path)).privateKey, + publicKey: (await this.#publicKeyService.fromBip44Mnemonic(mnemonic, path)).publicKey, + signingKey: mnemonic, + path, + }), + ); + } + public async confirmationMnemonic( signingKey: string, confirmKey: string, diff --git a/packages/sdk/source/signatory.ts b/packages/sdk/source/signatory.ts index ec233082..e73d6ddf 100644 --- a/packages/sdk/source/signatory.ts +++ b/packages/sdk/source/signatory.ts @@ -111,6 +111,10 @@ export class Signatory { } public path(): string { + if (this.#signatory instanceof MnemonicSignatory && this.#signatory.path()) { + return this.#signatory.path() as string; + } + if (this.#signatory instanceof LedgerSignatory) { return this.#signatory.signingKey(); } @@ -154,6 +158,10 @@ export class Signatory { return this.#signatory instanceof MnemonicSignatory; } + public actsWithBip44Mnemonic(): boolean { + return this.#signatory instanceof MnemonicSignatory && this.#signatory.path() !== undefined; + } + public actsWithConfirmationMnemonic(): boolean { return this.#signatory instanceof ConfirmationMnemonicSignatory; }