From b17e8ccb96b1fa5ca3fbfce070ca81e439ea7bb4 Mon Sep 17 00:00:00 2001 From: Z4karia Date: Thu, 10 Oct 2024 14:17:06 +0200 Subject: [PATCH 1/5] feat: implement erc4361 msg in lib --- src/AcreBtcNew.ts | 28 ++++++++++++++++++++++++++++ src/newops/appClient.ts | 29 ++++++++++++++++++++++++++++- tests/newops/AcreBtcNew.test.ts | 20 ++++++++++++++++---- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/AcreBtcNew.ts b/src/AcreBtcNew.ts index 6d5d184..105b2b4 100644 --- a/src/AcreBtcNew.ts +++ b/src/AcreBtcNew.ts @@ -313,6 +313,7 @@ export default class AcreBtcNew { s, }; } + cleanHexPrefix(hexString: string): string { let cleanedHex = hexString.startsWith("0x") ? hexString.slice(2) : hexString; if (cleanedHex.length % 2 !== 0) { @@ -401,6 +402,33 @@ export default class AcreBtcNew { }; } + /** + * Signs a ERC4361 hex-formatted message with the private key at + * the provided derivation path according to the Bitcoin Signature format + * and returns v, r, s. + */ + async signERC4361Message({ path, messageHex }: { path: string; messageHex: string }): Promise<{ + v: number; + r: string; + s: string; + }> { + const pathElements: number[] = pathStringToArray(path); + const message = Buffer.from(messageHex, "hex"); + const sig = await this.client.signERC4361Message(message, pathElements); + console.log("sig", sig); + const buf = Buffer.from(sig, "base64"); + + const v = buf.readUInt8() - 27 - 4; + const r = buf.slice(1, 33).toString("hex"); + const s = buf.slice(33, 65).toString("hex"); + + return { + v, + r, + s, + }; + } + /** * Calculates an output script along with public key and possible redeemScript * from a path and accountType. The accountPath must be a prefix of path. diff --git a/src/newops/appClient.ts b/src/newops/appClient.ts index 52c84aa..b6509cd 100644 --- a/src/newops/appClient.ts +++ b/src/newops/appClient.ts @@ -20,7 +20,8 @@ enum BitcoinIns { SIGN_PSBT = 0x04, GET_MASTER_FINGERPRINT = 0x05, SIGN_MESSAGE = 0x10, - SIGN_WITHDRAW = 0x11 + SIGN_WITHDRAW = 0x11, + SIGN_ERC4361_MESSAGE = 0x12 } enum FrameworkIns { @@ -247,4 +248,30 @@ export class AppClient { return response.toString("base64") } + + async signERC4361Message(message: Buffer, pathElements: number[]): Promise { + if (pathElements.length > 6) { + throw new Error("Path too long. At most 6 levels allowed."); + } + + const clientInterpreter = new ClientCommandInterpreter(() => {}); + + // prepare ClientCommandInterpreter + const nChunks = Math.ceil(message.length / 64); + const chunks: Buffer[] = []; + for (let i = 0; i < nChunks; i++) { + chunks.push(message.subarray(64 * i, 64 * i + 64)); + } + + clientInterpreter.addKnownList(chunks); + const chunksRoot = new Merkle(chunks.map(m => hashLeaf(m))).getRoot(); + + const response = await this.makeRequest( + BitcoinIns.SIGN_ERC4361_MESSAGE, + Buffer.concat([pathElementsToBuffer(pathElements), createVarint(message.length), chunksRoot]), + clientInterpreter, + ); + + return response.toString("base64"); + } } diff --git a/tests/newops/AcreBtcNew.test.ts b/tests/newops/AcreBtcNew.test.ts index a948094..9cc9ea2 100644 --- a/tests/newops/AcreBtcNew.test.ts +++ b/tests/newops/AcreBtcNew.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { openTransportReplayer, RecordStore } from "@ledgerhq/hw-transport-mocker"; import { TransportReplayer } from "@ledgerhq/hw-transport-mocker/lib/openTransportReplayer"; +import SpeculosTransport from "../speculosTransport"; import ecc from "tiny-secp256k1"; import { getXpubComponents, pathArrayToString } from "../../src/bip32"; import AcreBtcNew from "../../src/AcreBtcNew"; @@ -57,9 +58,10 @@ test("testSignMessage", async () => { await testSignMessageReplayer("m/44'/0'/0'"); }); -test("signWithdrawal", async () => { - await testSignWithdrawalReplayer(); -}); + +test("Sign ERC-4361 message", async () => { + await testSignERC4361Speculos(); +}, 60 * 10 * 1000); // 10-minute timeout (60 seconds * 10 minutes * 1000 milliseconds) function testPaths(type: StandardPurpose): { ins: string[]; out?: string } { const basePath = `m/${type}/1'/0'/`; @@ -228,6 +230,16 @@ async function testSignWithdrawalReplayer() { }); } +async function testSignERC4361Speculos() { + const transport = new SpeculosTransport('http://localhost:5000') + const client = new AppClient(transport); + const acreBtcNew = new AcreBtcNew(client); + const message = "stake.acre.fi wants you to sign in with your Bitcoin account:\nbc1q8fq0vs2f9g52cuk8px9f664qs0j7vtmx3r7wvx\n\n\nURI: https://stake.acre.fi\nVersion: 1\nNonce: cw73Kfdfn1lY42Jj8\nIssued At: 2024-10-01T11:03:05.707Z\nExpiration Time: 2024-10-08T11:03:05.707Z" + const path = "m/44'/0'/0'/0/0"; + const result = await acreBtcNew.signERC4361Message({messageHex: Buffer.from(message).toString("hex"), path: path}); + console.log(result); +} + function verifyGetWalletPublicKeyResult( result: { publicKey: string; bitcoinAddress: string; chainCode: string }, expectedXpub: string, @@ -318,4 +330,4 @@ class MockClient extends TestingClient { ): string { return walletPolicy.serialize().toString("hex") + change + addressIndex; } -} +} \ No newline at end of file From dd94310976c565fcbc5fa6659d9b6cc593e9730e Mon Sep 17 00:00:00 2001 From: Z4karia Date: Tue, 15 Oct 2024 15:43:50 +0200 Subject: [PATCH 2/5] test: add test for erc4361 --- tests/newops/AcreBtcNew.test.ts | 27 +++++++++++++++++++-------- tests/newops/apdus.ts | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/tests/newops/AcreBtcNew.test.ts b/tests/newops/AcreBtcNew.test.ts index 9cc9ea2..45f296b 100644 --- a/tests/newops/AcreBtcNew.test.ts +++ b/tests/newops/AcreBtcNew.test.ts @@ -8,7 +8,7 @@ import AcreBtcNew from "../../src/AcreBtcNew"; import { DefaultDescriptorTemplate, WalletPolicy } from "../../src/newops/policy"; import { PsbtV2 } from "../../src/newops/psbtv2"; import { splitTransaction } from "../../src/splitTransaction"; -import { withdrawalAPDUs, signMessageAPDUs } from "./apdus"; +import { withdrawalAPDUs, signMessageAPDUs, signERC4361APDUs } from "./apdus"; import { StandardPurpose, addressFormatFromDescriptorTemplate, @@ -58,10 +58,13 @@ test("testSignMessage", async () => { await testSignMessageReplayer("m/44'/0'/0'"); }); +test("signWithdrawal", async () => { + await testSignWithdrawalReplayer(); +}); -test("Sign ERC-4361 message", async () => { - await testSignERC4361Speculos(); -}, 60 * 10 * 1000); // 10-minute timeout (60 seconds * 10 minutes * 1000 milliseconds) +test("Sign ERC4361 message", async () => { + await testSignERC4361MessageReplayer("m/44'/0'/0'"); +}); function testPaths(type: StandardPurpose): { ins: string[]; out?: string } { const basePath = `m/${type}/1'/0'/`; @@ -230,14 +233,22 @@ async function testSignWithdrawalReplayer() { }); } -async function testSignERC4361Speculos() { - const transport = new SpeculosTransport('http://localhost:5000') +async function testSignERC4361MessageReplayer( + accountPath: string, +) { + const transport = await openTransportReplayer(RecordStore.fromString(signERC4361APDUs)); const client = new AppClient(transport); + const path = accountPath + "/0/0"; + const acreBtcNew = new AcreBtcNew(client); const message = "stake.acre.fi wants you to sign in with your Bitcoin account:\nbc1q8fq0vs2f9g52cuk8px9f664qs0j7vtmx3r7wvx\n\n\nURI: https://stake.acre.fi\nVersion: 1\nNonce: cw73Kfdfn1lY42Jj8\nIssued At: 2024-10-01T11:03:05.707Z\nExpiration Time: 2024-10-08T11:03:05.707Z" - const path = "m/44'/0'/0'/0/0"; const result = await acreBtcNew.signERC4361Message({messageHex: Buffer.from(message).toString("hex"), path: path}); - console.log(result); + expect(result).toEqual({ + v: 1, + r: 'f30ff91331b840cc97560b468d9dce0647afbef7fd74819773721a096905da7e', + s: '664a3ce374f1951e40222d433cd8d6977dde08af6320acc8dd90fa35ed1c8ed8' + }); + } function verifyGetWalletPublicKeyResult( diff --git a/tests/newops/apdus.ts b/tests/newops/apdus.ts index b3b0835..24f379d 100644 --- a/tests/newops/apdus.ts +++ b/tests/newops/apdus.ts @@ -111,3 +111,24 @@ export const signMessageAPDUs = ` => f80100000705050074657374 <= 1fdf44ce2f8f6f62fec9b0d01bd66bc91aa73984e0cf02ad8ff7bf12f8013ba7796d8ed4d795a542509ec7f63539ec6521a3d61a29e4cf9c6d9a386b06b32f224b9000 `; + +export const signERC4361APDUs = ` + => e112000036058000002c80000000800000000000000000000000f714384fe48a178439d013364f5dda49f7996a5551e3c00727531906947ab21fc4 + <= 4114384fe48a178439d013364f5dda49f7996a5551e3c00727531906947ab21fc40400e000 + => f801000062ed3e2c87ab5f2018467fec3740401cb87241e888f037e374331ae85a1ba5a22702026d870786ec5cd40f6898c4a13b94f8d5bcb50b776a7e83f868779d1a6b0ed170b0448f3bddf3fbc48f3e6d029aa0e43d8b882fd0bd490a18a01699eb4d1397b3 + <= 4000ed3e2c87ab5f2018467fec3740401cb87241e888f037e374331ae85a1ba5a227e000 + => f8010000434141007374616b652e616372652e66692077616e747320796f7520746f207369676e20696e207769746820796f757220426974636f696e206163636f756e743a0a6263 + <= 4114384fe48a178439d013364f5dda49f7996a5551e3c00727531906947ab21fc40401e000 + => f8010000626d870786ec5cd40f6898c4a13b94f8d5bcb50b776a7e83f868779d1a6b0ed1700202ed3e2c87ab5f2018467fec3740401cb87241e888f037e374331ae85a1ba5a227b0448f3bddf3fbc48f3e6d029aa0e43d8b882fd0bd490a18a01699eb4d1397b3 + <= 40006d870786ec5cd40f6898c4a13b94f8d5bcb50b776a7e83f868779d1a6b0ed170e000 + => f801000043414100317138667130767332663967353263756b38707839663636347173306a3776746d783372377776780a0a0a5552493a2068747470733a2f2f7374616b652e6163 + <= 4114384fe48a178439d013364f5dda49f7996a5551e3c00727531906947ab21fc40402e000 + => f801000062b02d2a861a934a4c9b88de91a2e1c399da88b1023423fdf60d8df66374fa1b9602023e0f091cf7fe3103e1327a1f734f4a2982068f8e9b33dd397d55fbe850967d61021417016261f943d7a7d76b4dc93c9cdac00805ee05e14233439b768148e06a + <= 4000b02d2a861a934a4c9b88de91a2e1c399da88b1023423fdf60d8df66374fa1b96e000 + => f80100004341410072652e66690a56657273696f6e3a20310a4e6f6e63653a20637737334b6664666e316c5934324a6a380a4973737565642041743a20323032342d31302d303154 + <= 4114384fe48a178439d013364f5dda49f7996a5551e3c00727531906947ab21fc40403e000 + => f8010000623e0f091cf7fe3103e1327a1f734f4a2982068f8e9b33dd397d55fbe850967d610202b02d2a861a934a4c9b88de91a2e1c399da88b1023423fdf60d8df66374fa1b96021417016261f943d7a7d76b4dc93c9cdac00805ee05e14233439b768148e06a + <= 40003e0f091cf7fe3103e1327a1f734f4a2982068f8e9b33dd397d55fbe850967d61e000 + => f80100003a38380031313a30333a30352e3730375a0a45787069726174696f6e2054696d653a20323032342d31302d30385431313a30333a30352e3730375a + <= 20f30ff91331b840cc97560b468d9dce0647afbef7fd74819773721a096905da7e664a3ce374f1951e40222d433cd8d6977dde08af6320acc8dd90fa35ed1c8ed89000 + `; From e36985400176b5187d5992d96a949da4fe9c5b5e Mon Sep 17 00:00:00 2001 From: Z4karia Date: Tue, 15 Oct 2024 16:43:52 +0200 Subject: [PATCH 3/5] docs: update erc4361 docs --- README.md | 112 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 89cc991..f36af2c 100644 --- a/README.md +++ b/README.md @@ -57,26 +57,32 @@ For a smooth and quick integration: * [Parameters](#parameters-9) * [signWithdrawal](#signwithdrawal) * [Parameters](#parameters-10) + * [Examples](#examples-7) + * [signERC4361Message](#signerc4361message) + * [Parameters](#parameters-11) + * [Examples](#examples-8) * [AcreBtcNew](#acrebtcnew) * [getWalletXpub](#getwalletxpub-1) - * [Parameters](#parameters-11) - * [getWalletPublicKey](#getwalletpublickey-1) * [Parameters](#parameters-12) - * [createPaymentTransaction](#createpaymenttransaction-1) + * [getWalletPublicKey](#getwalletpublickey-1) * [Parameters](#parameters-13) - * [signMessage](#signmessage-1) + * [createPaymentTransaction](#createpaymenttransaction-1) * [Parameters](#parameters-14) - * [signWithdrawal](#signwithdrawal-1) + * [signMessage](#signmessage-1) * [Parameters](#parameters-15) + * [signWithdrawal](#signwithdrawal-1) + * [Parameters](#parameters-16) + * [signERC4361Message](#signerc4361message-1) + * [Parameters](#parameters-17) * [descrTemplFrom](#descrtemplfrom) - * [Parameters](#parameters-16) + * [Parameters](#parameters-18) * [AcreBtcOld](#acrebtcold) * [getWalletPublicKey](#getwalletpublickey-2) - * [Parameters](#parameters-17) - * [Examples](#examples-7) + * [Parameters](#parameters-19) + * [Examples](#examples-9) * [createPaymentTransaction](#createpaymenttransaction-2) - * [Parameters](#parameters-18) - * [Examples](#examples-8) + * [Parameters](#parameters-20) + * [Examples](#examples-10) * [CreateTransactionArg](#createtransactionarg) * [Properties](#properties) * [AddressFormat](#addressformat) @@ -84,39 +90,39 @@ For a smooth and quick integration: * [Properties](#properties-1) * [AccountType](#accounttype) * [spendingCondition](#spendingcondition) - * [Parameters](#parameters-19) + * [Parameters](#parameters-21) * [setInput](#setinput) - * [Parameters](#parameters-20) + * [Parameters](#parameters-22) * [setOwnOutput](#setownoutput) - * [Parameters](#parameters-21) + * [Parameters](#parameters-23) * [getDescriptorTemplate](#getdescriptortemplate) * [SingleKeyAccount](#singlekeyaccount) * [getTaprootOutputKey](#gettaprootoutputkey) - * [Parameters](#parameters-22) + * [Parameters](#parameters-24) * [AppClient](#appclient) - * [Parameters](#parameters-23) + * [Parameters](#parameters-25) * [ClientCommandInterpreter](#clientcommandinterpreter) - * [Parameters](#parameters-24) + * [Parameters](#parameters-26) * [MerkelizedPsbt](#merkelizedpsbt) - * [Parameters](#parameters-25) + * [Parameters](#parameters-27) * [Merkle](#merkle) - * [Parameters](#parameters-26) + * [Parameters](#parameters-28) * [MerkleMap](#merklemap) - * [Parameters](#parameters-27) + * [Parameters](#parameters-29) * [WalletPolicy](#walletpolicy) - * [Parameters](#parameters-28) + * [Parameters](#parameters-30) * [extract](#extract) - * [Parameters](#parameters-29) + * [Parameters](#parameters-31) * [finalize](#finalize) - * [Parameters](#parameters-30) + * [Parameters](#parameters-32) * [clearFinalizedInput](#clearfinalizedinput) - * [Parameters](#parameters-31) + * [Parameters](#parameters-33) * [writePush](#writepush) - * [Parameters](#parameters-32) + * [Parameters](#parameters-34) * [PsbtV2](#psbtv2) * [serializeTransactionOutputs](#serializetransactionoutputs-1) - * [Parameters](#parameters-33) - * [Examples](#examples-9) + * [Parameters](#parameters-35) + * [Examples](#examples-11) * [SignP2SHTransactionArg](#signp2shtransactionarg) * [Properties](#properties-2) * [TransactionInput](#transactioninput) @@ -353,8 +359,6 @@ and returns v, r, s. * `$0.path` * `$0.withdrawalData` -Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{v: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), r: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), s: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** - ##### Examples ```javascript @@ -377,6 +381,31 @@ Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/ }).catch(function(ex) {console.log(ex);}); ``` +#### signERC4361Message + +Signs an Ethereum Sign-In (ERC-4361) message with the private key at +the provided derivation path according to the Bitcoin Signature format +and returns v, r, s. + +##### Parameters + +* `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** +* `messageHex` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** + +##### Examples + +```javascript +acre.signERC4361Message("44'/60'/0'/0'/0", Buffer.from("Example ERC-4361 message").toString("hex")).then(function(result) { + const v = result['v'] + 27 + 4; + const signature = Buffer.from(v.toString(16) + result['r'] + result['s'], 'hex').toString('base64'); + console.log("Signature : " + signature); +}).catch(function(ex) {console.log(ex);}); +``` + +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{v: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), r: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), s: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** + +**Note:** The message is restricted to maximum 128 character lines. + Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{v: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), r: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), s: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** @@ -492,27 +521,28 @@ and returns v, r, s. Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{v: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), r: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), s: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** -### descrTemplFrom +#### signERC4361Message -This function returns a descriptor template based on the address format. -See for details of -the bitcoin descriptor template. +Signs an ERC-4361 (Sign-In with Ethereum) formatted message with the private key at +the provided derivation path according to the Bitcoin Signature format +and returns v, r, s. -#### Parameters +##### Parameters -* `addressFormat` **[AddressFormat](#addressformat)** +* `$0` **{path: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), messageHex: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}** -Returns **DefaultDescriptorTemplate** + * `$0.path` The BIP32 derivation path of the key to use for signing + * `$0.messageHex` The ERC-4361 formatted message to sign, in hexadecimal format -### AcreBtcOld +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{v: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), r: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), s: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)}>** -This old API is compatible with versions of the Bitcoin nano app that are earlier than 2.1.0 . -It is never used by Acre, that is based on the latest Bitcoin nano app (2.1.0+). -This class is kept for compatibility purposes. +### descrTemplFrom -#### getWalletPublicKey +This function returns a descriptor template based on the address format. +See for details of +the bitcoin descriptor template. -##### Parameters +#### Parameters * `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** a BIP 32 path * `opts` **{verify: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?, format: [AddressFormat](#addressformat)?}?** From 23eec7440b036a60bf11d51f04155ad8f2c42104 Mon Sep 17 00:00:00 2001 From: Z4karia Date: Tue, 15 Oct 2024 20:04:20 +0200 Subject: [PATCH 4/5] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1675c9..81b4cb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blooo/hw-app-acre", - "version": "1.0.1", + "version": "1.1.0", "description": "Ledger Hardware Wallet Acre Application API", "keywords": [ "Ledger", From bfde79101790cefbb4ffc782ffb2498a327be7fd Mon Sep 17 00:00:00 2001 From: Z4karia Date: Wed, 16 Oct 2024 18:25:36 +0200 Subject: [PATCH 5/5] remove debug console.logs --- src/AcreBtcNew.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/AcreBtcNew.ts b/src/AcreBtcNew.ts index 105b2b4..c7ad0a3 100644 --- a/src/AcreBtcNew.ts +++ b/src/AcreBtcNew.ts @@ -323,8 +323,6 @@ export default class AcreBtcNew { } formatAcreWithdrawalData(withdrawalData: AcreWithdrawalData): AcreWithdrawalDataBuffer { - console.log("withdrawalData", withdrawalData); - console.log("dataLength", withdrawalData.data.length); const to = Buffer.from(this.cleanHexPrefix(withdrawalData.to.toString()), "hex").slice(-20); let withdrawalValueBuffer = Buffer.from(this.cleanHexPrefix(withdrawalData.value), "hex").slice(-32); @@ -386,7 +384,6 @@ export default class AcreBtcNew { }> { const pathElements: number[] = pathStringToArray(path); const withdrawalDataBuffer = this.formatAcreWithdrawalData(withdrawalData); - console.log("withdrawalDataBuffer", withdrawalDataBuffer); const sig = await this.client.signWithdrawal(pathElements, withdrawalDataBuffer); const buf = Buffer.from(sig, "base64"); @@ -415,7 +412,6 @@ export default class AcreBtcNew { const pathElements: number[] = pathStringToArray(path); const message = Buffer.from(messageHex, "hex"); const sig = await this.client.signERC4361Message(message, pathElements); - console.log("sig", sig); const buf = Buffer.from(sig, "base64"); const v = buf.readUInt8() - 27 - 4;