viem 0.0.0-main.20240521T214213 → 0.0.0-main.20240521T215546

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 (88) hide show
  1. package/_cjs/actions/public/verifyMessage.js.map +1 -1
  2. package/_cjs/actions/siwe/verifySiweMessage.js +32 -0
  3. package/_cjs/actions/siwe/verifySiweMessage.js.map +1 -0
  4. package/_cjs/chains/definitions/flowPreviewnet.js +1 -1
  5. package/_cjs/chains/definitions/metis.js.map +1 -1
  6. package/_cjs/clients/decorators/public.js +2 -0
  7. package/_cjs/clients/decorators/public.js.map +1 -1
  8. package/_cjs/errors/siwe.js +22 -0
  9. package/_cjs/errors/siwe.js.map +1 -0
  10. package/_cjs/errors/version.js +1 -1
  11. package/_cjs/siwe/index.js +16 -0
  12. package/_cjs/siwe/index.js.map +1 -0
  13. package/_cjs/utils/siwe/createSiweMessage.js +122 -0
  14. package/_cjs/utils/siwe/createSiweMessage.js.map +1 -0
  15. package/_cjs/utils/siwe/generateSiweNonce.js +9 -0
  16. package/_cjs/utils/siwe/generateSiweNonce.js.map +1 -0
  17. package/_cjs/utils/siwe/parseSiweMessage.js +25 -0
  18. package/_cjs/utils/siwe/parseSiweMessage.js.map +1 -0
  19. package/_cjs/utils/siwe/types.js +3 -0
  20. package/_cjs/utils/siwe/types.js.map +1 -0
  21. package/_cjs/utils/siwe/utils.js +44 -0
  22. package/_cjs/utils/siwe/utils.js.map +1 -0
  23. package/_cjs/utils/siwe/validateSiweMessage.js +29 -0
  24. package/_cjs/utils/siwe/validateSiweMessage.js.map +1 -0
  25. package/_esm/actions/public/verifyMessage.js.map +1 -1
  26. package/_esm/actions/siwe/verifySiweMessage.js +39 -0
  27. package/_esm/actions/siwe/verifySiweMessage.js.map +1 -0
  28. package/_esm/chains/definitions/flowPreviewnet.js +1 -1
  29. package/_esm/chains/definitions/metis.js.map +1 -1
  30. package/_esm/clients/decorators/public.js +2 -0
  31. package/_esm/clients/decorators/public.js.map +1 -1
  32. package/_esm/errors/siwe.js +18 -0
  33. package/_esm/errors/siwe.js.map +1 -0
  34. package/_esm/errors/version.js +1 -1
  35. package/_esm/siwe/index.js +7 -0
  36. package/_esm/siwe/index.js.map +1 -0
  37. package/_esm/utils/siwe/createSiweMessage.js +137 -0
  38. package/_esm/utils/siwe/createSiweMessage.js.map +1 -0
  39. package/_esm/utils/siwe/generateSiweNonce.js +15 -0
  40. package/_esm/utils/siwe/generateSiweNonce.js.map +1 -0
  41. package/_esm/utils/siwe/parseSiweMessage.js +30 -0
  42. package/_esm/utils/siwe/parseSiweMessage.js.map +1 -0
  43. package/_esm/utils/siwe/types.js +2 -0
  44. package/_esm/utils/siwe/types.js.map +1 -0
  45. package/_esm/utils/siwe/utils.js +49 -0
  46. package/_esm/utils/siwe/utils.js.map +1 -0
  47. package/_esm/utils/siwe/validateSiweMessage.js +30 -0
  48. package/_esm/utils/siwe/validateSiweMessage.js.map +1 -0
  49. package/_types/actions/public/verifyMessage.d.ts +3 -2
  50. package/_types/actions/public/verifyMessage.d.ts.map +1 -1
  51. package/_types/actions/siwe/verifySiweMessage.d.ts +34 -0
  52. package/_types/actions/siwe/verifySiweMessage.d.ts.map +1 -0
  53. package/_types/chains/definitions/metis.d.ts.map +1 -1
  54. package/_types/clients/decorators/public.d.ts +30 -0
  55. package/_types/clients/decorators/public.d.ts.map +1 -1
  56. package/_types/errors/siwe.d.ts +13 -0
  57. package/_types/errors/siwe.d.ts.map +1 -0
  58. package/_types/errors/version.d.ts +1 -1
  59. package/_types/siwe/index.d.ts +8 -0
  60. package/_types/siwe/index.d.ts.map +1 -0
  61. package/_types/utils/siwe/createSiweMessage.d.ts +24 -0
  62. package/_types/utils/siwe/createSiweMessage.d.ts.map +1 -0
  63. package/_types/utils/siwe/generateSiweNonce.d.ts +12 -0
  64. package/_types/utils/siwe/generateSiweNonce.d.ts.map +1 -0
  65. package/_types/utils/siwe/parseSiweMessage.d.ts +11 -0
  66. package/_types/utils/siwe/parseSiweMessage.d.ts.map +1 -0
  67. package/_types/utils/siwe/types.d.ts +61 -0
  68. package/_types/utils/siwe/types.d.ts.map +1 -0
  69. package/_types/utils/siwe/utils.d.ts +2 -0
  70. package/_types/utils/siwe/utils.d.ts.map +1 -0
  71. package/_types/utils/siwe/validateSiweMessage.d.ts +39 -0
  72. package/_types/utils/siwe/validateSiweMessage.d.ts.map +1 -0
  73. package/actions/public/verifyMessage.ts +11 -8
  74. package/actions/siwe/verifySiweMessage.ts +90 -0
  75. package/chains/definitions/flowPreviewnet.ts +1 -1
  76. package/chains/definitions/metis.ts +2 -1
  77. package/clients/decorators/public.ts +37 -0
  78. package/errors/siwe.ts +20 -0
  79. package/errors/version.ts +1 -1
  80. package/package.json +9 -1
  81. package/siwe/index.ts +29 -0
  82. package/siwe/package.json +6 -0
  83. package/utils/siwe/createSiweMessage.ts +168 -0
  84. package/utils/siwe/generateSiweNonce.ts +15 -0
  85. package/utils/siwe/parseSiweMessage.ts +55 -0
  86. package/utils/siwe/types.ts +61 -0
  87. package/utils/siwe/utils.ts +51 -0
  88. package/utils/siwe/validateSiweMessage.ts +70 -0
@@ -0,0 +1,61 @@
1
+ import type { Address } from 'abitype';
2
+ /**
3
+ * @description EIP-4361 message fields
4
+ *
5
+ * @see https://eips.ethereum.org/EIPS/eip-4361
6
+ */
7
+ export type SiweMessage = {
8
+ /**
9
+ * The Ethereum address performing the signing.
10
+ */
11
+ address: Address;
12
+ /**
13
+ * The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) Chain ID to which the session is bound,
14
+ */
15
+ chainId: number;
16
+ /**
17
+ * [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority that is requesting the signing.
18
+ */
19
+ domain: string;
20
+ /**
21
+ * Time when the signed authentication message is no longer valid.
22
+ */
23
+ expirationTime?: Date | undefined;
24
+ /**
25
+ * Time when the message was generated, typically the current time.
26
+ */
27
+ issuedAt?: Date | undefined;
28
+ /**
29
+ * A random string typically chosen by the relying party and used to prevent replay attacks.
30
+ */
31
+ nonce: string;
32
+ /**
33
+ * Time when the signed authentication message will become valid.
34
+ */
35
+ notBefore?: Date | undefined;
36
+ /**
37
+ * A system-specific identifier that may be used to uniquely refer to the sign-in request.
38
+ */
39
+ requestId?: string | undefined;
40
+ /**
41
+ * A list of information or references to information the user wishes to have resolved as part of authentication by the relying party.
42
+ */
43
+ resources?: string[] | undefined;
44
+ /**
45
+ * [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme of the origin of the request.
46
+ */
47
+ scheme?: string | undefined;
48
+ /**
49
+ * A human-readable ASCII assertion that the user will sign.
50
+ */
51
+ statement?: string | undefined;
52
+ /**
53
+ * [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) URI referring to the resource that is the subject of the signing (as in the subject of a claim).
54
+ */
55
+ uri: string;
56
+ /**
57
+ * The current version of the SIWE Message.
58
+ */
59
+ version: '1';
60
+ };
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../utils/siwe/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,cAAc,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IACjC;;OAEG;IACH,QAAQ,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IAC3B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAChC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;OAEG;IACH,OAAO,EAAE,GAAG,CAAA;CACb,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function isUri(value: string): string | false;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../utils/siwe/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,kBA4ClC"}
@@ -0,0 +1,39 @@
1
+ import type { Address } from 'abitype';
2
+ import type { ExactPartial } from '../../types/utils.js';
3
+ import type { SiweMessage } from './types.js';
4
+ export type ValidateSiweMessageParameters = {
5
+ /**
6
+ * Ethereum address to check against.
7
+ */
8
+ address?: Address | undefined;
9
+ /**
10
+ * [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority to check against.
11
+ */
12
+ domain?: string | undefined;
13
+ /**
14
+ * EIP-4361 message fields.
15
+ */
16
+ message: ExactPartial<SiweMessage>;
17
+ /**
18
+ * Random string to check against.
19
+ */
20
+ nonce?: string | undefined;
21
+ /**
22
+ * [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme to check against.
23
+ */
24
+ scheme?: string | undefined;
25
+ /**
26
+ * Current time to check optional `expirationTime` and `notBefore` fields.
27
+ *
28
+ * @default new Date()
29
+ */
30
+ time?: Date | undefined;
31
+ };
32
+ export type ValidateSiweMessageReturnType = boolean;
33
+ /**
34
+ * @description Validates EIP-4361 message.
35
+ *
36
+ * @see https://eips.ethereum.org/EIPS/eip-4361
37
+ */
38
+ export declare function validateSiweMessage(parameters: ValidateSiweMessageParameters): ValidateSiweMessageReturnType;
39
+ //# sourceMappingURL=validateSiweMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateSiweMessage.d.ts","sourceRoot":"","sources":["../../../utils/siwe/validateSiweMessage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAA;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAA;AAEnD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,6BAA6B,GACxC,6BAA6B,CAyB/B"}
@@ -10,6 +10,7 @@ import type {
10
10
  SignableMessage,
11
11
  Signature,
12
12
  } from '../../types/misc.js'
13
+ import type { Prettify } from '../../types/utils.js'
13
14
  import { hashMessage } from '../../utils/signature/hashMessage.js'
14
15
  import type { HashMessageErrorType } from '../../utils/signature/hashMessage.js'
15
16
  import {
@@ -18,14 +19,16 @@ import {
18
19
  verifyHash,
19
20
  } from './verifyHash.js'
20
21
 
21
- export type VerifyMessageParameters = Omit<VerifyHashParameters, 'hash'> & {
22
- /** The address that signed the original message. */
23
- address: Address
24
- /** The message to be verified. */
25
- message: SignableMessage
26
- /** The signature that was generated by signing the message with the address's private key. */
27
- signature: Hex | ByteArray | Signature
28
- }
22
+ export type VerifyMessageParameters = Prettify<
23
+ Omit<VerifyHashParameters, 'hash'> & {
24
+ /** The address that signed the original message. */
25
+ address: Address
26
+ /** The message to be verified. */
27
+ message: SignableMessage
28
+ /** The signature that was generated by signing the message with the address's private key. */
29
+ signature: Hex | ByteArray | Signature
30
+ }
31
+ >
29
32
 
30
33
  export type VerifyMessageReturnType = boolean
31
34
 
@@ -0,0 +1,90 @@
1
+ import type { Client } from '../../clients/createClient.js'
2
+ import type { Transport } from '../../clients/transports/createTransport.js'
3
+ import type { ErrorType } from '../../errors/utils.js'
4
+ import type { Chain } from '../../types/chain.js'
5
+ import type { Hex } from '../../types/misc.js'
6
+ import type { Prettify } from '../../types/utils.js'
7
+ import { hashMessage } from '../../utils/signature/hashMessage.js'
8
+ import type { HashMessageErrorType } from '../../utils/signature/hashMessage.js'
9
+ import { parseSiweMessage } from '../../utils/siwe/parseSiweMessage.js'
10
+ import {
11
+ type ValidateSiweMessageParameters,
12
+ validateSiweMessage,
13
+ } from '../../utils/siwe/validateSiweMessage.js'
14
+ import {
15
+ type VerifyHashErrorType,
16
+ type VerifyHashParameters,
17
+ verifyHash,
18
+ } from '../public/verifyHash.js'
19
+
20
+ export type VerifySiweMessageParameters = Prettify<
21
+ Pick<VerifyHashParameters, 'blockNumber' | 'blockTag'> &
22
+ Pick<
23
+ ValidateSiweMessageParameters,
24
+ 'address' | 'domain' | 'nonce' | 'scheme' | 'time'
25
+ > & {
26
+ /**
27
+ * EIP-4361 formatted message.
28
+ */
29
+ message: string
30
+ /**
31
+ * Signature to check against.
32
+ */
33
+ signature: Hex
34
+ }
35
+ >
36
+
37
+ export type VerifySiweMessageReturnType = boolean
38
+
39
+ export type VerifySiweMessageErrorType =
40
+ | HashMessageErrorType
41
+ | VerifyHashErrorType
42
+ | ErrorType
43
+
44
+ /**
45
+ * Verifies [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message was signed.
46
+ *
47
+ * Compatible with Smart Contract Accounts & Externally Owned Accounts via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492).
48
+ *
49
+ * - Docs {@link https://viem.sh/docs/siwe/actions/verifySiweMessage}
50
+ *
51
+ * @param client - Client to use.
52
+ * @param parameters - {@link VerifySiweMessageParameters}
53
+ * @returns Whether or not the signature is valid. {@link VerifySiweMessageReturnType}
54
+ */
55
+ export async function verifySiweMessage<chain extends Chain | undefined>(
56
+ client: Client<Transport, chain>,
57
+ parameters: VerifySiweMessageParameters,
58
+ ): Promise<VerifySiweMessageReturnType> {
59
+ const {
60
+ address,
61
+ domain,
62
+ message,
63
+ nonce,
64
+ scheme,
65
+ signature,
66
+ time = new Date(),
67
+ ...callRequest
68
+ } = parameters
69
+
70
+ const parsed = parseSiweMessage(message)
71
+ if (!parsed.address) return false
72
+
73
+ const isValid = validateSiweMessage({
74
+ address,
75
+ domain,
76
+ message: parsed,
77
+ nonce,
78
+ scheme,
79
+ time,
80
+ })
81
+ if (!isValid) return false
82
+
83
+ const hash = hashMessage(message)
84
+ return verifyHash(client, {
85
+ address: parsed.address,
86
+ hash,
87
+ signature,
88
+ ...callRequest,
89
+ })
90
+ }
@@ -21,7 +21,7 @@ export const flowPreviewnet = /*#__PURE__*/ defineChain({
21
21
  },
22
22
  contracts: {
23
23
  multicall3: {
24
- address: "0xca11bde05977b3631167028862be2a173976ca11",
24
+ address: '0xca11bde05977b3631167028862be2a173976ca11',
25
25
  blockCreated: 6205,
26
26
  },
27
27
  },
@@ -15,7 +15,8 @@ export const metis = /*#__PURE__*/ defineChain({
15
15
  default: {
16
16
  name: 'Metis Explorer',
17
17
  url: 'https://explorer.metis.io',
18
- apiUrl: 'https://api.routescan.io/v2/network/mainnet/evm/43114/etherscan/api',
18
+ apiUrl:
19
+ 'https://api.routescan.io/v2/network/mainnet/evm/43114/etherscan/api',
19
20
  },
20
21
  blockscout: {
21
22
  name: 'Andromeda Explorer',
@@ -220,6 +220,11 @@ import {
220
220
  type WatchPendingTransactionsReturnType,
221
221
  watchPendingTransactions,
222
222
  } from '../../actions/public/watchPendingTransactions.js'
223
+ import {
224
+ type VerifySiweMessageParameters,
225
+ type VerifySiweMessageReturnType,
226
+ verifySiweMessage,
227
+ } from '../../actions/siwe/verifySiweMessage.js'
223
228
  import {
224
229
  type PrepareTransactionRequestParameters,
225
230
  type PrepareTransactionRequestRequest,
@@ -1511,9 +1516,40 @@ export type PublicActions<
1511
1516
  accountOverride
1512
1517
  >
1513
1518
  >
1519
+ /**
1520
+ * Verify that a message was signed by the provided address.
1521
+ *
1522
+ * Compatible with Smart Contract Accounts & Externally Owned Accounts via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492).
1523
+ *
1524
+ * - Docs {@link https://viem.sh/docs/actions/public/verifyMessage}
1525
+ *
1526
+ * @param parameters - {@link VerifyMessageParameters}
1527
+ * @returns Whether or not the signature is valid. {@link VerifyMessageReturnType}
1528
+ */
1514
1529
  verifyMessage: (
1515
1530
  args: VerifyMessageParameters,
1516
1531
  ) => Promise<VerifyMessageReturnType>
1532
+ /**
1533
+ * Verifies [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message was signed.
1534
+ *
1535
+ * Compatible with Smart Contract Accounts & Externally Owned Accounts via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492).
1536
+ *
1537
+ * - Docs {@link https://viem.sh/docs/siwe/actions/verifySiweMessage}
1538
+ *
1539
+ * @param parameters - {@link VerifySiweMessageParameters}
1540
+ * @returns Whether or not the signature is valid. {@link VerifySiweMessageReturnType}
1541
+ */
1542
+ verifySiweMessage: (
1543
+ args: VerifySiweMessageParameters,
1544
+ ) => Promise<VerifySiweMessageReturnType>
1545
+ /**
1546
+ * Verify that typed data was signed by the provided address.
1547
+ *
1548
+ * - Docs {@link https://viem.sh/docs/actions/public/verifyTypedData}
1549
+ *
1550
+ * @param parameters - {@link VerifyTypedDataParameters}
1551
+ * @returns Whether or not the signature is valid. {@link VerifyTypedDataReturnType}
1552
+ */
1517
1553
  verifyTypedData: (
1518
1554
  args: VerifyTypedDataParameters,
1519
1555
  ) => Promise<VerifyTypedDataReturnType>
@@ -1807,6 +1843,7 @@ export function publicActions<
1807
1843
  sendRawTransaction: (args) => sendRawTransaction(client, args),
1808
1844
  simulateContract: (args) => simulateContract(client, args),
1809
1845
  verifyMessage: (args) => verifyMessage(client, args),
1846
+ verifySiweMessage: (args) => verifySiweMessage(client, args),
1810
1847
  verifyTypedData: (args) => verifyTypedData(client, args),
1811
1848
  uninstallFilter: (args) => uninstallFilter(client, args),
1812
1849
  waitForTransactionReceipt: (args) =>
package/errors/siwe.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { BaseError } from './base.js'
2
+
3
+ export type SiweInvalidMessageFieldErrorType = SiweInvalidMessageFieldError & {
4
+ name: 'SiweInvalidMessageFieldError'
5
+ }
6
+ export class SiweInvalidMessageFieldError extends BaseError {
7
+ override name = 'SiweInvalidMessageFieldError'
8
+ constructor(parameters: {
9
+ docsPath?: string | undefined
10
+ field: string
11
+ metaMessages?: string[] | undefined
12
+ }) {
13
+ const { docsPath, field, metaMessages } = parameters
14
+ super(`Invalid Sign-In with Ethereum message field "${field}".`, {
15
+ docsPath,
16
+ docsSlug: 'TODO',
17
+ metaMessages,
18
+ })
19
+ }
20
+ }
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.0.0-main.20240521T214213'
1
+ export const version = '0.0.0-main.20240521T215546'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "viem",
3
3
  "description": "TypeScript Interface for Ethereum",
4
- "version": "0.0.0-main.20240521T214213",
4
+ "version": "0.0.0-main.20240521T215546",
5
5
  "type": "module",
6
6
  "main": "./_cjs/index.js",
7
7
  "module": "./_esm/index.js",
@@ -69,6 +69,11 @@
69
69
  "import": "./_esm/op-stack/index.js",
70
70
  "default": "./_cjs/op-stack/index.js"
71
71
  },
72
+ "./siwe": {
73
+ "types": "./_types/siwe/index.d.ts",
74
+ "import": "./_esm/siwe/index.js",
75
+ "default": "./_cjs/siwe/index.js"
76
+ },
72
77
  "./utils": {
73
78
  "types": "./_types/utils/index.d.ts",
74
79
  "import": "./_esm/utils/index.js",
@@ -115,6 +120,9 @@
115
120
  "op-stack": [
116
121
  "./_types/op-stack/index.d.ts"
117
122
  ],
123
+ "siwe": [
124
+ "./_types/siwe/index.d.ts"
125
+ ],
118
126
  "utils": [
119
127
  "./_types/utils/index.d.ts"
120
128
  ],
package/siwe/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ export {
2
+ verifySiweMessage,
3
+ type VerifySiweMessageParameters,
4
+ type VerifySiweMessageReturnType,
5
+ type VerifySiweMessageErrorType,
6
+ } from '../actions/siwe/verifySiweMessage.js'
7
+
8
+ export {
9
+ createSiweMessage,
10
+ type CreateSiweMessageParameters,
11
+ type CreateSiweMessageReturnType,
12
+ type CreateSiweMessageErrorType,
13
+ } from '../utils/siwe/createSiweMessage.js'
14
+
15
+ export { generateSiweNonce } from '../utils/siwe/generateSiweNonce.js'
16
+ export { parseSiweMessage } from '../utils/siwe/parseSiweMessage.js'
17
+
18
+ export {
19
+ validateSiweMessage,
20
+ type ValidateSiweMessageParameters,
21
+ type ValidateSiweMessageReturnType,
22
+ } from '../utils/siwe/validateSiweMessage.js'
23
+
24
+ export type { SiweMessage } from '../utils/siwe/types.js'
25
+
26
+ export {
27
+ type SiweInvalidMessageFieldErrorType,
28
+ SiweInvalidMessageFieldError,
29
+ } from '../errors/siwe.js'
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "module",
3
+ "types": "../_types/siwe/index.d.ts",
4
+ "module": "../_esm/siwe/index.js",
5
+ "main": "../_cjs/siwe/index.js"
6
+ }
@@ -0,0 +1,168 @@
1
+ import {
2
+ SiweInvalidMessageFieldError,
3
+ type SiweInvalidMessageFieldErrorType,
4
+ } from '../../errors/siwe.js'
5
+ import type { ErrorType } from '../../errors/utils.js'
6
+ import { type GetAddressErrorType, getAddress } from '../address/getAddress.js'
7
+ import type { SiweMessage } from './types.js'
8
+ import { isUri } from './utils.js'
9
+
10
+ export type CreateSiweMessageParameters = SiweMessage
11
+
12
+ export type CreateSiweMessageReturnType = string
13
+
14
+ export type CreateSiweMessageErrorType =
15
+ | GetAddressErrorType
16
+ | SiweInvalidMessageFieldErrorType
17
+ | ErrorType
18
+
19
+ /**
20
+ * @description Creates EIP-4361 formatted message.
21
+ *
22
+ * @example
23
+ * const message = createMessage({
24
+ * address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
25
+ * chainId: 1,
26
+ * domain: 'example.com',
27
+ * nonce: 'foobarbaz',
28
+ * uri: 'https://example.com/path',
29
+ * version: '1',
30
+ * })
31
+ *
32
+ * @see https://eips.ethereum.org/EIPS/eip-4361
33
+ */
34
+ export function createSiweMessage(
35
+ parameters: CreateSiweMessageParameters,
36
+ ): CreateSiweMessageReturnType {
37
+ const {
38
+ chainId,
39
+ domain,
40
+ expirationTime,
41
+ issuedAt = new Date(),
42
+ nonce,
43
+ notBefore,
44
+ requestId,
45
+ resources,
46
+ scheme,
47
+ uri,
48
+ version,
49
+ } = parameters
50
+
51
+ // Validate fields
52
+ {
53
+ // Required fields
54
+ if (chainId !== Math.floor(chainId))
55
+ throw new SiweInvalidMessageFieldError({
56
+ field: 'chainId',
57
+ metaMessages: [
58
+ '- Chain ID must be a EIP-155 chain ID.',
59
+ '- See https://eips.ethereum.org/EIPS/eip-155',
60
+ '',
61
+ `Provided value: ${chainId}`,
62
+ ],
63
+ })
64
+ if (!domainRegex.test(domain))
65
+ throw new SiweInvalidMessageFieldError({
66
+ field: 'domain',
67
+ metaMessages: [
68
+ '- Domain must be an RFC 3986 authority.',
69
+ '- See https://www.rfc-editor.org/rfc/rfc3986',
70
+ '',
71
+ `Provided value: ${domain}`,
72
+ ],
73
+ })
74
+ if (!nonceRegex.test(nonce))
75
+ throw new SiweInvalidMessageFieldError({
76
+ field: 'nonce',
77
+ metaMessages: [
78
+ '- Nonce must be at least 8 characters.',
79
+ '- Nonce must be alphanumeric.',
80
+ '',
81
+ `Provided value: ${nonce}`,
82
+ ],
83
+ })
84
+ if (!isUri(uri))
85
+ throw new SiweInvalidMessageFieldError({
86
+ field: 'uri',
87
+ metaMessages: [
88
+ '- URI must be a RFC 3986 URI referring to the resource that is the subject of the signing.',
89
+ '- See https://www.rfc-editor.org/rfc/rfc3986',
90
+ '',
91
+ `Provided value: ${uri}`,
92
+ ],
93
+ })
94
+ if (version !== '1')
95
+ throw new SiweInvalidMessageFieldError({
96
+ field: 'version',
97
+ metaMessages: [
98
+ "- Version must be '1'.",
99
+ '',
100
+ `Provided value: ${version}`,
101
+ ],
102
+ })
103
+
104
+ // Optional fields
105
+ if (scheme && !schemeRegex.test(scheme))
106
+ throw new SiweInvalidMessageFieldError({
107
+ field: 'scheme',
108
+ metaMessages: [
109
+ '- Scheme must be an RFC 3986 URI scheme.',
110
+ '- See https://www.rfc-editor.org/rfc/rfc3986#section-3.1',
111
+ '',
112
+ `Provided value: ${scheme}`,
113
+ ],
114
+ })
115
+ const statement = parameters.statement
116
+ if (statement?.includes('\n'))
117
+ throw new SiweInvalidMessageFieldError({
118
+ field: 'statement',
119
+ metaMessages: [
120
+ "- Statement must not include '\\n'.",
121
+ '',
122
+ `Provided value: ${statement}`,
123
+ ],
124
+ })
125
+ }
126
+
127
+ // Construct message
128
+ const address = getAddress(parameters.address)
129
+ const origin = (() => {
130
+ if (scheme) return `${scheme}://${domain}`
131
+ return domain
132
+ })()
133
+ const statement = (() => {
134
+ if (!parameters.statement) return ''
135
+ return `\n${parameters.statement}\n`
136
+ })()
137
+ const prefix = `${origin} wants you to sign in with your Ethereum account:\n${address}\n${statement}`
138
+
139
+ let suffix = `URI: ${uri}\nVersion: ${version}\nChain ID: ${chainId}\nNonce: ${nonce}\nIssued At: ${issuedAt.toISOString()}`
140
+
141
+ if (expirationTime)
142
+ suffix += `\nExpiration Time: ${expirationTime.toISOString()}`
143
+ if (notBefore) suffix += `\nNot Before: ${notBefore.toISOString()}`
144
+ if (requestId) suffix += `\nRequest ID: ${requestId}`
145
+ if (resources) {
146
+ let content = '\nResources:'
147
+ for (const resource of resources) {
148
+ if (!isUri(resource))
149
+ throw new SiweInvalidMessageFieldError({
150
+ field: 'resources',
151
+ metaMessages: [
152
+ '- Every resource must be a RFC 3986 URI.',
153
+ '- See https://www.rfc-editor.org/rfc/rfc3986',
154
+ '',
155
+ `Provided value: ${resource}`,
156
+ ],
157
+ })
158
+ content += `\n- ${resource}`
159
+ }
160
+ suffix += content
161
+ }
162
+
163
+ return `${prefix}\n${suffix}`
164
+ }
165
+
166
+ const domainRegex = /^(?:(?:(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,63})$/
167
+ const nonceRegex = /^[a-zA-Z0-9]{8,}$/
168
+ const schemeRegex = /^([a-zA-Z][a-zA-Z0-9+-.]*)$/
@@ -0,0 +1,15 @@
1
+ import { uid } from '../../utils/uid.js'
2
+
3
+ /**
4
+ * @description Generates random EIP-4361 nonce.
5
+ *
6
+ * @example
7
+ * const nonce = generateNonce()
8
+ *
9
+ * @see https://eips.ethereum.org/EIPS/eip-4361
10
+ *
11
+ * @returns A randomly generated EIP-4361 nonce.
12
+ */
13
+ export function generateSiweNonce(): string {
14
+ return uid(96)
15
+ }
@@ -0,0 +1,55 @@
1
+ import type { Address } from 'abitype'
2
+
3
+ import type { ExactPartial, Prettify } from '../../types/utils.js'
4
+ import type { SiweMessage } from './types.js'
5
+
6
+ /**
7
+ * @description Parses EIP-4361 formatted message into message fields object.
8
+ *
9
+ * @see https://eips.ethereum.org/EIPS/eip-4361
10
+ *
11
+ * @returns EIP-4361 fields object
12
+ */
13
+ export function parseSiweMessage(
14
+ message: string,
15
+ ): Prettify<ExactPartial<SiweMessage>> {
16
+ const { scheme, statement, ...prefix } = (message.match(prefixRegex)
17
+ ?.groups ?? {}) as {
18
+ address: Address
19
+ domain: string
20
+ scheme?: string
21
+ statement?: string
22
+ }
23
+ const { chainId, expirationTime, issuedAt, notBefore, requestId, ...suffix } =
24
+ (message.match(suffixRegex)?.groups ?? {}) as {
25
+ chainId: string
26
+ expirationTime?: string
27
+ issuedAt?: string
28
+ nonce: string
29
+ notBefore?: string
30
+ requestId?: string
31
+ uri: string
32
+ version: '1'
33
+ }
34
+ const resources = message.split('Resources:')[1]?.split('\n- ').slice(1)
35
+ return {
36
+ ...prefix,
37
+ ...suffix,
38
+ ...(chainId ? { chainId: Number(chainId) } : {}),
39
+ ...(expirationTime ? { expirationTime: new Date(expirationTime) } : {}),
40
+ ...(issuedAt ? { issuedAt: new Date(issuedAt) } : {}),
41
+ ...(notBefore ? { notBefore: new Date(notBefore) } : {}),
42
+ ...(requestId ? { requestId } : {}),
43
+ ...(resources ? { resources } : {}),
44
+ ...(scheme ? { scheme } : {}),
45
+ ...(statement ? { statement } : {}),
46
+ }
47
+ }
48
+
49
+ // https://regexr.com/80gdj
50
+ const prefixRegex =
51
+ /^(?:(?<scheme>[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?<domain>[a-zA-Z0-9+-.]*) (?:wants you to sign in with your Ethereum account:\n)(?<address>0x[a-fA-F0-9]{40})\n\n(?:(?<statement>.*)\n\n)?/
52
+
53
+ // https://regexr.com/80gf9
54
+ const suffixRegex =
55
+ /(?:URI: (?<uri>.+))\n(?:Version: (?<version>.+))\n(?:Chain ID: (?<chainId>\d+))\n(?:Nonce: (?<nonce>[a-zA-Z0-9]+))\n(?:Issued At: (?<issuedAt>.+))(?:\nExpiration Time: (?<expirationTime>.+))?(?:\nNot Before: (?<notBefore>.+))?(?:\nRequest ID: (?<requestId>.+))?/