diff --git a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts index 5fc9554..4dfcc9e 100644 --- a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts +++ b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts @@ -1,42 +1,61 @@ // @ts-nocheck import { AvalancheSignRequest, AvalancheSignature } from "../src"; +import { UREncoder } from "@ngraveio/bc-ur"; describe("avalanche-sign-request", () => { it("test should generate avalanche-sign-reqeust", () => { const avalancheData = Buffer.from( - "00000000000000000001ed5f38341e436e5d46e2bb00b45d62ae97d1b050c64bc634ae10626739e35c4b0000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000089544000000000000000000000000100000001512e7191685398f00663e12197a3d8f6012d9ea300000001db720ad6707915cc4751fb7e5491a3af74e127a1d81817abe9438590c0833fe10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000000000989680000000010000000000000000", + "0000000000220000000100000000000000000000000000000000000000000000000000000000000000000000000221e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000031cb3a00000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c521e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000000005dabac900000000000000000000000100000001b5e66be5c7093d1114d74940333c0c45f81092c500000008120d0def706b8b759935b8ea9727662aafa5381e598a074daddc82492549cd760000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000046239d0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000131021c0000000100000000174d1a9b28e1d4d518f1999d4f8ac422b8a3a4755001f5965e8d05c93359feb10000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000176b6a5000000010000000065a3b1de10620296debfa01aa953e45ddd19d2c39e3dacb9a92e6a85ca8a309c0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000098968000000001000000006f6522ae52b0231076dc63ff95f7ea22e2fd80943e37235302c7ee32afce4cd60000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000009896800000000100000000845649c3d1a630d8b466f7b727f6577cb4a17864699e6de756e484b81d84cd2a0000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000006c2b440000000100000000d1e6480c1825197e2ec293a60bacdc7f60bfba2f3cc5383855180b45d595a7030000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff0000000500000000007a12000000000100000000f59b9a175ebe4ccd8de5dcfc6a26870414f30c696cce19283f30145624b445b70000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000005000000000107a493000000010000000000000000", "hex" ); - const derivationPath = "m/44'/133'/0'/0/0"; + const derivationPath = ["m/44'/9000'/0'/0/0","m/44'/9000'/0'/0/1"]; const utxos = []; - + const xfp = '2d0bdabc' const avalancheSignRequest = AvalancheSignRequest.constructAvalancheRequest( avalancheData, derivationPath, - utxos + utxos, + xfp ); + console.log('-----avalancheSignRequest--------',avalancheSignRequest.toCBOR().toString('hex')) + const ur = avalancheSignRequest.toUR(); + const encoder = new UREncoder(ur, Infinity); + console.log('----- Full UR String -----'); + console.log(encoder.nextPart().toUpperCase()); const request = AvalancheSignRequest.fromDataItem( avalancheSignRequest.toDataItem() ); + const paths = request.getDerivationPaths(); + expect(paths).toBeDefined(); + expect(paths.length).toBe(2); + + 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( - "00000000000000000001ed5f38341e436e5d46e2bb00b45d62ae97d1b050c64bc634ae10626739e35c4b0000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000089544000000000000000000000000100000001512e7191685398f00663e12197a3d8f6012d9ea300000001db720ad6707915cc4751fb7e5491a3af74e127a1d81817abe9438590c0833fe10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000000000989680000000010000000000000000" + "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/package.json b/packages/ur-registry-avalanche/package.json index 6ed3e32..b68b04c 100644 --- a/packages/ur-registry-avalanche/package.json +++ b/packages/ur-registry-avalanche/package.json @@ -1,6 +1,6 @@ { "name": "@keystonehq/bc-ur-registry-avalanche", - "version": "0.1.0", + "version": "0.1.4", "description": "bc-ur-registry extension for Avalanche", "main": "dist/index.cjs", "module": "dist/index.mjs", diff --git a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts index 7e066f4..d8e6288 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts @@ -4,6 +4,7 @@ import { extend, DataItemMap, CryptoKeypath, + PathComponent, } from "@keystonehq/bc-ur-registry"; import { ExtendedRegistryTypes } from "./RegistryType"; import * as uuid from "uuid"; @@ -14,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[]; @@ -37,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 = {}; @@ -56,7 +57,13 @@ export class AvalancheSignRequest extends RegistryItem { } map[Keys.signData] = Buffer.from(this.data); - map[Keys.derivationPath] = this.derivationPath; + + 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(); res.setTag(utxo.getRegistryType().getTag()); @@ -72,7 +79,9 @@ export class AvalancheSignRequest extends RegistryItem { ? map[Keys.requestId].getData() : undefined; const data = map[Keys.signData]; - const derivationPath = map[Keys.signData]; + const derivationPaths: CryptoKeypath[] = map[Keys.derivationPaths].map( + (item: DataItem) => CryptoKeypath.fromDataItem(item) + ); const utxos: AvalancheUtxo[] = map[Keys.utxos].map((utxo: DataItem) => AvalancheUtxo.fromDataItem(utxo) ); @@ -80,16 +89,17 @@ export class AvalancheSignRequest extends RegistryItem { return new AvalancheSignRequest({ requestId, data, - derivationPath, + derivationPaths, utxos, }); }; public static constructAvalancheRequest( data: Buffer, - derivationPath: CryptoKeypath, + hdPaths: string[], utxos: AvalancheUtxoData[], - requestId?: string | Buffer, + xfp: string, + requestId?: string | Buffer ) { let _requestId; if (typeof requestId === "string") { @@ -99,14 +109,27 @@ export class AvalancheSignRequest extends RegistryItem { } else { _requestId = Buffer.from(uuid.parse(uuid.v4()) as Uint8Array); } + const avalancheUtxos = utxos.map((utxo) => AvalancheUtxo.constructAvalancheUtxo(utxo) ); + 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, + derivationPaths: derivationPaths, utxos: avalancheUtxos, }); } diff --git a/packages/ur-registry-avalanche/src/AvalancheSignature.ts b/packages/ur-registry-avalanche/src/AvalancheSignature.ts index df146e3..3f43be2 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