From bbbd46026e4bb8ef72aa104b169dfa2dddb3b519 Mon Sep 17 00:00:00 2001 From: qkin Date: Wed, 14 Jan 2026 17:18:30 +0800 Subject: [PATCH] feat: update derivationPaths to array --- .../__tests__/AvalancheSignRequest.test.ts | 29 ++++++----- .../src/AvalancheSignRequest.ts | 51 ++++++++++--------- .../src/AvalancheSignature.ts | 18 +++---- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts index ddf798bf..4dfcc9e4 100644 --- a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts +++ b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts @@ -6,10 +6,10 @@ import { UREncoder } from "@ngraveio/bc-ur"; describe("avalanche-sign-request", () => { it("test should generate avalanche-sign-reqeust", () => { const avalancheData = Buffer.from( - "0000000000220000000100000000000000000000000000000000000000000000000000000000000000000000000221e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000700000000006c2b4400000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c521e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000176bbb400000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c500000001cd53226620f4be2b6f6e43b1470f4f715b3bc7f40c4530cd5237a1c4156b537f0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000000001e2fb33000000010000000000000000", + "0000000000220000000100000000000000000000000000000000000000000000000000000000000000000000000221e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000031cb3a00000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c521e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000000005dabac900000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c500000008120d0def706b8b759935b8ea9727662aafa5381e598a074daddc82492549cd760000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000046239d0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000131021c0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000176b6a5000000010000000065a3b1de10620296debfa01aa953e45ddd19d2c39e3dacb9a92e6a85ca8a309c0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000098968000000001000000006f6522ae52b0231076dc63ff95f7ea22e2fd80943e37235302c7ee32afce4cd60000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000009896800000000100000000845649c3d1a630d8b466f7b727f6577cb4a17864699e6de756e484b81d84cd2a0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000006c2b440000000100000000d1e6480c1825197e2ec293a60bacdc7f60bfba2f3cc5383855180b45d595a7030000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000007a12000000000100000000f59b9a175ebe4ccd8de5dcfc6a26870414f30c696cce19283f30145624b445b70000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000107a493000000010000000000000000", "hex" ); - const derivationPath = "m/44'/9000'/0'/0/1"; + const derivationPath = ["m/44'/9000'/0'/0/0","m/44'/9000'/0'/0/1"]; const utxos = []; const xfp = '2d0bdabc' @@ -29,28 +29,33 @@ describe("avalanche-sign-request", () => { avalancheSignRequest.toDataItem() ); - const path = request.getDerivationPath(); - expect(path).toBeDefined(); - expect(path.getPath()).toBe("44'/9000'/0'/0/1"); + const paths = request.getDerivationPaths(); + expect(paths).toBeDefined(); + expect(paths.length).toBe(2); - const recoveredXfp = request.getDerivationPath().getSourceFingerprint().toString('hex'); + expect(paths[0].getPath()).toBe("44'/9000'/0'/0/0"); + expect(paths[1].getPath()).toBe("44'/9000'/0'/0/1"); + + const recoveredXfp = paths[0].getSourceFingerprint().toString('hex'); expect(recoveredXfp).toBe(xfp) expect(request.getSignData().toString("hex")).toBe( - "0000000000220000000100000000000000000000000000000000000000000000000000000000000000000000000221e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000700000000006c2b4400000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c521e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000176bbb400000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c500000001cd53226620f4be2b6f6e43b1470f4f715b3bc7f40c4530cd5237a1c4156b537f0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000000001e2fb33000000010000000000000000" + "0000000000220000000100000000000000000000000000000000000000000000000000000000000000000000000221e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000031cb3a00000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c521e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000000005dabac900000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c500000008120d0def706b8b759935b8ea9727662aafa5381e598a074daddc82492549cd760000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000046239d0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000131021c0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000176b6a5000000010000000065a3b1de10620296debfa01aa953e45ddd19d2c39e3dacb9a92e6a85ca8a309c0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000098968000000001000000006f6522ae52b0231076dc63ff95f7ea22e2fd80943e37235302c7ee32afce4cd60000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000009896800000000100000000845649c3d1a630d8b466f7b727f6577cb4a17864699e6de756e484b81d84cd2a0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000006c2b440000000100000000d1e6480c1825197e2ec293a60bacdc7f60bfba2f3cc5383855180b45d595a7030000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000007a12000000000100000000f59b9a175ebe4ccd8de5dcfc6a26870414f30c696cce19283f30145624b445b70000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000107a493000000010000000000000000" ); }); it("test parse signature", () => { const cbor = Buffer.from( - "a201501a79a2072e114014837e792e003384c10258418d1b6e955f1b2a94aed0b2c29939d68bae89fce2d436cc814efc4731f4a43e8e78ae46e3fdd58e7e0f7c5fa7876239fe7ab0adb6a75c09a07132b741be62612000", + "a20150d797b45aef4b483cb106506e288b2c770282584116ef664a04634a748ff13b6bd43bc2657b699f90c86b0fa946e90514089f75b24e7f1fc3183733c9c4a90972d7ce756c4464acfd5e4ecb43e6505abca2125b9c005841ddc5acd7adb746a519d85fff8cdc609e94bec04603c867acd926eef683ccb2a40fe1690cd3d9d931b0f2ff9eda6dbf4ffdec20606126bc37cee53ada832d19b700", "hex" ); - const signature = AvalancheSignature.fromCBOR(cbor); + const signatures = AvalancheSignature.fromCBOR(cbor); + const sigBuffers = signatures.getSignatures(); + const finalHexArray = sigBuffers.map(sig => sig.toString('hex')); + console.log('signature 1:', finalHexArray[0]); + console.log('signature 2:', finalHexArray[1]); - expect(signature.getSignature().toString("hex")).toBe( - "8d1b6e955f1b2a94aed0b2c29939d68bae89fce2d436cc814efc4731f4a43e8e78ae46e3fdd58e7e0f7c5fa7876239fe7ab0adb6a75c09a07132b741be62612000" - ); + expect(finalHexArray.length).toBe(2); }); }); diff --git a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts index b1c41dd5..d8e6288d 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts @@ -15,20 +15,20 @@ const { RegistryTypes } = extend; type signRequestProps = { requestId?: Buffer; data: Buffer; - derivationPath: CryptoKeypath; + derivationPaths: CryptoKeypath[]; utxos: AvalancheUtxo[]; }; enum Keys { requestId = 1, signData, - derivationPath, + derivationPaths, utxos, } export class AvalancheSignRequest extends RegistryItem { private requestId?: Buffer; private data: Buffer; - private derivationPath: CryptoKeypath; + private derivationPaths: CryptoKeypath[]; private utxos: AvalancheUtxo[]; @@ -38,14 +38,14 @@ export class AvalancheSignRequest extends RegistryItem { super(); this.requestId = args.requestId; this.data = args.data; - this.derivationPath = args.derivationPath; + this.derivationPaths = args.derivationPaths; this.utxos = args.utxos; } public getRequestId = () => this.requestId; public getSignData = () => this.data; public getUtxos = () => this.utxos; - public getDerivationPath = () => this.derivationPath; + public getDerivationPaths = () => this.derivationPaths; public toDataItem = () => { const map: DataItemMap = {}; @@ -58,9 +58,11 @@ export class AvalancheSignRequest extends RegistryItem { map[Keys.signData] = Buffer.from(this.data); - const keyPath = this.derivationPath.toDataItem(); - keyPath.setTag(this.derivationPath.getRegistryType().getTag()); - map[Keys.derivationPath] = keyPath; + map[Keys.derivationPaths] = this.derivationPaths.map((keypath) => { + const item = keypath.toDataItem(); + item.setTag(keypath.getRegistryType().getTag()); + return item; + }); map[Keys.utxos] = this.utxos.map((utxo) => { const res = utxo.toDataItem(); @@ -77,7 +79,9 @@ export class AvalancheSignRequest extends RegistryItem { ? map[Keys.requestId].getData() : undefined; const data = map[Keys.signData]; - const derivationPath = CryptoKeypath.fromDataItem(map[Keys.derivationPath]); + const derivationPaths: CryptoKeypath[] = map[Keys.derivationPaths].map( + (item: DataItem) => CryptoKeypath.fromDataItem(item) + ); const utxos: AvalancheUtxo[] = map[Keys.utxos].map((utxo: DataItem) => AvalancheUtxo.fromDataItem(utxo) ); @@ -85,14 +89,14 @@ export class AvalancheSignRequest extends RegistryItem { return new AvalancheSignRequest({ requestId, data, - derivationPath, + derivationPaths, utxos, }); }; public static constructAvalancheRequest( data: Buffer, - hdPath: string, + hdPaths: string[], utxos: AvalancheUtxoData[], xfp: string, requestId?: string | Buffer @@ -110,23 +114,22 @@ export class AvalancheSignRequest extends RegistryItem { AvalancheUtxo.constructAvalancheUtxo(utxo) ); - const paths = hdPath.replace(/[m|M]\//, "").split("/"); - const hdpathObject = new CryptoKeypath( - paths.map((path) => { - const index = parseInt(path.replace("'", "")); - let isHardened = false; - if (path.endsWith("'")) { - isHardened = true; - } - return new PathComponent({ index, hardened: isHardened }); - }), - Buffer.from(xfp, "hex") - ); + const derivationPaths = hdPaths.map(hdPath => { + const paths = hdPath.replace(/[m|M]\//, "").split("/"); + return new CryptoKeypath( + paths.map((path) => { + const index = parseInt(path.replace(/[^0-9]/g, "")); + const isHardened = path.endsWith("'") || path.toLowerCase().endsWith("h"); + return new PathComponent({ index, hardened: isHardened }); + }), + Buffer.from(xfp, "hex") + ); + }); return new AvalancheSignRequest({ data, requestId: _requestId, - derivationPath: hdpathObject, + derivationPaths: derivationPaths, utxos: avalancheUtxos, }); } diff --git a/packages/ur-registry-avalanche/src/AvalancheSignature.ts b/packages/ur-registry-avalanche/src/AvalancheSignature.ts index df146e3d..3f43be2c 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignature.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignature.ts @@ -10,23 +10,23 @@ const { RegistryTypes, decodeToDataItem } = extend; enum Keys { requestId = 1, - signature, + signatures, } export class AvalancheSignature extends RegistryItem { private requestId?: Buffer; - private signature: Buffer; + private signatures: Buffer[]; getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_SIGNATURE; - constructor(signature: Buffer, requestId?: Buffer) { + constructor(signatures: Buffer[], requestId?: Buffer) { super(); - this.signature = signature; + this.signatures = Array.isArray(signatures) ? signatures : [signatures]; this.requestId = requestId; } public getRequestId = () => this.requestId; - public getSignature = () => this.signature; + public getSignatures = () => this.signatures; public toDataItem = () => { const map: DataItemMap = {}; @@ -36,19 +36,19 @@ export class AvalancheSignature extends RegistryItem { RegistryTypes.UUID.getTag() ); } - map[Keys.signature] = this.signature; + map[Keys.signatures] = this.signatures; return new DataItem(map); }; public static fromDataItem = (dataItem: DataItem) => { const map = dataItem.getData(); - const signature = map[Keys.signature]; + const signatures = map[Keys.signatures]; - return new AvalancheSignature(signature); + return new AvalancheSignature(signatures); }; public static fromCBOR = (_cborPayload: Buffer) => { const dataItem = decodeToDataItem(_cborPayload); return AvalancheSignature.fromDataItem(dataItem); }; -} +} \ No newline at end of file