@shapeshiftoss/hdwallet-gridplus 1.62.4-gridplus.alpha.0

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE.md +21 -0
  3. package/dist/adapter.d.ts +19 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +129 -0
  6. package/dist/adapter.js.map +1 -0
  7. package/dist/bitcoin.d.ts +7 -0
  8. package/dist/bitcoin.d.ts.map +1 -0
  9. package/dist/bitcoin.js +619 -0
  10. package/dist/bitcoin.js.map +1 -0
  11. package/dist/constants.d.ts +18 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +51 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/cosmos.d.ts +7 -0
  16. package/dist/cosmos.d.ts.map +1 -0
  17. package/dist/cosmos.js +156 -0
  18. package/dist/cosmos.js.map +1 -0
  19. package/dist/ethereum.d.ts +7 -0
  20. package/dist/ethereum.d.ts.map +1 -0
  21. package/dist/ethereum.js +294 -0
  22. package/dist/ethereum.js.map +1 -0
  23. package/dist/gridplus.d.ts +112 -0
  24. package/dist/gridplus.d.ts.map +1 -0
  25. package/dist/gridplus.js +574 -0
  26. package/dist/gridplus.js.map +1 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +24 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/mayachain.d.ts +7 -0
  32. package/dist/mayachain.d.ts.map +1 -0
  33. package/dist/mayachain.js +163 -0
  34. package/dist/mayachain.js.map +1 -0
  35. package/dist/solana.d.ts +5 -0
  36. package/dist/solana.d.ts.map +1 -0
  37. package/dist/solana.js +120 -0
  38. package/dist/solana.js.map +1 -0
  39. package/dist/thorchain.d.ts +5 -0
  40. package/dist/thorchain.d.ts.map +1 -0
  41. package/dist/thorchain.js +143 -0
  42. package/dist/thorchain.js.map +1 -0
  43. package/dist/transport.d.ts +28 -0
  44. package/dist/transport.d.ts.map +1 -0
  45. package/dist/transport.js +148 -0
  46. package/dist/transport.js.map +1 -0
  47. package/dist/utils.d.ts +17 -0
  48. package/dist/utils.d.ts.map +1 -0
  49. package/dist/utils.js +117 -0
  50. package/dist/utils.js.map +1 -0
  51. package/package.json +38 -0
  52. package/package.json.bak +38 -0
  53. package/src/adapter.ts +109 -0
  54. package/src/bitcoin.ts +711 -0
  55. package/src/constants.ts +52 -0
  56. package/src/cosmos.ts +132 -0
  57. package/src/ethereum.ts +305 -0
  58. package/src/gridplus.ts +550 -0
  59. package/src/index.ts +3 -0
  60. package/src/mayachain.ts +150 -0
  61. package/src/solana.ts +97 -0
  62. package/src/thorchain.ts +125 -0
  63. package/src/transport.ts +131 -0
  64. package/src/utils.ts +101 -0
  65. package/tsconfig.json +10 -0
  66. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,52 @@
1
+ import { UtxoAccountType } from "@shapeshiftoss/types";
2
+ export { UtxoAccountType };
3
+
4
+ export enum PublicKeyType {
5
+ xpub = "0488b21e",
6
+ ypub = "049d7cb2",
7
+ zpub = "04b24746",
8
+ dgub = "02facafd",
9
+ Ltub = "019da462",
10
+ Mtub = "01b26ef6",
11
+ }
12
+
13
+ export const accountTypeToVersion = (() => {
14
+ const Litecoin = {
15
+ [UtxoAccountType.P2pkh]: Buffer.from(PublicKeyType.Ltub, "hex"),
16
+ [UtxoAccountType.SegwitP2sh]: Buffer.from(PublicKeyType.Mtub, "hex"),
17
+ [UtxoAccountType.SegwitNative]: Buffer.from(PublicKeyType.zpub, "hex"),
18
+ };
19
+
20
+ const Dogecoin = {
21
+ [UtxoAccountType.P2pkh]: Buffer.from(PublicKeyType.dgub, "hex"),
22
+ };
23
+
24
+ const Bitcoin = {
25
+ [UtxoAccountType.P2pkh]: Buffer.from(PublicKeyType.xpub, "hex"),
26
+ [UtxoAccountType.SegwitP2sh]: Buffer.from(PublicKeyType.ypub, "hex"),
27
+ [UtxoAccountType.SegwitNative]: Buffer.from(PublicKeyType.zpub, "hex"),
28
+ };
29
+
30
+ return (coin: string, type: UtxoAccountType) => {
31
+ switch (coin) {
32
+ case "Litecoin":
33
+ return Litecoin[type];
34
+ case "Bitcoin":
35
+ return Bitcoin[type];
36
+ case "Dogecoin":
37
+ if (type !== UtxoAccountType.P2pkh) throw new Error("Unsupported account type");
38
+ return Dogecoin[type];
39
+ default:
40
+ return Bitcoin[type];
41
+ }
42
+ };
43
+ })();
44
+
45
+ export const convertVersions = ["Ltub", "xpub", "dgub"];
46
+
47
+ export const UTXO_NETWORK_PARAMS: Record<string, { pubKeyHash: number; scriptHash: number; bech32?: string }> = {
48
+ Bitcoin: { pubKeyHash: 0x00, scriptHash: 0x05, bech32: "bc" },
49
+ Dogecoin: { pubKeyHash: 0x1e, scriptHash: 0x16 },
50
+ Litecoin: { pubKeyHash: 0x30, scriptHash: 0x32, bech32: "ltc" },
51
+ BitcoinCash: { pubKeyHash: 0x00, scriptHash: 0x05 },
52
+ };
package/src/cosmos.ts ADDED
@@ -0,0 +1,132 @@
1
+ import { pointCompress } from "@bitcoinerlab/secp256k1";
2
+ import type { StdTx } from "@cosmjs/amino";
3
+ import type { DirectSignResponse, OfflineDirectSigner } from "@cosmjs/proto-signing";
4
+ import type { SignerData } from "@cosmjs/stargate";
5
+ import * as core from "@shapeshiftoss/hdwallet-core";
6
+ import * as bech32 from "bech32";
7
+ import type { SignDoc } from "cosmjs-types/cosmos/tx/v1beta1/tx";
8
+ import CryptoJS from "crypto-js";
9
+ import { Client, Constants } from "gridplus-sdk";
10
+ import PLazy from "p-lazy";
11
+
12
+ const protoTxBuilder = PLazy.from(() => import("@shapeshiftoss/proto-tx-builder"));
13
+ const cosmJsProtoSigning = PLazy.from(() => import("@cosmjs/proto-signing"));
14
+
15
+ export const bech32ify = (address: ArrayLike<number>, prefix: string): string => {
16
+ const words = bech32.toWords(address);
17
+ return bech32.encode(prefix, words);
18
+ };
19
+
20
+ export const createCosmosAddress = (publicKey: string, prefix: string): string => {
21
+ const message = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(publicKey));
22
+ const hash = CryptoJS.RIPEMD160(message as CryptoJS.lib.WordArray).toString();
23
+ const address = Buffer.from(hash, `hex`);
24
+ return bech32ify(address, prefix);
25
+ };
26
+
27
+ export async function cosmosGetAddress(client: Client, msg: core.CosmosGetAddress): Promise<string | null> {
28
+ // Get secp256k1 pubkey using GridPlus client instance
29
+ // Use FULL path - Cosmos uses standard BIP44: m/44'/118'/0'/0/0 (5 levels)
30
+ const addresses = await client.getAddresses({
31
+ startPath: msg.addressNList,
32
+ n: 1,
33
+ flag: Constants.GET_ADDR_FLAGS.SECP256K1_PUB,
34
+ });
35
+
36
+ if (!addresses.length) {
37
+ throw new Error("No address returned from device");
38
+ }
39
+
40
+ // GridPlus SDK returns uncompressed 65-byte pubkeys, but Cosmos needs compressed 33-byte pubkeys
41
+ const pubkeyBuffer = Buffer.isBuffer(addresses[0]) ? addresses[0] : Buffer.from(addresses[0], "hex");
42
+ const compressedPubkey = pointCompress(pubkeyBuffer, true);
43
+ const compressedHex = Buffer.from(compressedPubkey).toString("hex");
44
+ const cosmosAddress = createCosmosAddress(compressedHex, "cosmos");
45
+
46
+ return cosmosAddress;
47
+ }
48
+
49
+ export async function cosmosSignTx(client: Client, msg: core.CosmosSignTx): Promise<core.CosmosSignedTx | null> {
50
+ // Get the address for this path
51
+ const address = await cosmosGetAddress(client, { addressNList: msg.addressNList });
52
+ if (!address) throw new Error("Failed to get Cosmos address");
53
+
54
+ // Get the public key using client instance
55
+ const pubkeys = await client.getAddresses({
56
+ startPath: msg.addressNList,
57
+ n: 1,
58
+ flag: Constants.GET_ADDR_FLAGS.SECP256K1_PUB,
59
+ });
60
+
61
+ if (!pubkeys.length) {
62
+ throw new Error("No public key returned from device");
63
+ }
64
+
65
+ // GridPlus SDK returns uncompressed 65-byte pubkeys, but Cosmos needs compressed 33-byte pubkeys
66
+ const pubkeyBuffer = Buffer.isBuffer(pubkeys[0]) ? pubkeys[0] : Buffer.from(pubkeys[0], "hex");
67
+ const compressedPubkey = pointCompress(pubkeyBuffer, true);
68
+ const pubkey = Buffer.from(compressedPubkey);
69
+
70
+ // Create a signer adapter for GridPlus with Direct signing (Proto)
71
+ const signer: OfflineDirectSigner = {
72
+ getAccounts: async () => [
73
+ {
74
+ address,
75
+ pubkey,
76
+ algo: "secp256k1" as const,
77
+ },
78
+ ],
79
+ signDirect: async (signerAddress: string, signDoc: SignDoc): Promise<DirectSignResponse> => {
80
+ if (signerAddress !== address) {
81
+ throw new Error("Signer address mismatch");
82
+ }
83
+
84
+ // Use CosmJS to create the sign bytes from the SignDoc
85
+ const signBytes = (await cosmJsProtoSigning).makeSignBytes(signDoc);
86
+
87
+ // Sign using GridPlus SDK general signing
88
+ // Pass unhashed signBytes and let device hash with SHA256
89
+ const signData = {
90
+ data: {
91
+ payload: signBytes,
92
+ curveType: Constants.SIGNING.CURVES.SECP256K1,
93
+ hashType: Constants.SIGNING.HASHES.SHA256,
94
+ encodingType: Constants.SIGNING.ENCODINGS.NONE,
95
+ signerPath: msg.addressNList,
96
+ },
97
+ };
98
+
99
+ const signedResult = await client.sign(signData);
100
+
101
+ if (!signedResult?.sig) {
102
+ throw new Error("No signature returned from device");
103
+ }
104
+
105
+ const { r, s } = signedResult.sig;
106
+ const rHex = Buffer.isBuffer(r) ? r : Buffer.from(r);
107
+ const sHex = Buffer.isBuffer(s) ? s : Buffer.from(s);
108
+
109
+ // Combine r and s for signature
110
+ const signature = Buffer.concat([rHex, sHex]);
111
+
112
+ return {
113
+ signed: signDoc,
114
+ signature: {
115
+ pub_key: {
116
+ type: "tendermint/PubKeySecp256k1",
117
+ value: pubkey.toString("base64"),
118
+ },
119
+ signature: signature.toString("base64"),
120
+ },
121
+ };
122
+ },
123
+ };
124
+
125
+ const signerData: SignerData = {
126
+ sequence: Number(msg.sequence),
127
+ accountNumber: Number(msg.account_number),
128
+ chainId: msg.chain_id,
129
+ };
130
+
131
+ return (await protoTxBuilder).sign(address, msg.tx as StdTx, signer, signerData, "cosmos");
132
+ }
@@ -0,0 +1,305 @@
1
+ import Common from "@ethereumjs/common";
2
+ import { FeeMarketEIP1559Transaction, Transaction } from "@ethereumjs/tx";
3
+ import * as core from "@shapeshiftoss/hdwallet-core";
4
+ import { Client, Constants, Utils } from "gridplus-sdk";
5
+ import { encode } from "rlp";
6
+
7
+ export async function ethGetAddress(client: Client, msg: core.ETHGetAddress): Promise<core.Address | null> {
8
+ // Extract address index from EVM path: m/44'/60'/0'/0/X
9
+ // addressNList = [44', 60', 0', 0, X]
10
+ const addressIndex = msg.addressNList[4] || 0;
11
+ const startPath = [...msg.addressNList.slice(0, 4), addressIndex];
12
+
13
+ // TODO: testing only for @kaladinlight, revert me
14
+ // EXPERIMENTAL: Test different flags to see what GridPlus SDK returns
15
+ // Try SECP256K1_XPUB flag alongside default (no flag)
16
+ const addressesWithXpubFlag = await client.getAddresses({
17
+ startPath,
18
+ n: 1,
19
+ flag: Constants.GET_ADDR_FLAGS.SECP256K1_XPUB,
20
+ });
21
+
22
+ // Fetch only the requested address using client instance (current working method)
23
+ const addresses = await client.getAddresses({
24
+ startPath,
25
+ n: 1,
26
+ });
27
+
28
+ if (!addresses.length) {
29
+ throw new Error("No address returned from device");
30
+ }
31
+
32
+ const rawAddress = addresses[0];
33
+ const rawAddressWithXpubFlag = addressesWithXpubFlag[0];
34
+
35
+ let address: string;
36
+
37
+ // Handle response format (could be Buffer or string)
38
+ if (Buffer.isBuffer(rawAddress)) {
39
+ // Device returns raw address bytes without 0x prefix - add it for EVM compatibility
40
+ address = "0x" + rawAddress.toString("hex");
41
+ } else {
42
+ address = rawAddress.toString();
43
+ }
44
+
45
+ // Device may return address without 0x prefix - ensure it's present for EVM compatibility
46
+ if (!address.startsWith("0x")) {
47
+ address = "0x" + address;
48
+ }
49
+
50
+ // Validate Ethereum address format (should be 42 chars with 0x prefix)
51
+ if (address.length !== 42) {
52
+ throw new Error(`Invalid Ethereum address length: ${address}`);
53
+ }
54
+
55
+ // EXPERIMENTAL LOGGING: Compare what different flags return
56
+ console.log("=== GridPlus ethGetAddress Flag Comparison ===");
57
+ console.log("Path:", startPath);
58
+ console.log("No flag result:", {
59
+ type: Buffer.isBuffer(rawAddress) ? "Buffer" : typeof rawAddress,
60
+ raw: rawAddress,
61
+ asHex: Buffer.isBuffer(rawAddress) ? rawAddress.toString("hex") : rawAddress,
62
+ });
63
+ console.log("SECP256K1_XPUB flag result:", {
64
+ type: Buffer.isBuffer(rawAddressWithXpubFlag) ? "Buffer" : typeof rawAddressWithXpubFlag,
65
+ raw: rawAddressWithXpubFlag,
66
+ asString: Buffer.isBuffer(rawAddressWithXpubFlag) ? rawAddressWithXpubFlag.toString("hex") : rawAddressWithXpubFlag,
67
+ });
68
+ console.log("Final derived address:", address.toLowerCase());
69
+ console.log("==============================================");
70
+
71
+ // core.Address for ETH is just a string type `0x${string}`
72
+ return address.toLowerCase() as core.Address;
73
+ }
74
+
75
+ export async function ethSignTx(client: Client, msg: core.ETHSignTx): Promise<core.ETHSignedTx> {
76
+ const unsignedTxBase = {
77
+ to: msg.to,
78
+ value: msg.value,
79
+ data: msg.data,
80
+ nonce: msg.nonce,
81
+ gasLimit: msg.gasLimit,
82
+ chainId: msg.chainId,
83
+ };
84
+
85
+ const common = msg.maxFeePerGas
86
+ ? Common.custom({ chainId: msg.chainId }, { hardfork: "london" })
87
+ : Common.custom({ chainId: msg.chainId });
88
+ const unsignedTx = msg.maxFeePerGas
89
+ ? FeeMarketEIP1559Transaction.fromTxData(
90
+ {
91
+ ...unsignedTxBase,
92
+ maxFeePerGas: msg.maxFeePerGas,
93
+ maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
94
+ },
95
+ { common }
96
+ )
97
+ : Transaction.fromTxData({ ...unsignedTxBase, gasPrice: msg.gasPrice }, { common });
98
+
99
+ const payload = msg.maxFeePerGas ? unsignedTx.getMessageToSign(false) : encode(unsignedTx.getMessageToSign(false));
100
+
101
+ const callDataDecoder = msg.to ? await Utils.fetchCalldataDecoder(msg.data, msg.to, msg.chainId) : undefined;
102
+
103
+ const signingData = {
104
+ data: {
105
+ payload,
106
+ curveType: Constants.SIGNING.CURVES.SECP256K1,
107
+ hashType: Constants.SIGNING.HASHES.KECCAK256,
108
+ encodingType: Constants.SIGNING.ENCODINGS.EVM,
109
+ signerPath: msg.addressNList,
110
+ decoder: callDataDecoder?.def,
111
+ },
112
+ };
113
+
114
+ const signedResult = await client.sign(signingData);
115
+
116
+ if (!signedResult?.sig) {
117
+ throw new Error("No signature returned from device");
118
+ }
119
+
120
+ const { r, s, v } = signedResult.sig;
121
+
122
+ const rHex = "0x" + (Buffer.isBuffer(r) ? r.toString("hex") : core.toHexString(r));
123
+ const sHex = "0x" + (Buffer.isBuffer(s) ? s.toString("hex") : core.toHexString(s));
124
+ const vHex = "0x" + (Buffer.isBuffer(v) ? v.toString("hex") : core.toHexString(v));
125
+
126
+ const signedTx = msg.maxFeePerGas
127
+ ? FeeMarketEIP1559Transaction.fromTxData(
128
+ {
129
+ ...unsignedTxBase,
130
+ maxFeePerGas: msg.maxFeePerGas,
131
+ maxPriorityFeePerGas: msg.maxPriorityFeePerGas,
132
+ r: rHex,
133
+ s: sHex,
134
+ v: vHex,
135
+ },
136
+ { common }
137
+ )
138
+ : Transaction.fromTxData(
139
+ {
140
+ ...unsignedTxBase,
141
+ gasPrice: msg.gasPrice,
142
+ r: rHex,
143
+ s: sHex,
144
+ v: vHex,
145
+ },
146
+ { common }
147
+ );
148
+
149
+ const finalSerializedTx = `0x${signedTx.serialize().toString("hex")}`;
150
+ const vRaw = Buffer.isBuffer(v) ? v.readUInt8(0) : v;
151
+
152
+ const result = {
153
+ r: rHex,
154
+ s: sHex,
155
+ v: vRaw,
156
+ serialized: finalSerializedTx,
157
+ };
158
+
159
+ return result;
160
+ }
161
+
162
+ export async function ethSignTypedData(client: Client, msg: core.ETHSignTypedData): Promise<core.ETHSignedTypedData> {
163
+ const fwConstants = client.getFwConstants();
164
+ if (!fwConstants.eip712Supported) {
165
+ throw new Error("EIP-712 signing not supported by firmware version");
166
+ }
167
+
168
+ const addressResult = await ethGetAddress(client, {
169
+ addressNList: msg.addressNList,
170
+ showDisplay: false,
171
+ });
172
+
173
+ const signingOptions = {
174
+ currency: "ETH_MSG",
175
+ data: {
176
+ protocol: "eip712",
177
+ payload: msg.typedData,
178
+ signerPath: msg.addressNList,
179
+ },
180
+ };
181
+
182
+ // GridPlus SDK types don't properly support ETH_MSG currency, but runtime does
183
+ const signedResult = await client.sign(signingOptions as Parameters<typeof client.sign>[0]);
184
+
185
+ if (!signedResult?.sig) {
186
+ throw new Error("No signature returned from device");
187
+ }
188
+
189
+ // Type assertion needed because GridPlus SDK incorrectly types ETH_MSG signatures
190
+ const { r, s, v } = signedResult.sig as { r: string | Buffer; s: string | Buffer; v: number | Buffer };
191
+
192
+ let rHex: string;
193
+ let sHex: string;
194
+
195
+ if (Buffer.isBuffer(r)) {
196
+ rHex = "0x" + r.toString("hex");
197
+ } else if (typeof r === "string") {
198
+ if (r.startsWith("0x")) {
199
+ rHex = r;
200
+ } else {
201
+ rHex = "0x" + r;
202
+ }
203
+ } else {
204
+ throw new Error(`Unexpected r format: ${typeof r}`);
205
+ }
206
+
207
+ if (Buffer.isBuffer(s)) {
208
+ sHex = "0x" + s.toString("hex");
209
+ } else if (typeof s === "string") {
210
+ if (s.startsWith("0x")) {
211
+ sHex = s;
212
+ } else {
213
+ sHex = "0x" + s;
214
+ }
215
+ } else {
216
+ throw new Error(`Unexpected s format: ${typeof s}`);
217
+ }
218
+
219
+ const vBuf = Buffer.isBuffer(v) ? v : typeof v === "number" ? Buffer.from([v]) : Buffer.from(v);
220
+ const vValue = vBuf.readUInt8(0);
221
+ const vHex = "0x" + vValue.toString(16);
222
+
223
+ const signature = rHex + sHex.slice(2) + vHex.slice(2);
224
+
225
+ return {
226
+ address: addressResult!,
227
+ signature: signature,
228
+ };
229
+ }
230
+
231
+ export async function ethSignMessage(client: Client, msg: core.ETHSignMessage): Promise<core.ETHSignedMessage> {
232
+ if (typeof client.sign !== "function") {
233
+ throw new Error("GridPlus client missing required sign method");
234
+ }
235
+
236
+ const addressResult = await ethGetAddress(client, {
237
+ addressNList: msg.addressNList,
238
+ showDisplay: false,
239
+ });
240
+
241
+ let hexMessage: string;
242
+ if (msg.message.startsWith("0x")) {
243
+ hexMessage = msg.message;
244
+ } else {
245
+ const buffer = Buffer.from(msg.message, "utf8");
246
+ hexMessage = "0x" + buffer.toString("hex");
247
+ }
248
+
249
+ const signingOptions = {
250
+ currency: "ETH_MSG",
251
+ data: {
252
+ protocol: "signPersonal",
253
+ payload: hexMessage,
254
+ signerPath: msg.addressNList,
255
+ },
256
+ };
257
+
258
+ // GridPlus SDK types don't properly support ETH_MSG currency, but runtime does
259
+ const signedResult = await client.sign(signingOptions as Parameters<typeof client.sign>[0]);
260
+
261
+ if (!signedResult?.sig) {
262
+ throw new Error("No signature returned from device");
263
+ }
264
+
265
+ // Type assertion needed because GridPlus SDK incorrectly types ETH_MSG signatures
266
+ const { r, s, v } = signedResult.sig as { r: string | Buffer; s: string | Buffer; v: number | Buffer };
267
+
268
+ let rHex: string;
269
+ let sHex: string;
270
+
271
+ if (Buffer.isBuffer(r)) {
272
+ rHex = "0x" + r.toString("hex");
273
+ } else if (typeof r === "string") {
274
+ if (r.startsWith("0x")) {
275
+ rHex = r;
276
+ } else {
277
+ rHex = "0x" + r;
278
+ }
279
+ } else {
280
+ throw new Error(`Unexpected r format: ${typeof r}`);
281
+ }
282
+
283
+ if (Buffer.isBuffer(s)) {
284
+ sHex = "0x" + s.toString("hex");
285
+ } else if (typeof s === "string") {
286
+ if (s.startsWith("0x")) {
287
+ sHex = s;
288
+ } else {
289
+ sHex = "0x" + s;
290
+ }
291
+ } else {
292
+ throw new Error(`Unexpected s format: ${typeof s}`);
293
+ }
294
+
295
+ const vBuf = Buffer.isBuffer(v) ? v : typeof v === "number" ? Buffer.from([v]) : Buffer.from(v);
296
+ const vValue = vBuf.readUInt8(0);
297
+ const vHex = "0x" + vValue.toString(16);
298
+
299
+ const signature = rHex + sHex.slice(2) + vHex.slice(2);
300
+
301
+ return {
302
+ address: addressResult!,
303
+ signature: signature,
304
+ };
305
+ }