@shapeshiftoss/hdwallet-gridplus 1.62.9 → 1.62.10-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ethereum.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Common, Hardfork } from "@ethereumjs/common";
2
- import { TransactionFactory, TypedTxData } from "@ethereumjs/tx";
2
+ import { RLP } from "@ethereumjs/rlp";
3
+ import { TransactionFactory, TransactionType, TypedTxData } from "@ethereumjs/tx";
3
4
  import * as core from "@shapeshiftoss/hdwallet-core";
4
5
  import { Client, Constants, Utils } from "gridplus-sdk";
5
- import { encode } from "rlp";
6
6
 
7
7
  export async function ethGetAddress(client: Client, msg: core.ETHGetAddress): Promise<core.Address | null> {
8
8
  const address = (await client.getAddresses({ startPath: msg.addressNList, n: 1 }))[0];
@@ -23,37 +23,23 @@ export async function ethSignTx(client: Client, msg: core.ETHSignTx): Promise<co
23
23
  nonce: msg.nonce,
24
24
  gasLimit: msg.gasLimit,
25
25
  chainId: msg.chainId,
26
- // Add explicit type field for TransactionFactory to correctly detect transaction type
27
- type: isEIP1559 ? 2 : 0,
28
- ...(isEIP1559
29
- ? {
30
- maxFeePerGas: msg.maxFeePerGas,
31
- maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
32
- }
33
- : {
34
- gasPrice: msg.gasPrice,
35
- }),
26
+ type: isEIP1559 ? TransactionType.FeeMarketEIP1559 : TransactionType.Legacy,
27
+ maxFeePerGas: msg.maxFeePerGas,
28
+ maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
29
+ gasPrice: msg.gasPrice,
36
30
  };
37
31
 
38
- const common = isEIP1559
39
- ? Common.custom({ chainId: msg.chainId }, { hardfork: Hardfork.London })
40
- : Common.custom({ chainId: msg.chainId });
41
-
42
- // Use TransactionFactory with explicit type field (Kevin's approach)
32
+ const common = Common.custom({ chainId: msg.chainId }, { hardfork: Hardfork.London });
43
33
  const unsignedTx = TransactionFactory.fromTxData(txData, { common });
44
34
 
45
- // Handle payload encoding based on transaction type
46
- // Legacy transactions return an array that needs RLP encoding
47
- // EIP-1559 transactions return a pre-encoded buffer
48
- const rawPayload = unsignedTx.getMessageToSign();
49
- const payload = Array.isArray(rawPayload) ? encode(rawPayload) : rawPayload;
35
+ const payload = isEIP1559 ? unsignedTx.getMessageToSign() : RLP.encode(unsignedTx.getMessageToSign());
50
36
 
51
37
  const fwVersion = client.getFwVersion();
52
38
  const supportsDecoderRecursion = fwVersion.major > 0 || fwVersion.minor >= 16;
53
39
 
54
40
  const decoderResult = await (() => {
55
41
  if (!msg.data || (msg.data.startsWith("0x") && Buffer.from(msg.data.slice(2), "hex").length < 4)) {
56
- return { def: null };
42
+ return { def: undefined };
57
43
  }
58
44
  return Utils.fetchCalldataDecoder(msg.data, msg.to, msg.chainId, supportsDecoderRecursion);
59
45
  })();
@@ -67,7 +53,7 @@ export async function ethSignTx(client: Client, msg: core.ETHSignTx): Promise<co
67
53
  hashType: Constants.SIGNING.HASHES.KECCAK256,
68
54
  encodingType: Constants.SIGNING.ENCODINGS.EVM,
69
55
  signerPath: msg.addressNList,
70
- decoder: def,
56
+ decoder: def ? Buffer.from(def) : undefined,
71
57
  },
72
58
  });
73
59
 
@@ -79,29 +65,7 @@ export async function ethSignTx(client: Client, msg: core.ETHSignTx): Promise<co
79
65
  if (!Buffer.isBuffer(s)) throw new Error("Invalid signature (s)");
80
66
  if (!Buffer.isBuffer(v)) throw new Error("Invalid signature (v)");
81
67
 
82
- // Reconstruct signed transaction using TransactionFactory with explicit type field
83
- const signedTxData = {
84
- to: msg.to,
85
- value: msg.value,
86
- data: msg.data,
87
- nonce: msg.nonce,
88
- gasLimit: msg.gasLimit,
89
- chainId: msg.chainId,
90
- type: isEIP1559 ? 2 : 0,
91
- r,
92
- s,
93
- v,
94
- ...(isEIP1559
95
- ? {
96
- maxFeePerGas: msg.maxFeePerGas,
97
- maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
98
- }
99
- : {
100
- gasPrice: msg.gasPrice,
101
- }),
102
- };
103
-
104
- const signedTx = TransactionFactory.fromTxData(signedTxData, { common });
68
+ const signedTx = TransactionFactory.fromTxData({ ...txData, r, s, v }, { common });
105
69
  const serialized = `0x${Buffer.from(signedTx.serialize()).toString("hex")}`;
106
70
 
107
71
  return { r: `0x${r.toString("hex")}`, s: `0x${s.toString("hex")}`, v: v.readUIntBE(0, v.length), serialized };
package/src/gridplus.ts CHANGED
@@ -8,8 +8,6 @@ import * as eth from "./ethereum";
8
8
  import * as mayachain from "./mayachain";
9
9
  import * as solana from "./solana";
10
10
  import * as thorchain from "./thorchain";
11
- import { GridPlusTransport } from "./transport";
12
- import { convertXpubVersion, scriptTypeToAccountType } from "./utils";
13
11
 
14
12
  export function isGridPlus(wallet: core.HDWallet): wallet is GridPlusHDWallet {
15
13
  return isObject(wallet) && (wallet as any)._isGridPlus;
@@ -273,12 +271,12 @@ export class GridPlusHDWallet
273
271
  extends GridPlusWalletInfo
274
272
  implements
275
273
  core.HDWallet,
276
- core.ETHWallet,
277
- core.SolanaWallet,
278
274
  core.BTCWallet,
279
275
  core.CosmosWallet,
280
- core.ThorchainWallet,
281
- core.MayachainWallet
276
+ core.ETHWallet,
277
+ core.MayachainWallet,
278
+ core.SolanaWallet,
279
+ core.ThorchainWallet
282
280
  {
283
281
  readonly _supportsArbitrum = true;
284
282
  readonly _supportsArbitrumNova = false;
@@ -298,117 +296,77 @@ export class GridPlusHDWallet
298
296
 
299
297
  readonly _isGridPlus = true;
300
298
 
301
- private activeWalletId?: string;
299
+ client: Client | undefined;
302
300
 
303
- transport: GridPlusTransport;
304
- client?: Client;
305
-
306
- constructor(transport: GridPlusTransport) {
301
+ constructor(client: Client) {
307
302
  super();
308
- this.transport = transport;
309
- }
310
-
311
- public setActiveWalletId(walletId: string): void {
312
- this.activeWalletId = walletId;
303
+ this.client = client;
304
+ }
305
+
306
+ async cancel(): Promise<void> {}
307
+ async clearSession(): Promise<void> {}
308
+ async initialize(): Promise<void> {}
309
+ async loadDevice(): Promise<void> {}
310
+ async recover(): Promise<void> {}
311
+ async reset(): Promise<void> {}
312
+ async sendCharacter(): Promise<void> {}
313
+ async sendPassphrase(): Promise<void> {}
314
+ async sendPin(): Promise<void> {}
315
+ async sendWord(): Promise<void> {}
316
+ async wipe(): Promise<void> {}
317
+
318
+ async getDeviceID(): Promise<string> {
319
+ if (!this.client) throw new Error("Device not connected");
320
+ return this.client.getDeviceId();
313
321
  }
314
322
 
315
323
  async getFeatures(): Promise<Record<string, any>> {
324
+ if (!this.client) throw new Error("Device not connected");
325
+
316
326
  return {
317
327
  vendor: "GridPlus",
318
- deviceId: this.transport.deviceId,
328
+ deviceId: this.client.getDeviceId(),
319
329
  model: "Lattice1",
320
330
  };
321
331
  }
322
332
 
323
- public async isLocked(): Promise<boolean> {
324
- return !this.transport.isConnected();
325
- }
326
-
327
- public async clearSession(): Promise<void> {
328
- if (!this.client) return;
329
- await this.transport.disconnect();
330
- this.client = undefined;
331
- }
332
-
333
- public async isInitialized(): Promise<boolean> {
334
- return !!this.client;
335
- }
336
-
337
- public async initialize(): Promise<void> {
338
- // Get the GridPlus client from transport after successful pairing
339
- this.client = this.transport.getClient();
340
-
341
- if (!this.client) {
342
- throw new Error("GridPlus client not available - device may not be paired");
343
- }
344
-
345
- // Validate that the client has the expected methods
346
- if (typeof this.client.getAddresses !== "function") {
347
- throw new Error("GridPlus client missing required getAddresses method");
348
- }
349
- }
350
-
351
- public async ping(msg: core.Ping): Promise<core.Pong> {
352
- return { msg: msg.msg };
353
- }
354
-
355
- public async sendPin(): Promise<void> {}
356
-
357
- public async sendPassphrase(): Promise<void> {}
358
-
359
- public async sendCharacter(): Promise<void> {}
360
-
361
- public async sendWord(): Promise<void> {}
362
-
363
- public async cancel(): Promise<void> {
364
- // GridPlus has no pending device interactions to cancel
365
- // Wallet persists in keyring - do not disconnect
366
- }
367
-
368
- public async wipe(): Promise<void> {
369
- throw new Error("GridPlus does not support wiping");
333
+ async getFirmwareVersion(): Promise<string> {
334
+ if (!this.client) throw new Error("Device not connected");
335
+ const { major, minor, fix } = this.client.getFwVersion();
336
+ return `${major}.${minor}.${fix}`;
370
337
  }
371
338
 
372
- public async reset(): Promise<void> {
373
- await this.clearSession();
374
- await this.initialize();
339
+ async getModel(): Promise<string> {
340
+ return "Lattice1";
375
341
  }
376
342
 
377
- public async recover(): Promise<void> {
378
- throw new Error("GridPlus does not support recovery mode");
343
+ async getLabel(): Promise<string> {
344
+ return "GridPlus Lattice1";
379
345
  }
380
346
 
381
- public async loadDevice(): Promise<void> {
382
- throw new Error("GridPlus does not support device loading");
347
+ async isInitialized(): Promise<boolean> {
348
+ return Boolean(this.client);
383
349
  }
384
350
 
385
- public describePath(): core.PathDescription {
386
- return {
387
- verbose: "GridPlus does not support path descriptions yet",
388
- coin: "Unknown",
389
- isKnown: false,
390
- };
351
+ async isLocked(): Promise<boolean> {
352
+ if (!this.client) throw new Error("Device not connected");
353
+ return false;
391
354
  }
392
355
 
393
- public async getModel(): Promise<string> {
394
- return "Lattice1";
356
+ async ping(msg: core.Ping): Promise<core.Pong> {
357
+ return { msg: msg.msg };
395
358
  }
396
359
 
397
- public async getLabel(): Promise<string> {
398
- return "GridPlus Lattice1";
360
+ async disconnect(): Promise<void> {
361
+ this.client = undefined;
399
362
  }
400
363
 
401
- public async getFirmwareVersion(): Promise<string> {
364
+ getSessionId(): string | undefined {
402
365
  if (!this.client) throw new Error("Device not connected");
403
- const { major, minor, fix } = this.client.getFwVersion();
404
- return `${major}.${minor}.${fix}`;
405
- }
406
-
407
- public async getDeviceID(): Promise<string> {
408
- return this.activeWalletId || (await this.transport.getDeviceID());
366
+ return JSON.parse(this.client.getStateData())["privKey"];
409
367
  }
410
368
 
411
- public async getPublicKeys(msg: Array<core.GetPublicKey>): Promise<Array<core.PublicKey | null>> {
369
+ async getPublicKeys(msg: Array<core.GetPublicKey>): Promise<Array<core.PublicKey | null>> {
412
370
  if (!this.client) throw new Error("Device not connected");
413
371
 
414
372
  const publicKeys: Array<core.PublicKey | null> = [];
@@ -417,18 +375,18 @@ export class GridPlusHDWallet
417
375
  const { addressNList, curve, coin, scriptType } = getPublicKey;
418
376
 
419
377
  try {
420
- let flag: number;
421
-
422
- // Determine the appropriate flag based on curve type
423
- if (curve === "secp256k1") {
424
- // For UTXO chains (Bitcoin, Dogecoin), we need the xpub
425
- flag = Constants.GET_ADDR_FLAGS.SECP256K1_XPUB;
426
- } else if (curve === "ed25519") {
427
- // For Solana/ed25519 chains, we need the public key
428
- flag = Constants.GET_ADDR_FLAGS.ED25519_PUB;
429
- } else {
430
- throw new Error(`Unsupported curve: ${curve}`);
431
- }
378
+ const flag = (() => {
379
+ switch (curve) {
380
+ // For UTXO chains (Bitcoin, Dogecoin), we need the xpub
381
+ case "secp256k1":
382
+ return Constants.GET_ADDR_FLAGS.SECP256K1_XPUB;
383
+ // For Solana/ed25519 chains, we need the public key
384
+ case "ed25519":
385
+ return Constants.GET_ADDR_FLAGS.ED25519_PUB;
386
+ default:
387
+ throw new Error(`Unsupported curve: ${curve}`);
388
+ }
389
+ })();
432
390
 
433
391
  const addresses = await this.client!.getAddresses({
434
392
  startPath: addressNList,
@@ -436,17 +394,15 @@ export class GridPlusHDWallet
436
394
  flag,
437
395
  });
438
396
 
439
- if (!addresses.length) {
440
- throw new Error("No public key returned from device");
441
- }
397
+ if (!addresses.length) throw new Error("No public key returned from device");
442
398
 
443
399
  // addresses[0] contains either xpub string (for SECP256K1_XPUB) or pubkey hex (for ED25519_PUB)
444
400
  let xpub = typeof addresses[0] === "string" ? addresses[0] : Buffer.from(addresses[0]).toString("hex");
445
401
 
446
402
  // Convert xpub format for Dogecoin/Litecoin (GridPlus returns Bitcoin xpub format)
447
403
  if (coin && curve === "secp256k1") {
448
- const accountType = scriptTypeToAccountType(scriptType);
449
- xpub = convertXpubVersion(xpub, accountType, coin);
404
+ const accountType = scriptType ? core.scriptTypeToAccountType[scriptType] : undefined;
405
+ xpub = core.convertXpubVersion(xpub, accountType, coin);
450
406
  }
451
407
 
452
408
  publicKeys.push({ xpub });
@@ -458,53 +414,45 @@ export class GridPlusHDWallet
458
414
  return publicKeys;
459
415
  }
460
416
 
461
- public getSessionId(): string | undefined {
462
- return this.transport.getSessionId();
463
- }
464
-
465
- public async disconnect(): Promise<void> {
466
- await this.clearSession();
467
- }
468
-
469
- public async btcGetAddress(msg: core.BTCGetAddress): Promise<string | null> {
417
+ async btcGetAddress(msg: core.BTCGetAddress): Promise<string | null> {
470
418
  if (!this.client) throw new Error("Device not connected");
471
419
  return btc.btcGetAddress(this.client!, msg);
472
420
  }
473
421
 
474
- public async btcSignTx(msg: core.BTCSignTx): Promise<core.BTCSignedTx | null> {
422
+ async btcSignTx(msg: core.BTCSignTx): Promise<core.BTCSignedTx | null> {
475
423
  if (!this.client) throw new Error("Device not connected");
476
424
  return btc.btcSignTx(this.client, msg);
477
425
  }
478
426
 
479
- public async btcSignMessage(): Promise<core.BTCSignedMessage | null> {
427
+ async btcSignMessage(): Promise<core.BTCSignedMessage | null> {
480
428
  throw new Error("GridPlus BTC message signing not yet implemented");
481
429
  }
482
430
 
483
- public async btcVerifyMessage(): Promise<boolean | null> {
431
+ async btcVerifyMessage(): Promise<boolean | null> {
484
432
  throw new Error("GridPlus BTC message verification not yet implemented");
485
433
  }
486
434
 
487
- public async ethGetAddress(msg: core.ETHGetAddress): Promise<core.Address | null> {
435
+ async ethGetAddress(msg: core.ETHGetAddress): Promise<core.Address | null> {
488
436
  if (!this.client) throw new Error("Device not connected");
489
437
  return eth.ethGetAddress(this.client, msg);
490
438
  }
491
439
 
492
- public async ethSignTx(msg: core.ETHSignTx): Promise<core.ETHSignedTx> {
440
+ async ethSignTx(msg: core.ETHSignTx): Promise<core.ETHSignedTx> {
493
441
  if (!this.client) throw new Error("Device not connected");
494
442
  return eth.ethSignTx(this.client, msg);
495
443
  }
496
444
 
497
- public async ethSignTypedData(msg: core.ETHSignTypedData): Promise<core.ETHSignedTypedData> {
445
+ async ethSignTypedData(msg: core.ETHSignTypedData): Promise<core.ETHSignedTypedData> {
498
446
  if (!this.client) throw new Error("Device not connected");
499
447
  return eth.ethSignTypedData(this.client, msg);
500
448
  }
501
449
 
502
- public async ethSignMessage(msg: core.ETHSignMessage): Promise<core.ETHSignedMessage> {
450
+ async ethSignMessage(msg: core.ETHSignMessage): Promise<core.ETHSignedMessage> {
503
451
  if (!this.client) throw new Error("Device not connected");
504
452
  return eth.ethSignMessage(this.client, msg);
505
453
  }
506
454
 
507
- public async ethVerifyMessage(): Promise<boolean> {
455
+ async ethVerifyMessage(): Promise<boolean> {
508
456
  throw new Error("GridPlus ETH message verification not implemented yet");
509
457
  }
510
458
 
@@ -520,42 +468,42 @@ export class GridPlusHDWallet
520
468
  }
521
469
  }
522
470
 
523
- public async solanaGetAddress(msg: core.SolanaGetAddress): Promise<string | null> {
471
+ async solanaGetAddress(msg: core.SolanaGetAddress): Promise<string | null> {
524
472
  this.assertSolanaFwSupport();
525
473
  return solana.solanaGetAddress(this.client, msg);
526
474
  }
527
475
 
528
- public async solanaSignTx(msg: core.SolanaSignTx): Promise<core.SolanaSignedTx | null> {
476
+ async solanaSignTx(msg: core.SolanaSignTx): Promise<core.SolanaSignedTx | null> {
529
477
  this.assertSolanaFwSupport();
530
478
  return solana.solanaSignTx(this.client, msg);
531
479
  }
532
480
 
533
- public async cosmosGetAddress(msg: core.CosmosGetAddress): Promise<string | null> {
481
+ async cosmosGetAddress(msg: core.CosmosGetAddress): Promise<string | null> {
534
482
  if (!this.client) throw new Error("Device not connected");
535
483
  return cosmos.cosmosGetAddress(this.client, msg);
536
484
  }
537
485
 
538
- public async cosmosSignTx(msg: core.CosmosSignTx): Promise<core.CosmosSignedTx | null> {
486
+ async cosmosSignTx(msg: core.CosmosSignTx): Promise<core.CosmosSignedTx | null> {
539
487
  if (!this.client) throw new Error("Device not connected");
540
488
  return cosmos.cosmosSignTx(this.client, msg);
541
489
  }
542
490
 
543
- public async thorchainGetAddress(msg: core.ThorchainGetAddress): Promise<string | null> {
491
+ async thorchainGetAddress(msg: core.ThorchainGetAddress): Promise<string | null> {
544
492
  if (!this.client) throw new Error("Device not connected");
545
493
  return thorchain.thorchainGetAddress(this.client, msg);
546
494
  }
547
495
 
548
- public async thorchainSignTx(msg: core.ThorchainSignTx): Promise<core.ThorchainSignedTx | null> {
496
+ async thorchainSignTx(msg: core.ThorchainSignTx): Promise<core.ThorchainSignedTx | null> {
549
497
  if (!this.client) throw new Error("Device not connected");
550
498
  return thorchain.thorchainSignTx(this.client, msg);
551
499
  }
552
500
 
553
- public async mayachainGetAddress(msg: core.MayachainGetAddress): Promise<string | null> {
501
+ async mayachainGetAddress(msg: core.MayachainGetAddress): Promise<string | null> {
554
502
  if (!this.client) throw new Error("Device not connected");
555
503
  return mayachain.mayachainGetAddress(this.client, msg);
556
504
  }
557
505
 
558
- public async mayachainSignTx(msg: core.MayachainSignTx): Promise<core.MayachainSignedTx | null> {
506
+ async mayachainSignTx(msg: core.MayachainSignTx): Promise<core.MayachainSignedTx | null> {
559
507
  if (!this.client) throw new Error("Device not connected");
560
508
  return mayachain.mayachainSignTx(this.client, msg);
561
509
  }
package/src/index.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./adapter";
2
2
  export { GridPlusHDWallet, GridPlusWalletInfo, isGridPlus } from "./gridplus";
3
- export * from "./transport";
package/src/utils.ts CHANGED
@@ -1,14 +1,11 @@
1
1
  import { pointCompress } from "@bitcoinerlab/secp256k1";
2
- import * as core from "@shapeshiftoss/hdwallet-core";
3
2
  import * as bech32 from "bech32";
4
- import { decode as bs58Decode, encode as bs58Encode } from "bs58check";
3
+ import * as bs58 from "bs58check";
5
4
  import CryptoJS from "crypto-js";
6
5
 
7
- import { accountTypeToVersion, convertVersions, UTXO_NETWORK_PARAMS, UtxoAccountType } from "./constants";
8
-
9
6
  export const getCompressedPubkey = (pubkey: string | Buffer): Buffer => {
10
7
  // Extended public key (xpub/ypub/zpub)
11
- if (typeof pubkey === "string") return bs58Decode(pubkey).subarray(45, 78);
8
+ if (typeof pubkey === "string") return bs58.decode(pubkey).subarray(45, 78);
12
9
 
13
10
  // Already compressed public key (33 bytes)
14
11
  if (pubkey.length === 33) return pubkey;
@@ -27,98 +24,3 @@ export const createBech32Address = (pubkey: string | Buffer, prefix: string): st
27
24
  const words = bech32.toWords(address);
28
25
  return bech32.encode(prefix, words);
29
26
  };
30
-
31
- /**
32
- * Convert xpub version bytes for different coins (e.g., xpub → dgub for Dogecoin)
33
- * GridPlus returns Bitcoin-format xpubs, but some coins like Dogecoin need different prefixes
34
- */
35
- export function convertXpubVersion(xpub: string, accountType: UtxoAccountType | undefined, coin: string): string {
36
- if (!accountType) return xpub;
37
- if (!convertVersions.includes(xpub.substring(0, 4))) {
38
- return xpub;
39
- }
40
-
41
- const payload = bs58Decode(xpub);
42
- const version = payload.slice(0, 4);
43
- const desiredVersion = accountTypeToVersion(coin, accountType);
44
- if (version.compare(desiredVersion) !== 0) {
45
- const key = payload.slice(4);
46
- return bs58Encode(Buffer.concat([desiredVersion, key]));
47
- }
48
- return xpub;
49
- }
50
-
51
- export function scriptTypeToAccountType(scriptType: core.BTCInputScriptType | undefined): UtxoAccountType | undefined {
52
- switch (scriptType) {
53
- case core.BTCInputScriptType.SpendAddress:
54
- return UtxoAccountType.P2pkh;
55
- case core.BTCInputScriptType.SpendWitness:
56
- return UtxoAccountType.SegwitNative;
57
- case core.BTCInputScriptType.SpendP2SHWitness:
58
- return UtxoAccountType.SegwitP2sh;
59
- default:
60
- return undefined;
61
- }
62
- }
63
-
64
- /**
65
- * Derive a UTXO address from a compressed public key
66
- * @param pubkeyHex - Compressed public key as hex string (33 bytes, starting with 02 or 03)
67
- * @param coin - Coin name (Bitcoin, Dogecoin, Litecoin, etc.)
68
- * @param scriptType - Script type (p2pkh, p2wpkh, p2sh-p2wpkh)
69
- * @returns The derived address
70
- */
71
- export function deriveAddressFromPubkey(
72
- pubkeyHex: string,
73
- coin: string,
74
- scriptType: core.BTCInputScriptType = core.BTCInputScriptType.SpendAddress
75
- ): string {
76
- const network = UTXO_NETWORK_PARAMS[coin] || UTXO_NETWORK_PARAMS.Bitcoin;
77
- const pubkeyBuffer = Buffer.from(pubkeyHex, "hex");
78
-
79
- if (pubkeyBuffer.length !== 33) {
80
- throw new Error(`Invalid compressed public key length: ${pubkeyBuffer.length} bytes`);
81
- }
82
-
83
- // Hash160 = RIPEMD160(SHA256(pubkey))
84
- const sha256Hash = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(pubkeyHex));
85
- const hash160 = CryptoJS.RIPEMD160(sha256Hash).toString();
86
- const hash160Buffer = Buffer.from(hash160, "hex");
87
-
88
- switch (scriptType) {
89
- case core.BTCInputScriptType.SpendAddress: {
90
- // P2PKH: <pubKeyHash version byte> + hash160 + checksum
91
- const payload = Buffer.concat([Buffer.from([network.pubKeyHash]), hash160Buffer]);
92
- return bs58Encode(payload);
93
- }
94
-
95
- case core.BTCInputScriptType.SpendWitness: {
96
- // P2WPKH (bech32): witness version 0 + hash160
97
- if (!network.bech32) {
98
- throw new Error(`Bech32 not supported for ${coin}`);
99
- }
100
- const words = bech32.toWords(hash160Buffer);
101
- words.unshift(0); // witness version 0
102
- return bech32.encode(network.bech32, words);
103
- }
104
-
105
- case core.BTCInputScriptType.SpendP2SHWitness: {
106
- // P2SH-P2WPKH: scriptHash of witness program
107
- // Witness program: OP_0 (0x00) + length (0x14) + hash160
108
- const witnessProgram = Buffer.concat([Buffer.from([0x00, 0x14]), hash160Buffer]);
109
-
110
- // Hash160 of witness program
111
- const wpHex = witnessProgram.toString("hex");
112
- const wpSha256 = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(wpHex));
113
- const wpHash160 = CryptoJS.RIPEMD160(wpSha256).toString();
114
- const wpHash160Buffer = Buffer.from(wpHash160, "hex");
115
-
116
- // Encode with scriptHash version byte
117
- const payload = Buffer.concat([Buffer.from([network.scriptHash]), wpHash160Buffer]);
118
- return bs58Encode(payload);
119
- }
120
-
121
- default:
122
- throw new Error(`Unsupported script type: ${scriptType}`);
123
- }
124
- }
package/tsconfig.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
+ "rootDir": "src",
4
5
  "outDir": "dist",
5
- "rootDir": "src"
6
+ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
6
7
  },
7
8
  "include": ["src/**/*"],
8
9
  "exclude": ["node_modules", "dist"],