@shapeshiftoss/hdwallet-gridplus 1.62.10 → 1.62.12
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/dist/adapter.d.ts +3 -11
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +26 -98
- package/dist/adapter.js.map +1 -1
- package/dist/bitcoin.d.ts +1 -2
- package/dist/bitcoin.d.ts.map +1 -1
- package/dist/bitcoin.js +130 -555
- package/dist/bitcoin.js.map +1 -1
- package/dist/ethereum.d.ts.map +1 -1
- package/dist/ethereum.js +18 -34
- package/dist/ethereum.js.map +1 -1
- package/dist/gridplus.d.ts +17 -22
- package/dist/gridplus.d.ts.map +1 -1
- package/dist/gridplus.js +74 -101
- package/dist/gridplus.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils.d.ts +0 -16
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -87
- package/dist/utils.js.map +1 -1
- package/package.json +6 -5
- package/src/adapter.ts +26 -84
- package/src/bitcoin.ts +133 -651
- package/src/ethereum.ts +11 -47
- package/src/gridplus.ts +83 -130
- package/src/index.ts +0 -1
- package/src/utils.ts +2 -100
- package/tsconfig.json +2 -1
- package/dist/transport.d.ts +0 -28
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -148
- package/dist/transport.js.map +0 -1
- package/src/transport.ts +0 -131
- package/tsconfig.tsbuildinfo +0 -1
package/src/ethereum.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Common, Hardfork } from "@ethereumjs/common";
|
|
2
|
-
import {
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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,8 @@ 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
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
const ZERO_BUFFER = Buffer.alloc(32);
|
|
13
13
|
|
|
14
14
|
export function isGridPlus(wallet: core.HDWallet): wallet is GridPlusHDWallet {
|
|
15
15
|
return isObject(wallet) && (wallet as any)._isGridPlus;
|
|
@@ -273,12 +273,12 @@ export class GridPlusHDWallet
|
|
|
273
273
|
extends GridPlusWalletInfo
|
|
274
274
|
implements
|
|
275
275
|
core.HDWallet,
|
|
276
|
-
core.ETHWallet,
|
|
277
|
-
core.SolanaWallet,
|
|
278
276
|
core.BTCWallet,
|
|
279
277
|
core.CosmosWallet,
|
|
280
|
-
core.
|
|
281
|
-
core.MayachainWallet
|
|
278
|
+
core.ETHWallet,
|
|
279
|
+
core.MayachainWallet,
|
|
280
|
+
core.SolanaWallet,
|
|
281
|
+
core.ThorchainWallet
|
|
282
282
|
{
|
|
283
283
|
readonly _supportsArbitrum = true;
|
|
284
284
|
readonly _supportsArbitrumNova = false;
|
|
@@ -298,117 +298,80 @@ export class GridPlusHDWallet
|
|
|
298
298
|
|
|
299
299
|
readonly _isGridPlus = true;
|
|
300
300
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
transport: GridPlusTransport;
|
|
304
|
-
client?: Client;
|
|
301
|
+
client: Client | undefined;
|
|
305
302
|
|
|
306
|
-
constructor(
|
|
303
|
+
constructor(client: Client) {
|
|
307
304
|
super();
|
|
308
|
-
this.
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
305
|
+
this.client = client;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async cancel(): Promise<void> {}
|
|
309
|
+
async clearSession(): Promise<void> {}
|
|
310
|
+
async initialize(): Promise<void> {}
|
|
311
|
+
async loadDevice(): Promise<void> {}
|
|
312
|
+
async recover(): Promise<void> {}
|
|
313
|
+
async reset(): Promise<void> {}
|
|
314
|
+
async sendCharacter(): Promise<void> {}
|
|
315
|
+
async sendPassphrase(): Promise<void> {}
|
|
316
|
+
async sendPin(): Promise<void> {}
|
|
317
|
+
async sendWord(): Promise<void> {}
|
|
318
|
+
async wipe(): Promise<void> {}
|
|
319
|
+
|
|
320
|
+
async getDeviceID(): Promise<string> {
|
|
321
|
+
if (!this.client) throw new Error("Device not connected");
|
|
322
|
+
return this.client.getDeviceId();
|
|
313
323
|
}
|
|
314
324
|
|
|
315
325
|
async getFeatures(): Promise<Record<string, any>> {
|
|
326
|
+
if (!this.client) throw new Error("Device not connected");
|
|
327
|
+
|
|
316
328
|
return {
|
|
317
329
|
vendor: "GridPlus",
|
|
318
|
-
deviceId: this.
|
|
330
|
+
deviceId: this.client.getDeviceId(),
|
|
319
331
|
model: "Lattice1",
|
|
320
332
|
};
|
|
321
333
|
}
|
|
322
334
|
|
|
323
|
-
|
|
324
|
-
|
|
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");
|
|
335
|
+
async getFirmwareVersion(): Promise<string> {
|
|
336
|
+
if (!this.client) throw new Error("Device not connected");
|
|
337
|
+
const { major, minor, fix } = this.client.getFwVersion();
|
|
338
|
+
return `${major}.${minor}.${fix}`;
|
|
370
339
|
}
|
|
371
340
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
await this.initialize();
|
|
341
|
+
async getModel(): Promise<string> {
|
|
342
|
+
return "Lattice1";
|
|
375
343
|
}
|
|
376
344
|
|
|
377
|
-
|
|
378
|
-
|
|
345
|
+
async getLabel(): Promise<string> {
|
|
346
|
+
return "GridPlus Lattice1";
|
|
379
347
|
}
|
|
380
348
|
|
|
381
|
-
|
|
382
|
-
|
|
349
|
+
async isInitialized(): Promise<boolean> {
|
|
350
|
+
return Boolean(this.client);
|
|
383
351
|
}
|
|
384
352
|
|
|
385
|
-
|
|
386
|
-
return
|
|
387
|
-
verbose: "GridPlus does not support path descriptions yet",
|
|
388
|
-
coin: "Unknown",
|
|
389
|
-
isKnown: false,
|
|
390
|
-
};
|
|
353
|
+
async isLocked(): Promise<boolean> {
|
|
354
|
+
return false;
|
|
391
355
|
}
|
|
392
356
|
|
|
393
|
-
|
|
394
|
-
return
|
|
357
|
+
async ping(msg: core.Ping): Promise<core.Pong> {
|
|
358
|
+
return { msg: msg.msg };
|
|
395
359
|
}
|
|
396
360
|
|
|
397
|
-
|
|
398
|
-
|
|
361
|
+
async disconnect(): Promise<void> {
|
|
362
|
+
this.client = undefined;
|
|
399
363
|
}
|
|
400
364
|
|
|
401
|
-
|
|
365
|
+
async getActiveWalletId(): Promise<string | undefined> {
|
|
402
366
|
if (!this.client) throw new Error("Device not connected");
|
|
403
|
-
const { major, minor, fix } = this.client.getFwVersion();
|
|
404
|
-
return `${major}.${minor}.${fix}`;
|
|
405
|
-
}
|
|
406
367
|
|
|
407
|
-
|
|
408
|
-
|
|
368
|
+
const { external, internal } = await this.client.fetchActiveWallet();
|
|
369
|
+
|
|
370
|
+
if (!external.uid.equals(ZERO_BUFFER)) return external.uid.toString("hex");
|
|
371
|
+
if (!internal.uid.equals(ZERO_BUFFER)) return internal.uid.toString("hex");
|
|
409
372
|
}
|
|
410
373
|
|
|
411
|
-
|
|
374
|
+
async getPublicKeys(msg: Array<core.GetPublicKey>): Promise<Array<core.PublicKey | null>> {
|
|
412
375
|
if (!this.client) throw new Error("Device not connected");
|
|
413
376
|
|
|
414
377
|
const publicKeys: Array<core.PublicKey | null> = [];
|
|
@@ -417,18 +380,18 @@ export class GridPlusHDWallet
|
|
|
417
380
|
const { addressNList, curve, coin, scriptType } = getPublicKey;
|
|
418
381
|
|
|
419
382
|
try {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
383
|
+
const flag = (() => {
|
|
384
|
+
switch (curve) {
|
|
385
|
+
// For UTXO chains (Bitcoin, Dogecoin), we need the xpub
|
|
386
|
+
case "secp256k1":
|
|
387
|
+
return Constants.GET_ADDR_FLAGS.SECP256K1_XPUB;
|
|
388
|
+
// For Solana/ed25519 chains, we need the public key
|
|
389
|
+
case "ed25519":
|
|
390
|
+
return Constants.GET_ADDR_FLAGS.ED25519_PUB;
|
|
391
|
+
default:
|
|
392
|
+
throw new Error(`Unsupported curve: ${curve}`);
|
|
393
|
+
}
|
|
394
|
+
})();
|
|
432
395
|
|
|
433
396
|
const addresses = await this.client!.getAddresses({
|
|
434
397
|
startPath: addressNList,
|
|
@@ -436,17 +399,15 @@ export class GridPlusHDWallet
|
|
|
436
399
|
flag,
|
|
437
400
|
});
|
|
438
401
|
|
|
439
|
-
if (!addresses.length)
|
|
440
|
-
throw new Error("No public key returned from device");
|
|
441
|
-
}
|
|
402
|
+
if (!addresses.length) throw new Error("No public key returned from device");
|
|
442
403
|
|
|
443
404
|
// addresses[0] contains either xpub string (for SECP256K1_XPUB) or pubkey hex (for ED25519_PUB)
|
|
444
405
|
let xpub = typeof addresses[0] === "string" ? addresses[0] : Buffer.from(addresses[0]).toString("hex");
|
|
445
406
|
|
|
446
407
|
// Convert xpub format for Dogecoin/Litecoin (GridPlus returns Bitcoin xpub format)
|
|
447
408
|
if (coin && curve === "secp256k1") {
|
|
448
|
-
const accountType = scriptTypeToAccountType
|
|
449
|
-
xpub = convertXpubVersion(xpub, accountType, coin);
|
|
409
|
+
const accountType = scriptType ? core.scriptTypeToAccountType[scriptType] : undefined;
|
|
410
|
+
xpub = core.convertXpubVersion(xpub, accountType, coin);
|
|
450
411
|
}
|
|
451
412
|
|
|
452
413
|
publicKeys.push({ xpub });
|
|
@@ -458,53 +419,45 @@ export class GridPlusHDWallet
|
|
|
458
419
|
return publicKeys;
|
|
459
420
|
}
|
|
460
421
|
|
|
461
|
-
|
|
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> {
|
|
422
|
+
async btcGetAddress(msg: core.BTCGetAddress): Promise<string | null> {
|
|
470
423
|
if (!this.client) throw new Error("Device not connected");
|
|
471
424
|
return btc.btcGetAddress(this.client!, msg);
|
|
472
425
|
}
|
|
473
426
|
|
|
474
|
-
|
|
427
|
+
async btcSignTx(msg: core.BTCSignTx): Promise<core.BTCSignedTx | null> {
|
|
475
428
|
if (!this.client) throw new Error("Device not connected");
|
|
476
429
|
return btc.btcSignTx(this.client, msg);
|
|
477
430
|
}
|
|
478
431
|
|
|
479
|
-
|
|
432
|
+
async btcSignMessage(): Promise<core.BTCSignedMessage | null> {
|
|
480
433
|
throw new Error("GridPlus BTC message signing not yet implemented");
|
|
481
434
|
}
|
|
482
435
|
|
|
483
|
-
|
|
436
|
+
async btcVerifyMessage(): Promise<boolean | null> {
|
|
484
437
|
throw new Error("GridPlus BTC message verification not yet implemented");
|
|
485
438
|
}
|
|
486
439
|
|
|
487
|
-
|
|
440
|
+
async ethGetAddress(msg: core.ETHGetAddress): Promise<core.Address | null> {
|
|
488
441
|
if (!this.client) throw new Error("Device not connected");
|
|
489
442
|
return eth.ethGetAddress(this.client, msg);
|
|
490
443
|
}
|
|
491
444
|
|
|
492
|
-
|
|
445
|
+
async ethSignTx(msg: core.ETHSignTx): Promise<core.ETHSignedTx> {
|
|
493
446
|
if (!this.client) throw new Error("Device not connected");
|
|
494
447
|
return eth.ethSignTx(this.client, msg);
|
|
495
448
|
}
|
|
496
449
|
|
|
497
|
-
|
|
450
|
+
async ethSignTypedData(msg: core.ETHSignTypedData): Promise<core.ETHSignedTypedData> {
|
|
498
451
|
if (!this.client) throw new Error("Device not connected");
|
|
499
452
|
return eth.ethSignTypedData(this.client, msg);
|
|
500
453
|
}
|
|
501
454
|
|
|
502
|
-
|
|
455
|
+
async ethSignMessage(msg: core.ETHSignMessage): Promise<core.ETHSignedMessage> {
|
|
503
456
|
if (!this.client) throw new Error("Device not connected");
|
|
504
457
|
return eth.ethSignMessage(this.client, msg);
|
|
505
458
|
}
|
|
506
459
|
|
|
507
|
-
|
|
460
|
+
async ethVerifyMessage(): Promise<boolean> {
|
|
508
461
|
throw new Error("GridPlus ETH message verification not implemented yet");
|
|
509
462
|
}
|
|
510
463
|
|
|
@@ -520,42 +473,42 @@ export class GridPlusHDWallet
|
|
|
520
473
|
}
|
|
521
474
|
}
|
|
522
475
|
|
|
523
|
-
|
|
476
|
+
async solanaGetAddress(msg: core.SolanaGetAddress): Promise<string | null> {
|
|
524
477
|
this.assertSolanaFwSupport();
|
|
525
478
|
return solana.solanaGetAddress(this.client, msg);
|
|
526
479
|
}
|
|
527
480
|
|
|
528
|
-
|
|
481
|
+
async solanaSignTx(msg: core.SolanaSignTx): Promise<core.SolanaSignedTx | null> {
|
|
529
482
|
this.assertSolanaFwSupport();
|
|
530
483
|
return solana.solanaSignTx(this.client, msg);
|
|
531
484
|
}
|
|
532
485
|
|
|
533
|
-
|
|
486
|
+
async cosmosGetAddress(msg: core.CosmosGetAddress): Promise<string | null> {
|
|
534
487
|
if (!this.client) throw new Error("Device not connected");
|
|
535
488
|
return cosmos.cosmosGetAddress(this.client, msg);
|
|
536
489
|
}
|
|
537
490
|
|
|
538
|
-
|
|
491
|
+
async cosmosSignTx(msg: core.CosmosSignTx): Promise<core.CosmosSignedTx | null> {
|
|
539
492
|
if (!this.client) throw new Error("Device not connected");
|
|
540
493
|
return cosmos.cosmosSignTx(this.client, msg);
|
|
541
494
|
}
|
|
542
495
|
|
|
543
|
-
|
|
496
|
+
async thorchainGetAddress(msg: core.ThorchainGetAddress): Promise<string | null> {
|
|
544
497
|
if (!this.client) throw new Error("Device not connected");
|
|
545
498
|
return thorchain.thorchainGetAddress(this.client, msg);
|
|
546
499
|
}
|
|
547
500
|
|
|
548
|
-
|
|
501
|
+
async thorchainSignTx(msg: core.ThorchainSignTx): Promise<core.ThorchainSignedTx | null> {
|
|
549
502
|
if (!this.client) throw new Error("Device not connected");
|
|
550
503
|
return thorchain.thorchainSignTx(this.client, msg);
|
|
551
504
|
}
|
|
552
505
|
|
|
553
|
-
|
|
506
|
+
async mayachainGetAddress(msg: core.MayachainGetAddress): Promise<string | null> {
|
|
554
507
|
if (!this.client) throw new Error("Device not connected");
|
|
555
508
|
return mayachain.mayachainGetAddress(this.client, msg);
|
|
556
509
|
}
|
|
557
510
|
|
|
558
|
-
|
|
511
|
+
async mayachainSignTx(msg: core.MayachainSignTx): Promise<core.MayachainSignedTx | null> {
|
|
559
512
|
if (!this.client) throw new Error("Device not connected");
|
|
560
513
|
return mayachain.mayachainSignTx(this.client, msg);
|
|
561
514
|
}
|
package/src/index.ts
CHANGED
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
|
|
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
|
|
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
package/dist/transport.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as core from "@shapeshiftoss/hdwallet-core";
|
|
2
|
-
import { Client } from "gridplus-sdk";
|
|
3
|
-
export type GridPlusTransportConfig = {
|
|
4
|
-
deviceId: string;
|
|
5
|
-
password?: string;
|
|
6
|
-
};
|
|
7
|
-
export declare class GridPlusTransport extends core.Transport {
|
|
8
|
-
deviceId?: string;
|
|
9
|
-
password?: string;
|
|
10
|
-
connected: boolean;
|
|
11
|
-
private client?;
|
|
12
|
-
private sessionId?;
|
|
13
|
-
constructor(config: GridPlusTransportConfig);
|
|
14
|
-
getDeviceID(): Promise<string>;
|
|
15
|
-
connect(): Promise<void>;
|
|
16
|
-
connectGridPlus(deviceId: string, password?: string): Promise<void>;
|
|
17
|
-
disconnect(): Promise<void>;
|
|
18
|
-
isConnected(): boolean;
|
|
19
|
-
setup(deviceId: string, password?: string, existingSessionId?: string): Promise<{
|
|
20
|
-
isPaired: boolean;
|
|
21
|
-
sessionId: string;
|
|
22
|
-
}>;
|
|
23
|
-
pair(pairingCode: string): Promise<boolean>;
|
|
24
|
-
getClient(): Client | undefined;
|
|
25
|
-
getSessionId(): string | undefined;
|
|
26
|
-
call(): Promise<any>;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,8BAA8B,CAAC;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,iBAAkB,SAAQ,IAAI,CAAC,SAAS;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,MAAM,CAAC,CAAS;IAIxB,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,MAAM,EAAE,uBAAuB;IAMpC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAIhB,KAAK,CAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAgDvC,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUjD,SAAS,IAAI,MAAM,GAAG,SAAS;IAI/B,YAAY,IAAI,MAAM,GAAG,SAAS;IAI5B,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;CAGlC"}
|