From 6ac1c207b7ce2f307b50ac1d35f57d4cc29d9907 Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 15 Dec 2025 09:42:55 +0800 Subject: [PATCH 1/7] feat: update core wallet new path --- .../src/AvalancheSignRequest.ts | 42 +++++-------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts index b469a03b..c33ce2d5 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts @@ -3,6 +3,7 @@ import { RegistryItem, extend, DataItemMap, + CryptoKeypath, } from "@keystonehq/bc-ur-registry"; import { ExtendedRegistryTypes } from "./RegistryType"; import * as uuid from "uuid"; @@ -12,25 +13,18 @@ const { RegistryTypes } = extend; type signRequestProps = { requestId?: Buffer; data: Buffer; - mfp: Buffer; - xpub: string; - walletIndex: number; + derivationPath: CryptoKeypath; }; enum Keys { requestId = 1, signData = 2, - mfp = 3, - xpub = 6, - walletIndex = 7, + derivationPath = 3, } - export class AvalancheSignRequest extends RegistryItem { private requestId?: Buffer; private data: Buffer; - private mfp: Buffer; - private xpub: string; - private walletIndex: number; + private derivationPath: CryptoKeypath; getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_SIGN_REQUEST; @@ -38,9 +32,7 @@ export class AvalancheSignRequest extends RegistryItem { super(); this.requestId = args.requestId; this.data = args.data; - this.mfp = args.mfp; - this.xpub = args.xpub; - this.walletIndex = args.walletIndex; + this.derivationPath = args.derivationPath; } public getRequestId = () => this.requestId; @@ -56,40 +48,30 @@ export class AvalancheSignRequest extends RegistryItem { } map[Keys.signData] = Buffer.from(this.data); - map[Keys.mfp] = this.mfp.readUInt32BE(0); - map[Keys.xpub] = this.xpub; - map[Keys.walletIndex] = Number(this.walletIndex); + map[Keys.derivationPath] = this.derivationPath; return new DataItem(map); }; public static fromDataItem = (dataItem: DataItem) => { const map = dataItem.getData(); - const masterFingerprint = Buffer.alloc(4); - const _masterFingerprint = map[Keys.mfp]; - masterFingerprint.writeUInt32BE(_masterFingerprint, 0); const requestId = map[Keys.requestId] ? map[Keys.requestId].getData() : undefined; const data = map[Keys.signData]; - const xpub = map[Keys.xpub]; - const walletIndex = map[Keys.signData]; + const derivationPath = map[Keys.signData]; return new AvalancheSignRequest({ requestId, data, - xpub, - walletIndex, - mfp: masterFingerprint, + derivationPath, }); }; public static constructAvalancheRequest( data: Buffer, - mfp: string, - xpub: string, - walletIndex: number, - requestId?: string | Buffer + derivationPath: CryptoKeypath, + requestId?: string | Buffer, ) { let _requestId; if (typeof requestId === "string") { @@ -103,9 +85,7 @@ export class AvalancheSignRequest extends RegistryItem { return new AvalancheSignRequest({ data, requestId: _requestId, - mfp: Buffer.from(mfp, "hex"), - xpub, - walletIndex, + derivationPath }); } } From 4acaf5a38e44338558349fac204c15cf981fe3bb Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 15 Dec 2025 14:14:23 +0800 Subject: [PATCH 2/7] feat: add AvalanceUtxo --- .../ur-registry-avalanche/src/AvalanceUtxo.ts | 127 ++++++++++++++++++ .../src/AvalancheSignRequest.ts | 28 +++- .../ur-registry-avalanche/src/RegistryType.ts | 1 + 3 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 packages/ur-registry-avalanche/src/AvalanceUtxo.ts diff --git a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts new file mode 100644 index 00000000..7bcbbbf9 --- /dev/null +++ b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts @@ -0,0 +1,127 @@ +import { + CryptoKeypath, + extend, + DataItem, + PathComponent, + RegistryItem, + DataItemMap, + } from "@keystonehq/bc-ur-registry"; + import { ExtendedRegistryTypes } from "./RegistryType"; + + const { decodeToDataItem } = extend; + + enum Keys { + txid = 1, + value, + vout, + path, + address, + } + + export interface AvalanceUtxoProps { + txid: Buffer; + value: string; + vout: number; + path: CryptoKeypath; + address: string; + } + + export interface AvalanceUtxoData { + txid: string; + value: string; + vout: number; + path: string; + address: string; + xfp: string; + } + + export class AvalanceUtxo extends RegistryItem { + private txid: Buffer; + private value: string; + private vout: number; + private path: CryptoKeypath; + private address: string; + + getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_UTXO; + + constructor(args: AvalanceUtxoProps) { + super(); + this.txid = args.txid; + this.value = args.value; + this.vout = args.vout; + this.path = args.path; + this.address = args.address; + } + + public getTxid = () => this.txid; + public getVout = () => this.vout; + public getKeyPath = () => this.path.getPath(); + public getValue = () => this.value; + public getAddress = () => this.address; + + public toDataItem = () => { + const map: DataItemMap = {}; + if (this.txid) { + map[Keys.txid] = this.txid; + } + map[Keys.vout] = this.vout; + map[Keys.value] = this.value; + + const keyPath = this.path.toDataItem(); + keyPath.setTag(this.path.getRegistryType().getTag()); + map[Keys.path] = keyPath; + + map[Keys.address] = this.address; + return new DataItem(map); + }; + + public static fromDataItem = (dataItem: DataItem) => { + const map = dataItem.getData(); + const txid = map[Keys.txid]; + const vout = map[Keys.vout]; + const path = CryptoKeypath.fromDataItem(map[Keys.path]); + const address = map[Keys.address]; + const value = map[Keys.value]; + + return new AvalanceUtxo({ + txid, + vout, + value, + path, + address, + }); + }; + + public static fromCBOR = (_cborPayload: Buffer) => { + const dataItem = decodeToDataItem(_cborPayload); + return AvalanceUtxo.fromDataItem(dataItem); + }; + + public static constructAvalanceUtxo({ + txid, + vout, + value, + xfp, + path, + address, + }: AvalanceUtxoData) { + const paths = path.replace(/[m|M]\//, "").split("/"); + const hdPathObject = new CryptoKeypath( + paths.map((path) => { + const index = parseInt(path.replace("'", "")); + const isHardened = path.endsWith("'"); + return new PathComponent({ index, hardened: isHardened }); + }), + Buffer.from(xfp, "hex") + ); + + return new AvalanceUtxo({ + txid: Buffer.from(txid, "hex"), + vout, + value, + path: hdPathObject, + address, + }); + } + } + \ No newline at end of file diff --git a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts index c33ce2d5..9c04d385 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts @@ -7,6 +7,7 @@ import { } from "@keystonehq/bc-ur-registry"; import { ExtendedRegistryTypes } from "./RegistryType"; import * as uuid from "uuid"; +import { AvalanceUtxo, AvalanceUtxoData } from "./AvalanceUtxo"; const { RegistryTypes } = extend; @@ -14,17 +15,21 @@ type signRequestProps = { requestId?: Buffer; data: Buffer; derivationPath: CryptoKeypath; + utxos: AvalanceUtxo[]; }; enum Keys { requestId = 1, - signData = 2, - derivationPath = 3, + signData, + derivationPath, + utxos, } export class AvalancheSignRequest extends RegistryItem { private requestId?: Buffer; private data: Buffer; private derivationPath: CryptoKeypath; + private utxos: AvalanceUtxo[]; + getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_SIGN_REQUEST; @@ -33,10 +38,13 @@ export class AvalancheSignRequest extends RegistryItem { this.requestId = args.requestId; this.data = args.data; this.derivationPath = args.derivationPath; + this.utxos = args.utxos; } public getRequestId = () => this.requestId; public getSignData = () => this.data; + public getUtxos = () => this.utxos; + public getDerivationPath = () => this.derivationPath; public toDataItem = () => { const map: DataItemMap = {}; @@ -49,6 +57,11 @@ export class AvalancheSignRequest extends RegistryItem { map[Keys.signData] = Buffer.from(this.data); map[Keys.derivationPath] = this.derivationPath; + map[Keys.utxos] = this.utxos.map((utxo) => { + const res = utxo.toDataItem(); + res.setTag(utxo.getRegistryType().getTag()); + return res; + }); return new DataItem(map); }; @@ -60,17 +73,22 @@ export class AvalancheSignRequest extends RegistryItem { : undefined; const data = map[Keys.signData]; const derivationPath = map[Keys.signData]; + const utxos: AvalanceUtxo[] = map[Keys.utxos].map((utxo: DataItem) => + AvalanceUtxo.fromDataItem(utxo) + ); return new AvalancheSignRequest({ requestId, data, derivationPath, + utxos, }); }; public static constructAvalancheRequest( data: Buffer, derivationPath: CryptoKeypath, + utxos: AvalanceUtxoData[], requestId?: string | Buffer, ) { let _requestId; @@ -81,11 +99,15 @@ export class AvalancheSignRequest extends RegistryItem { } else { _requestId = Buffer.from(uuid.parse(uuid.v4()) as Uint8Array); } + const avalanceUtxos = utxos.map((utxo) => + AvalanceUtxo.constructAvalanceUtxo(utxo) + ); return new AvalancheSignRequest({ data, requestId: _requestId, - derivationPath + derivationPath, + utxos: avalanceUtxos, }); } } diff --git a/packages/ur-registry-avalanche/src/RegistryType.ts b/packages/ur-registry-avalanche/src/RegistryType.ts index b132b902..110eb5b1 100644 --- a/packages/ur-registry-avalanche/src/RegistryType.ts +++ b/packages/ur-registry-avalanche/src/RegistryType.ts @@ -3,4 +3,5 @@ import { RegistryType } from "@keystonehq/bc-ur-registry"; export const ExtendedRegistryTypes = { AVALANCHE_SIGN_REQUEST: new RegistryType("avax-sign-request", 8301), AVALANCHE_SIGNATURE: new RegistryType("avax-signature", 8302), + AVALANCHE_UTXO: new RegistryType("avax-utxo", 8303), }; From 10dcf0396be7dda05489685e3cc1a2cd2fa1e636 Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 15 Dec 2025 14:19:48 +0800 Subject: [PATCH 3/7] feat: update AvalanceUtxo txid --- packages/ur-registry-avalanche/src/AvalanceUtxo.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts index 7bcbbbf9..0b8e2993 100644 --- a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts +++ b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts @@ -61,9 +61,7 @@ import { public toDataItem = () => { const map: DataItemMap = {}; - if (this.txid) { - map[Keys.txid] = this.txid; - } + map[Keys.txid] = this.txid; map[Keys.vout] = this.vout; map[Keys.value] = this.value; From 06b2afdf325acb308552ed9f5dbaf4142465efe7 Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 15 Dec 2025 14:50:23 +0800 Subject: [PATCH 4/7] feat: update AvalanceUtxo fields --- .../ur-registry-avalanche/src/AvalanceUtxo.ts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts index 0b8e2993..b3d45178 100644 --- a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts +++ b/packages/ur-registry-avalanche/src/AvalanceUtxo.ts @@ -12,64 +12,50 @@ import { enum Keys { txid = 1, - value, vout, path, - address, } export interface AvalanceUtxoProps { txid: Buffer; - value: string; vout: number; path: CryptoKeypath; - address: string; } export interface AvalanceUtxoData { txid: string; - value: string; vout: number; path: string; - address: string; xfp: string; } export class AvalanceUtxo extends RegistryItem { private txid: Buffer; - private value: string; private vout: number; private path: CryptoKeypath; - private address: string; getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_UTXO; constructor(args: AvalanceUtxoProps) { super(); this.txid = args.txid; - this.value = args.value; this.vout = args.vout; this.path = args.path; - this.address = args.address; } public getTxid = () => this.txid; public getVout = () => this.vout; public getKeyPath = () => this.path.getPath(); - public getValue = () => this.value; - public getAddress = () => this.address; public toDataItem = () => { const map: DataItemMap = {}; map[Keys.txid] = this.txid; map[Keys.vout] = this.vout; - map[Keys.value] = this.value; const keyPath = this.path.toDataItem(); keyPath.setTag(this.path.getRegistryType().getTag()); map[Keys.path] = keyPath; - map[Keys.address] = this.address; return new DataItem(map); }; @@ -78,15 +64,11 @@ import { const txid = map[Keys.txid]; const vout = map[Keys.vout]; const path = CryptoKeypath.fromDataItem(map[Keys.path]); - const address = map[Keys.address]; - const value = map[Keys.value]; return new AvalanceUtxo({ txid, vout, - value, path, - address, }); }; @@ -98,10 +80,8 @@ import { public static constructAvalanceUtxo({ txid, vout, - value, xfp, path, - address, }: AvalanceUtxoData) { const paths = path.replace(/[m|M]\//, "").split("/"); const hdPathObject = new CryptoKeypath( @@ -116,9 +96,7 @@ import { return new AvalanceUtxo({ txid: Buffer.from(txid, "hex"), vout, - value, path: hdPathObject, - address, }); } } From a22a6def6b876dc0888d999b57bc59d3992920dd Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 22 Dec 2025 09:49:30 +0800 Subject: [PATCH 5/7] feat: update AvalancheUtxo --- .../src/AvalancheSignRequest.ts | 18 ++++++++-------- .../src/{AvalanceUtxo.ts => AvalancheUtxo.ts} | 21 ++++++++----------- 2 files changed, 18 insertions(+), 21 deletions(-) rename packages/ur-registry-avalanche/src/{AvalanceUtxo.ts => AvalancheUtxo.ts} (83%) diff --git a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts index 9c04d385..7e066f45 100644 --- a/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts +++ b/packages/ur-registry-avalanche/src/AvalancheSignRequest.ts @@ -7,7 +7,7 @@ import { } from "@keystonehq/bc-ur-registry"; import { ExtendedRegistryTypes } from "./RegistryType"; import * as uuid from "uuid"; -import { AvalanceUtxo, AvalanceUtxoData } from "./AvalanceUtxo"; +import { AvalancheUtxo, AvalancheUtxoData } from "./AvalancheUtxo"; const { RegistryTypes } = extend; @@ -15,7 +15,7 @@ type signRequestProps = { requestId?: Buffer; data: Buffer; derivationPath: CryptoKeypath; - utxos: AvalanceUtxo[]; + utxos: AvalancheUtxo[]; }; enum Keys { @@ -28,7 +28,7 @@ export class AvalancheSignRequest extends RegistryItem { private requestId?: Buffer; private data: Buffer; private derivationPath: CryptoKeypath; - private utxos: AvalanceUtxo[]; + private utxos: AvalancheUtxo[]; getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_SIGN_REQUEST; @@ -73,8 +73,8 @@ export class AvalancheSignRequest extends RegistryItem { : undefined; const data = map[Keys.signData]; const derivationPath = map[Keys.signData]; - const utxos: AvalanceUtxo[] = map[Keys.utxos].map((utxo: DataItem) => - AvalanceUtxo.fromDataItem(utxo) + const utxos: AvalancheUtxo[] = map[Keys.utxos].map((utxo: DataItem) => + AvalancheUtxo.fromDataItem(utxo) ); return new AvalancheSignRequest({ @@ -88,7 +88,7 @@ export class AvalancheSignRequest extends RegistryItem { public static constructAvalancheRequest( data: Buffer, derivationPath: CryptoKeypath, - utxos: AvalanceUtxoData[], + utxos: AvalancheUtxoData[], requestId?: string | Buffer, ) { let _requestId; @@ -99,15 +99,15 @@ export class AvalancheSignRequest extends RegistryItem { } else { _requestId = Buffer.from(uuid.parse(uuid.v4()) as Uint8Array); } - const avalanceUtxos = utxos.map((utxo) => - AvalanceUtxo.constructAvalanceUtxo(utxo) + const avalancheUtxos = utxos.map((utxo) => + AvalancheUtxo.constructAvalancheUtxo(utxo) ); return new AvalancheSignRequest({ data, requestId: _requestId, derivationPath, - utxos: avalanceUtxos, + utxos: avalancheUtxos, }); } } diff --git a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts b/packages/ur-registry-avalanche/src/AvalancheUtxo.ts similarity index 83% rename from packages/ur-registry-avalanche/src/AvalanceUtxo.ts rename to packages/ur-registry-avalanche/src/AvalancheUtxo.ts index b3d45178..cf7198d4 100644 --- a/packages/ur-registry-avalanche/src/AvalanceUtxo.ts +++ b/packages/ur-registry-avalanche/src/AvalancheUtxo.ts @@ -16,27 +16,26 @@ import { path, } - export interface AvalanceUtxoProps { + export interface AvalancheUtxoProps { txid: Buffer; vout: number; path: CryptoKeypath; } - export interface AvalanceUtxoData { + export interface AvalancheUtxoData { txid: string; vout: number; path: string; - xfp: string; } - export class AvalanceUtxo extends RegistryItem { + export class AvalancheUtxo extends RegistryItem { private txid: Buffer; private vout: number; private path: CryptoKeypath; getRegistryType = () => ExtendedRegistryTypes.AVALANCHE_UTXO; - constructor(args: AvalanceUtxoProps) { + constructor(args: AvalancheUtxoProps) { super(); this.txid = args.txid; this.vout = args.vout; @@ -65,7 +64,7 @@ import { const vout = map[Keys.vout]; const path = CryptoKeypath.fromDataItem(map[Keys.path]); - return new AvalanceUtxo({ + return new AvalancheUtxo({ txid, vout, path, @@ -74,15 +73,14 @@ import { public static fromCBOR = (_cborPayload: Buffer) => { const dataItem = decodeToDataItem(_cborPayload); - return AvalanceUtxo.fromDataItem(dataItem); + return AvalancheUtxo.fromDataItem(dataItem); }; - public static constructAvalanceUtxo({ + public static constructAvalancheUtxo({ txid, vout, - xfp, path, - }: AvalanceUtxoData) { + }: AvalancheUtxoData) { const paths = path.replace(/[m|M]\//, "").split("/"); const hdPathObject = new CryptoKeypath( paths.map((path) => { @@ -90,10 +88,9 @@ import { const isHardened = path.endsWith("'"); return new PathComponent({ index, hardened: isHardened }); }), - Buffer.from(xfp, "hex") ); - return new AvalanceUtxo({ + return new AvalancheUtxo({ txid: Buffer.from(txid, "hex"), vout, path: hdPathObject, From 9b03a79738bdff1c018916fd64b003406da0e7a9 Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 5 Jan 2026 10:56:17 +0800 Subject: [PATCH 6/7] feat: update package version --- packages/ur-registry-avalanche/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ur-registry-avalanche/package.json b/packages/ur-registry-avalanche/package.json index 6a36f9e1..6ac32224 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.0.5", + "version": "0.0.6", "description": "bc-ur-registry extension for Avalanche", "main": "dist/index.cjs", "module": "dist/index.mjs", From 94eac2aac0627cfe5a4f5321da708ea64e884d2f Mon Sep 17 00:00:00 2001 From: qkin Date: Mon, 5 Jan 2026 13:10:40 +0800 Subject: [PATCH 7/7] feat: update test case --- .../__tests__/AvalancheSignRequest.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts index a77ad7b2..5fc95548 100644 --- a/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts +++ b/packages/ur-registry-avalanche/__tests__/AvalancheSignRequest.test.ts @@ -8,16 +8,14 @@ describe("avalanche-sign-request", () => { "00000000000000000001ed5f38341e436e5d46e2bb00b45d62ae97d1b050c64bc634ae10626739e35c4b0000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff00000007000000000089544000000000000000000000000100000001512e7191685398f00663e12197a3d8f6012d9ea300000001db720ad6707915cc4751fb7e5491a3af74e127a1d81817abe9438590c0833fe10000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000000000989680000000010000000000000000", "hex" ); - const mfp = "1250B6BC"; - const xpub = - "xpub661MyMwAqRbcFFDMuFiGQmA1EqWxxgDLdtNvxxiucf9qkfoVrvwgnYyshxWoewWtkZ1aLhKoVDrpeDvn1YRqxX2szhGKi3UiSEv1hYRMF8q"; - const walletIndex = 0; + const derivationPath = "m/44'/133'/0'/0/0"; + const utxos = []; + const avalancheSignRequest = AvalancheSignRequest.constructAvalancheRequest( avalancheData, - mfp, - xpub, - walletIndex + derivationPath, + utxos ); const request = AvalancheSignRequest.fromDataItem(