@sovereign-sdk/signers 0.0.2 → 0.0.4

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/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @sovereign-sdk/signers
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@sovereign-sdk/signers.svg)](https://www.npmjs.com/package/@sovereign-sdk/signers)
4
+ [![CI](https://github.com/Sovereign-Labs/sovereign-sdk-web3-js/actions/workflows/ci.yaml/badge.svg)](https://github.com/Sovereign-Labs/sovereign-sdk-web3-js/actions/workflows/ci.yaml)
5
+
6
+ A signer interface and implementations for use with Sovereign SDK applications.
7
+
8
+ ## Installation
9
+
10
+ ```
11
+ npm install @sovereign-sdk/signers
12
+ ```
13
+
14
+ ## Features
15
+
16
+ - 🔐 Abstract `Signer` interface that can be implemented to provide custom signers for use in `@sovereign-sdk/web3`.
17
+ - 🦊 MetaMask Snap signer implementation for use with [Sovereign's Universal MetaMask Snap](https://github.com/Sovereign-Labs/sovereign-universal-snap)
18
+
19
+
20
+ ## Usage
21
+
22
+ ### MetaMask Snap Signer
23
+
24
+
25
+ ```typescript
26
+ import { newMetaMaskSnapSigner } from '@sovereign-sdk/signers';
27
+
28
+ // Initialize the signer
29
+ const signer = newMetaMaskSnapSigner({
30
+ curve: 'ed25519', // or 'secp256k1'
31
+ schema: {
32
+ // Your rollup schema
33
+ },
34
+ snapId: 'npm:@sovereign-sdk/metamask-snap', // Metamask snap origin, can be changed to `local:localhost:8080` for local development
35
+ });
36
+
37
+ // Get public key
38
+ const publicKey = await signer.publicKey();
39
+
40
+ // Sign a message
41
+ const message = new Uint8Array([/* your message */]);
42
+ const signature = await signer.sign(message);
43
+ ```
44
+
45
+ ### Customer Signer Implementation
46
+
47
+ You can implement your own signer by implementing the `Signer` interface if your wallet is not currently supported.
48
+
49
+ ```typescript
50
+ import { Signer } from '@sovereign-sdk/signers';
51
+
52
+ class MySigner implements Signer {
53
+ publicKey() {
54
+ // retireve the public key from your wallet
55
+ return new Uint8Array([/* your public key */]);
56
+ }
57
+
58
+ async sign(message: Uint8Array) {
59
+ // sign the message
60
+ return new Uint8Array([/* your signature */]);
61
+ }
62
+ }
63
+ ```
package/dist/index.d.mts CHANGED
@@ -1,18 +1,64 @@
1
1
  import { MetaMaskInpageProvider } from '@metamask/providers';
2
2
 
3
+ /**
4
+ * A signer interface that can be implemented to provide custom signers for use in Sovereign SDK applications.
5
+ */
3
6
  interface Signer {
7
+ /**
8
+ * Sign a message.
9
+ *
10
+ * @param message - The message to sign
11
+ * @returns A promise that resolves to the signature
12
+ */
4
13
  sign(message: Uint8Array): Promise<Uint8Array>;
14
+ /**
15
+ * Get the public key.
16
+ *
17
+ * @returns A promise that resolves to the public key
18
+ */
5
19
  publicKey(): Promise<Uint8Array>;
6
20
  }
21
+ /**
22
+ * Options for initializing a signer.
23
+ */
7
24
  type SignerOpt = {
25
+ /**
26
+ * The rollup schema generated during building of the rollup.
27
+ *
28
+ * Can be used to serialize and deserialize types and provide human readable representation
29
+ * of signing data.
30
+ */
8
31
  schema: Record<string, unknown>;
32
+ /**
33
+ * The curve to use for signing.
34
+ */
9
35
  curve: "ed25519" | "secp256k1";
10
36
  };
11
37
 
38
+ /**
39
+ * Options for initializing a MetaMask Snap signer.
40
+ */
12
41
  type MetaMaskSnapSignerOpt = {
42
+ /**
43
+ * The {@link MetaMaskInpageProvider} to use for the signer.
44
+ *
45
+ * If not provided, the signer will attempt to use the global `window.ethereum` provider.
46
+ */
13
47
  provider?: MetaMaskInpageProvider;
48
+ /**
49
+ * The snap ID to use for the signer.
50
+ *
51
+ * Defaults to `npm:@sovereign-sdk/metamask-snap`.
52
+ * Can be changed to `local:localhost:8080` for local development.
53
+ */
14
54
  snapId?: string;
15
55
  } & SignerOpt;
56
+ /**
57
+ * Create a new MetaMask Snap signer.
58
+ *
59
+ * @param options - The {@link MetaMaskSnapSignerOpt} options.
60
+ * @returns A {@link Signer} implementation utilizing Sovereign's MetaMask Snap.
61
+ */
16
62
  declare const newMetaMaskSnapSigner: ({ curve, schema, snapId, ...rest }: MetaMaskSnapSignerOpt) => Signer;
17
63
 
18
64
  export { type MetaMaskSnapSignerOpt, type Signer, type SignerOpt, newMetaMaskSnapSigner };
package/dist/index.d.ts CHANGED
@@ -1,18 +1,64 @@
1
1
  import { MetaMaskInpageProvider } from '@metamask/providers';
2
2
 
3
+ /**
4
+ * A signer interface that can be implemented to provide custom signers for use in Sovereign SDK applications.
5
+ */
3
6
  interface Signer {
7
+ /**
8
+ * Sign a message.
9
+ *
10
+ * @param message - The message to sign
11
+ * @returns A promise that resolves to the signature
12
+ */
4
13
  sign(message: Uint8Array): Promise<Uint8Array>;
14
+ /**
15
+ * Get the public key.
16
+ *
17
+ * @returns A promise that resolves to the public key
18
+ */
5
19
  publicKey(): Promise<Uint8Array>;
6
20
  }
21
+ /**
22
+ * Options for initializing a signer.
23
+ */
7
24
  type SignerOpt = {
25
+ /**
26
+ * The rollup schema generated during building of the rollup.
27
+ *
28
+ * Can be used to serialize and deserialize types and provide human readable representation
29
+ * of signing data.
30
+ */
8
31
  schema: Record<string, unknown>;
32
+ /**
33
+ * The curve to use for signing.
34
+ */
9
35
  curve: "ed25519" | "secp256k1";
10
36
  };
11
37
 
38
+ /**
39
+ * Options for initializing a MetaMask Snap signer.
40
+ */
12
41
  type MetaMaskSnapSignerOpt = {
42
+ /**
43
+ * The {@link MetaMaskInpageProvider} to use for the signer.
44
+ *
45
+ * If not provided, the signer will attempt to use the global `window.ethereum` provider.
46
+ */
13
47
  provider?: MetaMaskInpageProvider;
48
+ /**
49
+ * The snap ID to use for the signer.
50
+ *
51
+ * Defaults to `npm:@sovereign-sdk/metamask-snap`.
52
+ * Can be changed to `local:localhost:8080` for local development.
53
+ */
14
54
  snapId?: string;
15
55
  } & SignerOpt;
56
+ /**
57
+ * Create a new MetaMask Snap signer.
58
+ *
59
+ * @param options - The {@link MetaMaskSnapSignerOpt} options.
60
+ * @returns A {@link Signer} implementation utilizing Sovereign's MetaMask Snap.
61
+ */
16
62
  declare const newMetaMaskSnapSigner: ({ curve, schema, snapId, ...rest }: MetaMaskSnapSignerOpt) => Signer;
17
63
 
18
64
  export { type MetaMaskSnapSignerOpt, type Signer, type SignerOpt, newMetaMaskSnapSigner };
package/dist/index.js CHANGED
@@ -58,33 +58,19 @@ __export(src_exports, {
58
58
  });
59
59
  module.exports = __toCommonJS(src_exports);
60
60
 
61
- // src/utils.ts
62
- function hexToBytes(hex) {
63
- if (hex.length && hex.length % 2 !== 0) {
64
- throw new Error(`Invalid hex string length: ${hex.length}`);
65
- }
66
- const matches = hex.match(/[\da-f]{2}/gi);
67
- if (!matches) {
68
- throw new Error("Invalid hex string: No valid hex digits found");
69
- }
70
- return new Uint8Array(matches.map((h) => Number.parseInt(h, 16)));
71
- }
72
- function bytesToHex(arr) {
73
- let hex = "";
74
- for (let i = 0; i < arr.length; i++) {
75
- let hexValue = arr[i].toString(16);
76
- if (hexValue.length === 1) {
77
- hexValue = `0${hexValue}`;
78
- }
79
- hex += hexValue;
80
- }
81
- return hex;
82
- }
61
+ // src/snap.ts
62
+ var import_utils = require("@sovereign-sdk/utils");
83
63
 
84
64
  // src/errors.ts
85
65
  var SignerError = class extends Error {
66
+ /**
67
+ * Create a new SignerError.
68
+ *
69
+ * @param message - The error message
70
+ * @param signerId - The ID of the signer that threw the error
71
+ */
86
72
  constructor(message, signerId) {
87
- super(message);
73
+ super(`[${signerId}] ${message}`);
88
74
  this.signerId = signerId;
89
75
  this.name = this.constructor.name;
90
76
  this.stack = new Error().stack;
@@ -136,7 +122,7 @@ var newMetaMaskSnapSigner = (_a) => {
136
122
  }
137
123
  };
138
124
  const { publicKey } = yield provider.request(args);
139
- return hexToBytes(publicKey);
125
+ return (0, import_utils.hexToBytes)(publicKey);
140
126
  });
141
127
  },
142
128
  sign(message) {
@@ -148,12 +134,12 @@ var newMetaMaskSnapSigner = (_a) => {
148
134
  snapId,
149
135
  request: {
150
136
  method: "signTransaction",
151
- params: { unsignedTxHex: bytesToHex(message), schema, curve, path }
137
+ params: { unsignedTxHex: (0, import_utils.bytesToHex)(message), schema, curve, path }
152
138
  }
153
139
  }
154
140
  };
155
141
  const { signature } = yield provider.request(args);
156
- return hexToBytes(signature);
142
+ return (0, import_utils.hexToBytes)(signature);
157
143
  });
158
144
  }
159
145
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/errors.ts","../src/snap.ts"],"sourcesContent":["export * from \"./signer\";\nexport * from \"./snap\";\n","export function hexToBytes(hex: string) {\n if (hex.length && hex.length % 2 !== 0) {\n throw new Error(`Invalid hex string length: ${hex.length}`);\n }\n\n const matches = hex.match(/[\\da-f]{2}/gi);\n\n if (!matches) {\n throw new Error(\"Invalid hex string: No valid hex digits found\");\n }\n\n return new Uint8Array(matches.map((h) => Number.parseInt(h, 16)));\n}\n\nexport function bytesToHex(arr: Uint8Array): string {\n let hex = \"\";\n for (let i = 0; i < arr.length; i++) {\n let hexValue = arr[i].toString(16);\n if (hexValue.length === 1) {\n hexValue = `0${hexValue}`;\n }\n hex += hexValue;\n }\n return hex;\n}\n","export class SignerError extends Error {\n public readonly signerId: string;\n\n constructor(message: string, signerId: string) {\n super(message);\n\n this.signerId = signerId;\n this.name = this.constructor.name;\n this.stack = new Error().stack;\n }\n}\n","/// <reference path=\"./snap-env.d.ts\" />\n\nimport type { MetaMaskInpageProvider } from \"@metamask/providers\";\nimport { Signer, SignerOpt } from \"./signer\";\nimport { bytesToHex, hexToBytes } from \"./utils\";\nimport { SignerError } from \"./errors\";\n\nexport type MetaMaskSnapSignerOpt = {\n provider?: MetaMaskInpageProvider;\n snapId?: string;\n} & SignerOpt;\n\nexport const newMetaMaskSnapSigner = ({\n curve,\n schema,\n snapId = \"npm:@sovereign-sdk/metamask-snap\",\n ...rest\n}: MetaMaskSnapSignerOpt): Signer => {\n const signerId = \"MetaMaskSnap\";\n const provider = rest.provider ?? window.ethereum;\n\n if (!provider) {\n throw new SignerError(\"Failed to find provider for signer\", signerId);\n }\n\n const assertSupported = async () => {\n try {\n await provider.request({\n method: \"wallet_getSnaps\",\n });\n } catch {\n throw new SignerError(\n \"Provider does not support MetaMask snaps\",\n signerId\n );\n }\n };\n\n const path = 0;\n\n return {\n async publicKey() {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"getPublicKey\",\n params: { path, curve },\n },\n },\n };\n const { publicKey } = (await provider.request(args)) as any;\n\n return hexToBytes(publicKey);\n },\n async sign(message: Uint8Array) {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"signTransaction\",\n params: { unsignedTxHex: bytesToHex(message), schema, curve, path },\n },\n },\n };\n const { signature } = (await provider.request(args)) as any;\n\n return hexToBytes(signature);\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,SAAS,WAAW,KAAa;AACtC,MAAI,IAAI,UAAU,IAAI,SAAS,MAAM,GAAG;AACtC,UAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,EAAE;AAAA,EAC5D;AAEA,QAAM,UAAU,IAAI,MAAM,cAAc;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,SAAO,IAAI,WAAW,QAAQ,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,CAAC,CAAC;AAClE;AAEO,SAAS,WAAW,KAAyB;AAClD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,QAAI,WAAW,IAAI,CAAC,EAAE,SAAS,EAAE;AACjC,QAAI,SAAS,WAAW,GAAG;AACzB,iBAAW,IAAI,QAAQ;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACxBO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAGrC,YAAY,SAAiB,UAAkB;AAC7C,UAAM,OAAO;AAEb,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,QAAQ,IAAI,MAAM,EAAE;AAAA,EAC3B;AACF;;;ACEO,IAAM,wBAAwB,CAAC,OAKD;AALC,eACpC;AAAA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAfX,IAYsC,IAIjC,iBAJiC,IAIjC;AAAA,IAHH;AAAA,IACA;AAAA,IACA;AAAA;AAfF,MAAAA;AAkBE,QAAM,WAAW;AACjB,QAAM,YAAWA,MAAA,KAAK,aAAL,OAAAA,MAAiB,OAAO;AAEzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,YAAY,sCAAsC,QAAQ;AAAA,EACtE;AAEA,QAAM,kBAAkB,MAAY;AAClC,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,QACrB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO;AAEb,SAAO;AAAA,IACC,YAAY;AAAA;AAChB,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,MAAM,MAAM;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AACA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,IACM,KAAK,SAAqB;AAAA;AAC9B,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,eAAe,WAAW,OAAO,GAAG,QAAQ,OAAO,KAAK;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AACA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,EACF;AACF;","names":["_a"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/snap.ts","../src/errors.ts"],"sourcesContent":["export * from \"./signer\";\nexport * from \"./snap\";\n","/// <reference path=\"./snap-env.d.ts\" />\n\nimport type { MetaMaskInpageProvider } from \"@metamask/providers\";\nimport { bytesToHex, hexToBytes } from \"@sovereign-sdk/utils\";\nimport { SignerError } from \"./errors\";\nimport type { Signer, SignerOpt } from \"./signer\";\n\n/**\n * Options for initializing a MetaMask Snap signer.\n */\nexport type MetaMaskSnapSignerOpt = {\n /**\n * The {@link MetaMaskInpageProvider} to use for the signer.\n *\n * If not provided, the signer will attempt to use the global `window.ethereum` provider.\n */\n provider?: MetaMaskInpageProvider;\n /**\n * The snap ID to use for the signer.\n *\n * Defaults to `npm:@sovereign-sdk/metamask-snap`.\n * Can be changed to `local:localhost:8080` for local development.\n */\n snapId?: string;\n} & SignerOpt;\n\n/**\n * Create a new MetaMask Snap signer.\n *\n * @param options - The {@link MetaMaskSnapSignerOpt} options.\n * @returns A {@link Signer} implementation utilizing Sovereign's MetaMask Snap.\n */\nexport const newMetaMaskSnapSigner = ({\n curve,\n schema,\n snapId = \"npm:@sovereign-sdk/metamask-snap\",\n ...rest\n}: MetaMaskSnapSignerOpt): Signer => {\n const signerId = \"MetaMaskSnap\";\n const provider = rest.provider ?? window.ethereum;\n\n if (!provider) {\n throw new SignerError(\"Failed to find provider for signer\", signerId);\n }\n\n const assertSupported = async () => {\n try {\n await provider.request({\n method: \"wallet_getSnaps\",\n });\n } catch {\n throw new SignerError(\n \"Provider does not support MetaMask snaps\",\n signerId,\n );\n }\n };\n\n const path = 0;\n\n return {\n async publicKey() {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"getPublicKey\",\n params: { path, curve },\n },\n },\n };\n // biome-ignore lint/suspicious/noExplicitAny: todo\n const { publicKey } = (await provider.request(args)) as any;\n\n return hexToBytes(publicKey);\n },\n async sign(message: Uint8Array) {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"signTransaction\",\n params: { unsignedTxHex: bytesToHex(message), schema, curve, path },\n },\n },\n };\n // biome-ignore lint/suspicious/noExplicitAny: todo\n const { signature } = (await provider.request(args)) as any;\n\n return hexToBytes(signature);\n },\n };\n};\n","/**\n * An error that can be thrown by a signer.\n */\nexport class SignerError extends Error {\n public readonly signerId: string;\n\n /**\n * Create a new SignerError.\n *\n * @param message - The error message\n * @param signerId - The ID of the signer that threw the error\n */\n constructor(message: string, signerId: string) {\n super(`[${signerId}] ${message}`);\n\n this.signerId = signerId;\n this.name = this.constructor.name;\n this.stack = new Error().stack;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,mBAAuC;;;ACAhC,IAAM,cAAN,cAA0B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrC,YAAY,SAAiB,UAAkB;AAC7C,UAAM,IAAI,QAAQ,KAAK,OAAO,EAAE;AAEhC,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,QAAQ,IAAI,MAAM,EAAE;AAAA,EAC3B;AACF;;;ADaO,IAAM,wBAAwB,CAAC,OAKD;AALC,eACpC;AAAA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAnCX,IAgCsC,IAIjC,iBAJiC,IAIjC;AAAA,IAHH;AAAA,IACA;AAAA,IACA;AAAA;AAnCF,MAAAA;AAsCE,QAAM,WAAW;AACjB,QAAM,YAAWA,MAAA,KAAK,aAAL,OAAAA,MAAiB,OAAO;AAEzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,YAAY,sCAAsC,QAAQ;AAAA,EACtE;AAEA,QAAM,kBAAkB,MAAY;AAClC,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,QACrB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO;AAEb,SAAO;AAAA,IACC,YAAY;AAAA;AAChB,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,MAAM,MAAM;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAEA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,mBAAO,yBAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,IACM,KAAK,SAAqB;AAAA;AAC9B,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,mBAAe,yBAAW,OAAO,GAAG,QAAQ,OAAO,KAAK;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AAEA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,mBAAO,yBAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,EACF;AACF;","names":["_a"]}
package/dist/index.mjs CHANGED
@@ -34,33 +34,19 @@ var __async = (__this, __arguments, generator) => {
34
34
  });
35
35
  };
36
36
 
37
- // src/utils.ts
38
- function hexToBytes(hex) {
39
- if (hex.length && hex.length % 2 !== 0) {
40
- throw new Error(`Invalid hex string length: ${hex.length}`);
41
- }
42
- const matches = hex.match(/[\da-f]{2}/gi);
43
- if (!matches) {
44
- throw new Error("Invalid hex string: No valid hex digits found");
45
- }
46
- return new Uint8Array(matches.map((h) => Number.parseInt(h, 16)));
47
- }
48
- function bytesToHex(arr) {
49
- let hex = "";
50
- for (let i = 0; i < arr.length; i++) {
51
- let hexValue = arr[i].toString(16);
52
- if (hexValue.length === 1) {
53
- hexValue = `0${hexValue}`;
54
- }
55
- hex += hexValue;
56
- }
57
- return hex;
58
- }
37
+ // src/snap.ts
38
+ import { bytesToHex, hexToBytes } from "@sovereign-sdk/utils";
59
39
 
60
40
  // src/errors.ts
61
41
  var SignerError = class extends Error {
42
+ /**
43
+ * Create a new SignerError.
44
+ *
45
+ * @param message - The error message
46
+ * @param signerId - The ID of the signer that threw the error
47
+ */
62
48
  constructor(message, signerId) {
63
- super(message);
49
+ super(`[${signerId}] ${message}`);
64
50
  this.signerId = signerId;
65
51
  this.name = this.constructor.name;
66
52
  this.stack = new Error().stack;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/errors.ts","../src/snap.ts"],"sourcesContent":["export function hexToBytes(hex: string) {\n if (hex.length && hex.length % 2 !== 0) {\n throw new Error(`Invalid hex string length: ${hex.length}`);\n }\n\n const matches = hex.match(/[\\da-f]{2}/gi);\n\n if (!matches) {\n throw new Error(\"Invalid hex string: No valid hex digits found\");\n }\n\n return new Uint8Array(matches.map((h) => Number.parseInt(h, 16)));\n}\n\nexport function bytesToHex(arr: Uint8Array): string {\n let hex = \"\";\n for (let i = 0; i < arr.length; i++) {\n let hexValue = arr[i].toString(16);\n if (hexValue.length === 1) {\n hexValue = `0${hexValue}`;\n }\n hex += hexValue;\n }\n return hex;\n}\n","export class SignerError extends Error {\n public readonly signerId: string;\n\n constructor(message: string, signerId: string) {\n super(message);\n\n this.signerId = signerId;\n this.name = this.constructor.name;\n this.stack = new Error().stack;\n }\n}\n","/// <reference path=\"./snap-env.d.ts\" />\n\nimport type { MetaMaskInpageProvider } from \"@metamask/providers\";\nimport { Signer, SignerOpt } from \"./signer\";\nimport { bytesToHex, hexToBytes } from \"./utils\";\nimport { SignerError } from \"./errors\";\n\nexport type MetaMaskSnapSignerOpt = {\n provider?: MetaMaskInpageProvider;\n snapId?: string;\n} & SignerOpt;\n\nexport const newMetaMaskSnapSigner = ({\n curve,\n schema,\n snapId = \"npm:@sovereign-sdk/metamask-snap\",\n ...rest\n}: MetaMaskSnapSignerOpt): Signer => {\n const signerId = \"MetaMaskSnap\";\n const provider = rest.provider ?? window.ethereum;\n\n if (!provider) {\n throw new SignerError(\"Failed to find provider for signer\", signerId);\n }\n\n const assertSupported = async () => {\n try {\n await provider.request({\n method: \"wallet_getSnaps\",\n });\n } catch {\n throw new SignerError(\n \"Provider does not support MetaMask snaps\",\n signerId\n );\n }\n };\n\n const path = 0;\n\n return {\n async publicKey() {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"getPublicKey\",\n params: { path, curve },\n },\n },\n };\n const { publicKey } = (await provider.request(args)) as any;\n\n return hexToBytes(publicKey);\n },\n async sign(message: Uint8Array) {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"signTransaction\",\n params: { unsignedTxHex: bytesToHex(message), schema, curve, path },\n },\n },\n };\n const { signature } = (await provider.request(args)) as any;\n\n return hexToBytes(signature);\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAO,SAAS,WAAW,KAAa;AACtC,MAAI,IAAI,UAAU,IAAI,SAAS,MAAM,GAAG;AACtC,UAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,EAAE;AAAA,EAC5D;AAEA,QAAM,UAAU,IAAI,MAAM,cAAc;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,SAAO,IAAI,WAAW,QAAQ,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,CAAC,CAAC;AAClE;AAEO,SAAS,WAAW,KAAyB;AAClD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,QAAI,WAAW,IAAI,CAAC,EAAE,SAAS,EAAE;AACjC,QAAI,SAAS,WAAW,GAAG;AACzB,iBAAW,IAAI,QAAQ;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACxBO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAGrC,YAAY,SAAiB,UAAkB;AAC7C,UAAM,OAAO;AAEb,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,QAAQ,IAAI,MAAM,EAAE;AAAA,EAC3B;AACF;;;ACEO,IAAM,wBAAwB,CAAC,OAKD;AALC,eACpC;AAAA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAfX,IAYsC,IAIjC,iBAJiC,IAIjC;AAAA,IAHH;AAAA,IACA;AAAA,IACA;AAAA;AAfF,MAAAA;AAkBE,QAAM,WAAW;AACjB,QAAM,YAAWA,MAAA,KAAK,aAAL,OAAAA,MAAiB,OAAO;AAEzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,YAAY,sCAAsC,QAAQ;AAAA,EACtE;AAEA,QAAM,kBAAkB,MAAY;AAClC,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,QACrB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO;AAEb,SAAO;AAAA,IACC,YAAY;AAAA;AAChB,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,MAAM,MAAM;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AACA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,IACM,KAAK,SAAqB;AAAA;AAC9B,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,eAAe,WAAW,OAAO,GAAG,QAAQ,OAAO,KAAK;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AACA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,EACF;AACF;","names":["_a"]}
1
+ {"version":3,"sources":["../src/snap.ts","../src/errors.ts"],"sourcesContent":["/// <reference path=\"./snap-env.d.ts\" />\n\nimport type { MetaMaskInpageProvider } from \"@metamask/providers\";\nimport { bytesToHex, hexToBytes } from \"@sovereign-sdk/utils\";\nimport { SignerError } from \"./errors\";\nimport type { Signer, SignerOpt } from \"./signer\";\n\n/**\n * Options for initializing a MetaMask Snap signer.\n */\nexport type MetaMaskSnapSignerOpt = {\n /**\n * The {@link MetaMaskInpageProvider} to use for the signer.\n *\n * If not provided, the signer will attempt to use the global `window.ethereum` provider.\n */\n provider?: MetaMaskInpageProvider;\n /**\n * The snap ID to use for the signer.\n *\n * Defaults to `npm:@sovereign-sdk/metamask-snap`.\n * Can be changed to `local:localhost:8080` for local development.\n */\n snapId?: string;\n} & SignerOpt;\n\n/**\n * Create a new MetaMask Snap signer.\n *\n * @param options - The {@link MetaMaskSnapSignerOpt} options.\n * @returns A {@link Signer} implementation utilizing Sovereign's MetaMask Snap.\n */\nexport const newMetaMaskSnapSigner = ({\n curve,\n schema,\n snapId = \"npm:@sovereign-sdk/metamask-snap\",\n ...rest\n}: MetaMaskSnapSignerOpt): Signer => {\n const signerId = \"MetaMaskSnap\";\n const provider = rest.provider ?? window.ethereum;\n\n if (!provider) {\n throw new SignerError(\"Failed to find provider for signer\", signerId);\n }\n\n const assertSupported = async () => {\n try {\n await provider.request({\n method: \"wallet_getSnaps\",\n });\n } catch {\n throw new SignerError(\n \"Provider does not support MetaMask snaps\",\n signerId,\n );\n }\n };\n\n const path = 0;\n\n return {\n async publicKey() {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"getPublicKey\",\n params: { path, curve },\n },\n },\n };\n // biome-ignore lint/suspicious/noExplicitAny: todo\n const { publicKey } = (await provider.request(args)) as any;\n\n return hexToBytes(publicKey);\n },\n async sign(message: Uint8Array) {\n await assertSupported();\n\n const args = {\n method: \"wallet_invokeSnap\",\n params: {\n snapId,\n request: {\n method: \"signTransaction\",\n params: { unsignedTxHex: bytesToHex(message), schema, curve, path },\n },\n },\n };\n // biome-ignore lint/suspicious/noExplicitAny: todo\n const { signature } = (await provider.request(args)) as any;\n\n return hexToBytes(signature);\n },\n };\n};\n","/**\n * An error that can be thrown by a signer.\n */\nexport class SignerError extends Error {\n public readonly signerId: string;\n\n /**\n * Create a new SignerError.\n *\n * @param message - The error message\n * @param signerId - The ID of the signer that threw the error\n */\n constructor(message: string, signerId: string) {\n super(`[${signerId}] ${message}`);\n\n this.signerId = signerId;\n this.name = this.constructor.name;\n this.stack = new Error().stack;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,SAAS,YAAY,kBAAkB;;;ACAhC,IAAM,cAAN,cAA0B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrC,YAAY,SAAiB,UAAkB;AAC7C,UAAM,IAAI,QAAQ,KAAK,OAAO,EAAE;AAEhC,SAAK,WAAW;AAChB,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,QAAQ,IAAI,MAAM,EAAE;AAAA,EAC3B;AACF;;;ADaO,IAAM,wBAAwB,CAAC,OAKD;AALC,eACpC;AAAA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EAnCX,IAgCsC,IAIjC,iBAJiC,IAIjC;AAAA,IAHH;AAAA,IACA;AAAA,IACA;AAAA;AAnCF,MAAAA;AAsCE,QAAM,WAAW;AACjB,QAAM,YAAWA,MAAA,KAAK,aAAL,OAAAA,MAAiB,OAAO;AAEzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,YAAY,sCAAsC,QAAQ;AAAA,EACtE;AAEA,QAAM,kBAAkB,MAAY;AAClC,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,QACrB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO;AAEb,SAAO;AAAA,IACC,YAAY;AAAA;AAChB,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,MAAM,MAAM;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAEA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,IACM,KAAK,SAAqB;AAAA;AAC9B,cAAM,gBAAgB;AAEtB,cAAM,OAAO;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,YACA,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,EAAE,eAAe,WAAW,OAAO,GAAG,QAAQ,OAAO,KAAK;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AAEA,cAAM,EAAE,UAAU,IAAK,MAAM,SAAS,QAAQ,IAAI;AAElD,eAAO,WAAW,SAAS;AAAA,MAC7B;AAAA;AAAA,EACF;AACF;","names":["_a"]}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@sovereign-sdk/signers",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Signer interface and default implementations for use with Sovereign SDK applications",
5
5
  "files": [
6
6
  "dist",
7
+ "README.md",
7
8
  "package.json"
8
9
  ],
9
10
  "exports": {
@@ -18,22 +19,25 @@
18
19
  "types": "./dist/index.d.ts",
19
20
  "devDependencies": {
20
21
  "@metamask/providers": "^18.1.0",
21
- "biome": "^0.3.3",
22
22
  "tsup": "^8.3.0",
23
- "typescript": "^5.6.3"
23
+ "typescript": "^5.6.3",
24
+ "vitest": "^3.0.5"
24
25
  },
25
26
  "peerDependencies": {
26
- "biome": "^0.3.3",
27
27
  "tsup": "^8.3.0",
28
28
  "typescript": "^5.6.3"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public"
32
32
  },
33
+ "dependencies": {
34
+ "@sovereign-sdk/utils": "^0.0.3"
35
+ },
33
36
  "scripts": {
34
37
  "build": "tsup",
35
38
  "ci": "biome ci",
36
39
  "fix": "biome check --write",
37
- "lint": "biome lint"
40
+ "lint": "biome lint",
41
+ "test": "vitest"
38
42
  }
39
43
  }