tempo.ts 0.6.1 → 0.7.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 (113) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +6 -2
  3. package/dist/ox/Transaction.js +1 -1
  4. package/dist/ox/Transaction.js.map +1 -1
  5. package/dist/server/Handler.d.ts +346 -0
  6. package/dist/server/Handler.d.ts.map +1 -0
  7. package/dist/server/Handler.js +441 -0
  8. package/dist/server/Handler.js.map +1 -0
  9. package/dist/server/Kv.d.ts +16 -0
  10. package/dist/server/Kv.d.ts.map +1 -0
  11. package/dist/server/Kv.js +25 -0
  12. package/dist/server/Kv.js.map +1 -0
  13. package/dist/server/index.d.ts +3 -0
  14. package/dist/server/index.d.ts.map +1 -0
  15. package/dist/server/index.js +3 -0
  16. package/dist/server/index.js.map +1 -0
  17. package/dist/server/internal/requestListener.d.ts +124 -0
  18. package/dist/server/internal/requestListener.d.ts.map +1 -0
  19. package/dist/server/internal/requestListener.js +174 -0
  20. package/dist/server/internal/requestListener.js.map +1 -0
  21. package/dist/viem/Actions/account.d.ts +40 -0
  22. package/dist/viem/Actions/account.d.ts.map +1 -0
  23. package/dist/viem/Actions/account.js +87 -0
  24. package/dist/viem/Actions/account.js.map +1 -0
  25. package/dist/viem/Actions/amm.d.ts +51 -1245
  26. package/dist/viem/Actions/amm.d.ts.map +1 -1
  27. package/dist/viem/Actions/amm.js +15 -478
  28. package/dist/viem/Actions/amm.js.map +1 -1
  29. package/dist/viem/Actions/index.d.ts +1 -0
  30. package/dist/viem/Actions/index.d.ts.map +1 -1
  31. package/dist/viem/Actions/index.js +1 -0
  32. package/dist/viem/Actions/index.js.map +1 -1
  33. package/dist/viem/Actions/reward.d.ts +0 -1067
  34. package/dist/viem/Actions/reward.d.ts.map +1 -1
  35. package/dist/viem/Actions/reward.js +4 -212
  36. package/dist/viem/Actions/reward.js.map +1 -1
  37. package/dist/viem/Decorator.d.ts +28 -263
  38. package/dist/viem/Decorator.d.ts.map +1 -1
  39. package/dist/viem/Decorator.js +2 -10
  40. package/dist/viem/Decorator.js.map +1 -1
  41. package/dist/viem/Storage.d.ts +23 -0
  42. package/dist/viem/Storage.d.ts.map +1 -0
  43. package/dist/viem/Storage.js +47 -0
  44. package/dist/viem/Storage.js.map +1 -0
  45. package/dist/viem/Transport.d.ts +10 -1
  46. package/dist/viem/Transport.d.ts.map +1 -1
  47. package/dist/viem/Transport.js +22 -3
  48. package/dist/viem/Transport.js.map +1 -1
  49. package/dist/viem/internal/utils.d.ts +6 -0
  50. package/dist/viem/internal/utils.d.ts.map +1 -1
  51. package/dist/viem/internal/utils.js +24 -0
  52. package/dist/viem/internal/utils.js.map +1 -1
  53. package/dist/wagmi/Actions/amm.d.ts +0 -225
  54. package/dist/wagmi/Actions/amm.d.ts.map +1 -1
  55. package/dist/wagmi/Actions/amm.js +0 -248
  56. package/dist/wagmi/Actions/amm.js.map +1 -1
  57. package/dist/wagmi/Actions/reward.d.ts +0 -110
  58. package/dist/wagmi/Actions/reward.d.ts.map +1 -1
  59. package/dist/wagmi/Actions/reward.js +0 -121
  60. package/dist/wagmi/Actions/reward.js.map +1 -1
  61. package/dist/wagmi/Connector.d.ts +6 -17
  62. package/dist/wagmi/Connector.d.ts.map +1 -1
  63. package/dist/wagmi/Connector.js +17 -43
  64. package/dist/wagmi/Connector.js.map +1 -1
  65. package/dist/wagmi/Hooks/amm.d.ts +0 -236
  66. package/dist/wagmi/Hooks/amm.d.ts.map +1 -1
  67. package/dist/wagmi/Hooks/amm.js +0 -285
  68. package/dist/wagmi/Hooks/amm.js.map +1 -1
  69. package/dist/wagmi/Hooks/reward.d.ts +0 -88
  70. package/dist/wagmi/Hooks/reward.d.ts.map +1 -1
  71. package/dist/wagmi/Hooks/reward.js +0 -103
  72. package/dist/wagmi/Hooks/reward.js.map +1 -1
  73. package/dist/wagmi/KeyManager.d.ts +57 -0
  74. package/dist/wagmi/KeyManager.d.ts.map +1 -0
  75. package/dist/wagmi/KeyManager.js +101 -0
  76. package/dist/wagmi/KeyManager.js.map +1 -0
  77. package/dist/wagmi/index.d.ts +1 -0
  78. package/dist/wagmi/index.d.ts.map +1 -1
  79. package/dist/wagmi/index.js +1 -0
  80. package/dist/wagmi/index.js.map +1 -1
  81. package/package.json +8 -2
  82. package/src/ox/Transaction.ts +1 -1
  83. package/src/ox/e2e.test.ts +7 -0
  84. package/src/server/Handler.test.ts +566 -0
  85. package/src/server/Handler.ts +577 -0
  86. package/src/server/Kv.ts +40 -0
  87. package/src/server/index.ts +2 -0
  88. package/src/server/internal/requestListener.ts +285 -0
  89. package/src/viem/Actions/account.test.ts +414 -0
  90. package/src/viem/Actions/account.ts +108 -0
  91. package/src/viem/Actions/amm.test.ts +10 -284
  92. package/src/viem/Actions/amm.ts +88 -768
  93. package/src/viem/Actions/index.ts +1 -0
  94. package/src/viem/Actions/reward.test.ts +4 -212
  95. package/src/viem/Actions/reward.ts +4 -291
  96. package/src/viem/Decorator.test.ts +1 -0
  97. package/src/viem/Decorator.ts +32 -294
  98. package/src/viem/Storage.ts +88 -0
  99. package/src/viem/Transport.ts +40 -2
  100. package/src/viem/e2e.test.ts +106 -3
  101. package/src/viem/internal/utils.ts +21 -0
  102. package/src/wagmi/Actions/amm.test.ts +7 -85
  103. package/src/wagmi/Actions/amm.ts +0 -346
  104. package/src/wagmi/Actions/reward.test.ts +0 -99
  105. package/src/wagmi/Actions/reward.ts +0 -203
  106. package/src/wagmi/Connector.test.ts +4 -1
  107. package/src/wagmi/Connector.ts +24 -58
  108. package/src/wagmi/Hooks/amm.test.ts +8 -200
  109. package/src/wagmi/Hooks/amm.ts +0 -443
  110. package/src/wagmi/Hooks/reward.test.ts +1 -142
  111. package/src/wagmi/Hooks/reward.ts +0 -196
  112. package/src/wagmi/KeyManager.ts +159 -0
  113. package/src/wagmi/index.ts +1 -0
@@ -0,0 +1,285 @@
1
+ // @ts-nocheck
2
+ // Credit: https://github.com/mjackson/remix-the-web/blob/main/packages/node-fetch-server/src/lib/request-listener.ts
3
+
4
+ import type * as http from 'node:http'
5
+ import type * as http2 from 'node:http2'
6
+
7
+ export interface RequestListenerOptions {
8
+ /**
9
+ * Overrides the host portion of the incoming request URL. By default the request URL host is
10
+ * derived from the HTTP `Host` header.
11
+ *
12
+ * For example, if you have a `$HOST` environment variable that contains the hostname of your
13
+ * server, you can use it to set the host of all incoming request URLs like so:
14
+ *
15
+ * ```ts
16
+ * createRequestListener(handler, { host: process.env.HOST })
17
+ * ```
18
+ */
19
+ host?: string
20
+ /**
21
+ * An error handler that determines the response when the request handler throws an error. By
22
+ * default a 500 Internal Server Error response will be sent.
23
+ */
24
+ onError?: ErrorHandler
25
+ /**
26
+ * Overrides the protocol of the incoming request URL. By default the request URL protocol is
27
+ * derived from the connection protocol. So e.g. when serving over HTTPS (using
28
+ * `https.createServer()`), the request URL will begin with `https:`.
29
+ */
30
+ protocol?: string
31
+ }
32
+
33
+ /**
34
+ * Wraps a fetch handler in a Node.js request listener that can be used with:
35
+ *
36
+ * - [`http.createServer()`](https://nodejs.org/api/http.html#httpcreateserveroptions-requestlistener)
37
+ * - [`https.createServer()`](https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener)
38
+ * - [`http2.createServer()`](https://nodejs.org/api/http2.html#http2createserveroptions-onrequesthandler)
39
+ * - [`http2.createSecureServer()`](https://nodejs.org/api/http2.html#http2createsecureserveroptions-onrequesthandler)
40
+ *
41
+ * Example:
42
+ *
43
+ * ```ts
44
+ * import * as http from 'node:http';
45
+ * import { createRequestListener } from '@mjackson/node-fetch-server';
46
+ *
47
+ * async function handler(request) {
48
+ * return new Response('Hello, world!');
49
+ * }
50
+ *
51
+ * let server = http.createServer(
52
+ * createRequestListener(handler)
53
+ * );
54
+ *
55
+ * server.listen(3000);
56
+ * ```
57
+ *
58
+ * @param handler The fetch handler to use for processing incoming requests.
59
+ * @param options Request listener options.
60
+ * @returns A Node.js request listener function.
61
+ */
62
+ export function fromFetchHandler(
63
+ handler: FetchHandler,
64
+ options?: RequestListenerOptions,
65
+ ): http.RequestListener {
66
+ const onError = options?.onError ?? defaultErrorHandler
67
+
68
+ return async (req, res) => {
69
+ const request = createRequest(req, res, options)
70
+ const client = {
71
+ address: req.socket.remoteAddress!,
72
+ family: req.socket.remoteFamily! as ClientAddress['family'],
73
+ port: req.socket.remotePort!,
74
+ }
75
+
76
+ let response: Response
77
+ try {
78
+ response = await handler(request, client)
79
+ } catch (error) {
80
+ try {
81
+ response = (await onError(error)) ?? internalServerError()
82
+ } catch (error) {
83
+ console.error(`There was an error in the error handler: ${error}`)
84
+ response = internalServerError()
85
+ }
86
+ }
87
+
88
+ await sendResponse(res, response)
89
+ }
90
+ }
91
+
92
+ function defaultErrorHandler(error: unknown): Response {
93
+ console.error(error)
94
+ return internalServerError()
95
+ }
96
+
97
+ function internalServerError(): Response {
98
+ return new Response(
99
+ // "Internal Server Error"
100
+ new Uint8Array([
101
+ 73, 110, 116, 101, 114, 110, 97, 108, 32, 83, 101, 114, 118, 101, 114, 32,
102
+ 69, 114, 114, 111, 114,
103
+ ]),
104
+ {
105
+ headers: {
106
+ 'Content-Type': 'text/plain',
107
+ },
108
+ status: 500,
109
+ },
110
+ )
111
+ }
112
+
113
+ export type RequestOptions = Omit<RequestListenerOptions, 'onError'>
114
+
115
+ /**
116
+ * Creates a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object from
117
+ *
118
+ * - a [`http.IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage)/[`http.ServerResponse`](https://nodejs.org/api/http.html#class-httpserverresponse) pair
119
+ * - a [`http2.Http2ServerRequest`](https://nodejs.org/api/http2.html#class-http2http2serverrequest)/[`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#class-http2http2serverresponse) pair
120
+ *
121
+ * @param req The incoming request object.
122
+ * @param res The server response object.
123
+ * @param options
124
+ * @returns A request object.
125
+ */
126
+ export function createRequest(
127
+ req: http.IncomingMessage | http2.Http2ServerRequest,
128
+ res: http.ServerResponse | http2.Http2ServerResponse,
129
+ options?: RequestOptions,
130
+ ): Request {
131
+ const controller = new AbortController()
132
+ res.on('close', () => {
133
+ controller.abort()
134
+ })
135
+
136
+ const method = req.method ?? 'GET'
137
+ const headers = createHeaders(req)
138
+
139
+ const protocol =
140
+ options?.protocol ??
141
+ ('encrypted' in req.socket && req.socket.encrypted ? 'https:' : 'http:')
142
+ const host = options?.host ?? headers.get('Host') ?? 'localhost'
143
+ const url = new URL(req.url!, `${protocol}//${host}`)
144
+
145
+ const init: RequestInit = { headers, method, signal: controller.signal }
146
+
147
+ if (method !== 'GET' && method !== 'HEAD') {
148
+ init.body = new ReadableStream({
149
+ start(controller) {
150
+ req.on('data', (chunk) => {
151
+ controller.enqueue(
152
+ new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength),
153
+ )
154
+ })
155
+ req.on('end', () => {
156
+ controller.close()
157
+ })
158
+ },
159
+ })
160
+
161
+ // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.
162
+ // However, this property is not defined in the TypeScript types for RequestInit, so we have
163
+ // to cast it here in order to set it without a type error.
164
+ // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex
165
+ ;(init as { duplex: 'half' }).duplex = 'half'
166
+ }
167
+
168
+ return new Request(url, init)
169
+ }
170
+
171
+ /**
172
+ * Creates a [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object from the headers in a Node.js
173
+ * [`http.IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage)/[`http2.Http2ServerRequest`](https://nodejs.org/api/http2.html#class-http2http2serverrequest).
174
+ *
175
+ * @param req The incoming request object.
176
+ * @returns A headers object.
177
+ */
178
+ export function createHeaders(
179
+ req: http.IncomingMessage | http2.Http2ServerRequest,
180
+ ): Headers {
181
+ const headers = new Headers()
182
+
183
+ const rawHeaders = req.rawHeaders
184
+ for (let i = 0; i < rawHeaders.length; i += 2) {
185
+ if (rawHeaders[i]?.startsWith(':')) continue
186
+ headers.append(rawHeaders[i]!, rawHeaders[i + 1]!)
187
+ }
188
+
189
+ return headers
190
+ }
191
+
192
+ /**
193
+ * Sends a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) to the client using a Node.js
194
+ * [`http.ServerResponse`](https://nodejs.org/api/http.html#class-httpserverresponse)/[`http2.Http2ServerResponse`](https://nodejs.org/api/http2.html#class-http2http2serverresponse)
195
+ * object.
196
+ *
197
+ * @param res The server response object.
198
+ * @param response The response to send.
199
+ */
200
+ export async function sendResponse(
201
+ res: http.ServerResponse | http2.Http2ServerResponse,
202
+ response: Response,
203
+ ): Promise<void> {
204
+ // Iterate over response.headers so we are sure to send multiple Set-Cookie headers correctly.
205
+ // These would incorrectly be merged into a single header if we tried to use
206
+ // `Object.fromEntries(response.headers.entries())`.
207
+ const headers: Record<string, string | string[]> = {}
208
+ for (const [key, value] of response.headers as any) {
209
+ if (key in headers) {
210
+ if (Array.isArray(headers[key])) {
211
+ headers[key].push(value)
212
+ } else {
213
+ headers[key] = [headers[key] as string, value]
214
+ }
215
+ } else {
216
+ headers[key] = value
217
+ }
218
+ }
219
+
220
+ ;(res as any).writeHead(response.status, headers)
221
+
222
+ if (response.body != null && res.req.method !== 'HEAD') {
223
+ for await (const chunk of readStream(response.body)) {
224
+ // @ts-expect-error - Node typings for http2 require a 2nd parameter to write but it's optional
225
+ res.write(chunk)
226
+ }
227
+ }
228
+
229
+ res.end()
230
+ }
231
+
232
+ export async function* readStream(
233
+ stream: ReadableStream<Uint8Array>,
234
+ ): AsyncIterable<Uint8Array> {
235
+ const reader = stream.getReader()
236
+
237
+ while (true) {
238
+ const { done, value } = await reader.read()
239
+ if (done) break
240
+ yield value
241
+ }
242
+ }
243
+
244
+ export interface ClientAddress {
245
+ /**
246
+ * The IP address of the client that sent the request.
247
+ *
248
+ * [Node.js Reference](https://nodejs.org/api/net.html#socketremoteaddress)
249
+ */
250
+ address: string
251
+ /**
252
+ * The family of the client IP address.
253
+ *
254
+ * [Node.js Reference](https://nodejs.org/api/net.html#socketremotefamily)
255
+ */
256
+ family: 'IPv4' | 'IPv6'
257
+ /**
258
+ * The remote port of the client that sent the request.
259
+ *
260
+ * [Node.js Reference](https://nodejs.org/api/net.html#socketremoteport)
261
+ */
262
+ port: number
263
+ }
264
+
265
+ /**
266
+ * A function that handles an error that occurred during request handling. May return a response to
267
+ * send to the client, or `undefined` to allow the server to send a default error response.
268
+ *
269
+ * [MDN `Response` Reference](https://developer.mozilla.org/en-US/docs/Web/API/Response)
270
+ */
271
+ export type ErrorHandler = (
272
+ error: unknown,
273
+ ) => undefined | Response | Promise<undefined | Response>
274
+
275
+ /**
276
+ * A function that handles an incoming request and returns a response.
277
+ *
278
+ * [MDN `Request` Reference](https://developer.mozilla.org/en-US/docs/Web/API/Request)
279
+ *
280
+ * [MDN `Response` Reference](https://developer.mozilla.org/en-US/docs/Web/API/Response)
281
+ */
282
+ export type FetchHandler = (
283
+ request: Request,
284
+ client: ClientAddress,
285
+ ) => Response | Promise<Response>
@@ -0,0 +1,414 @@
1
+ import { Hex, P256, Secp256k1, WebCryptoP256 } from 'ox'
2
+ import { verifyMessage, verifyTypedData } from 'viem/actions'
3
+ import { describe, expect, test } from 'vitest'
4
+ import { client as baseClient } from '../../../test/viem/config.js'
5
+ import * as Account from '../Account.js'
6
+ import { decorator as tempoActions } from '../Decorator.js'
7
+ import * as actions from './account.js'
8
+
9
+ const client = baseClient.extend(tempoActions())
10
+
11
+ describe('verifyHash', () => {
12
+ test('secp256k1: default signature', async () => {
13
+ const privateKey = Secp256k1.randomPrivateKey()
14
+ const account = Account.fromSecp256k1(privateKey)
15
+
16
+ const hash = Hex.random(32)
17
+ const signature = await account.sign({ hash })
18
+
19
+ const valid = await actions.verifyHash(client, {
20
+ address: account.address,
21
+ hash,
22
+ signature,
23
+ })
24
+
25
+ expect(valid).toBe(true)
26
+ })
27
+
28
+ test('secp256k1: without address (recovers from signature)', async () => {
29
+ const privateKey = Secp256k1.randomPrivateKey()
30
+ const account = Account.fromSecp256k1(privateKey)
31
+
32
+ const hash = Hex.random(32)
33
+ const signature = await account.sign({ hash })
34
+
35
+ const valid = await actions.verifyHash(client, {
36
+ hash,
37
+ signature,
38
+ })
39
+
40
+ expect(valid).toBe(true)
41
+ })
42
+
43
+ test('secp256k1: invalid signature returns false', async () => {
44
+ const privateKey = Secp256k1.randomPrivateKey()
45
+ const account = Account.fromSecp256k1(privateKey)
46
+
47
+ const hash = Hex.random(32)
48
+ const wrongHash = Hex.random(32)
49
+ const signature = await account.sign({ hash })
50
+
51
+ const valid = await actions.verifyHash(client, {
52
+ address: account.address,
53
+ hash: wrongHash,
54
+ signature,
55
+ })
56
+
57
+ expect(valid).toBe(false)
58
+ })
59
+
60
+ test('p256: default signature', async () => {
61
+ const privateKey = P256.randomPrivateKey()
62
+ const account = Account.fromP256(privateKey)
63
+
64
+ const hash = Hex.random(32)
65
+ const signature = await account.sign({ hash })
66
+
67
+ const valid = await actions.verifyHash(client, {
68
+ address: account.address,
69
+ hash,
70
+ signature,
71
+ })
72
+
73
+ expect(valid).toBe(true)
74
+ })
75
+
76
+ test('p256: invalid signature returns false', async () => {
77
+ const privateKey = P256.randomPrivateKey()
78
+ const account = Account.fromP256(privateKey)
79
+
80
+ const hash = Hex.random(32)
81
+ const wrongHash = Hex.random(32)
82
+ const signature = await account.sign({ hash })
83
+
84
+ const valid = await actions.verifyHash(client, {
85
+ address: account.address,
86
+ hash: wrongHash,
87
+ signature,
88
+ })
89
+
90
+ expect(valid).toBe(false)
91
+ })
92
+
93
+ test('webCrypto p256: default signature', async () => {
94
+ const keyPair = await WebCryptoP256.createKeyPair()
95
+ const account = Account.fromWebCryptoP256(keyPair)
96
+
97
+ const hash = Hex.random(32)
98
+ const signature = await account.sign({ hash })
99
+
100
+ const valid = await actions.verifyHash(client, {
101
+ address: account.address,
102
+ hash,
103
+ signature,
104
+ })
105
+
106
+ expect(valid).toBe(true)
107
+ })
108
+
109
+ test('webCrypto p256: invalid signature returns false', async () => {
110
+ const keyPair = await WebCryptoP256.createKeyPair()
111
+ const account = Account.fromWebCryptoP256(keyPair)
112
+
113
+ const hash = Hex.random(32)
114
+ const wrongHash = Hex.random(32)
115
+ const signature = await account.sign({ hash })
116
+
117
+ const valid = await actions.verifyHash(client, {
118
+ address: account.address,
119
+ hash: wrongHash,
120
+ signature,
121
+ })
122
+
123
+ expect(valid).toBe(false)
124
+ })
125
+
126
+ test('headless webAuthn: default signature', async () => {
127
+ const privateKey = P256.randomPrivateKey()
128
+ const account = Account.fromHeadlessWebAuthn(privateKey, {
129
+ rpId: 'example.com',
130
+ origin: 'https://example.com',
131
+ })
132
+
133
+ const hash = Hex.random(32)
134
+ const signature = await account.sign({ hash })
135
+
136
+ const valid = await actions.verifyHash(client, {
137
+ address: account.address,
138
+ hash,
139
+ signature,
140
+ })
141
+
142
+ expect(valid).toBe(true)
143
+ })
144
+
145
+ test('headless webAuthn: invalid signature returns false', async () => {
146
+ const privateKey = P256.randomPrivateKey()
147
+ const account = Account.fromHeadlessWebAuthn(privateKey, {
148
+ rpId: 'example.com',
149
+ origin: 'https://example.com',
150
+ })
151
+
152
+ const hash = Hex.random(32)
153
+ const wrongHash = Hex.random(32)
154
+ const signature = await account.sign({ hash })
155
+
156
+ const valid = await actions.verifyHash(client, {
157
+ address: account.address,
158
+ hash: wrongHash,
159
+ signature,
160
+ })
161
+
162
+ expect(valid).toBe(false)
163
+ })
164
+
165
+ test('behavior: signature from wrong account returns false', async () => {
166
+ const privateKey1 = Secp256k1.randomPrivateKey()
167
+ const account1 = Account.fromSecp256k1(privateKey1)
168
+
169
+ const privateKey2 = Secp256k1.randomPrivateKey()
170
+ const account2 = Account.fromSecp256k1(privateKey2)
171
+
172
+ const hash = Hex.random(32)
173
+ const signature = await account1.sign({ hash })
174
+
175
+ // Try to verify with wrong address
176
+ const valid = await actions.verifyHash(client, {
177
+ address: account2.address,
178
+ hash,
179
+ signature,
180
+ })
181
+
182
+ expect(valid).toBe(false)
183
+ })
184
+
185
+ test('as inherited: verifyMessage with secp256k1', async () => {
186
+ const privateKey = Secp256k1.randomPrivateKey()
187
+ const account = Account.fromSecp256k1(privateKey)
188
+
189
+ const message = 'Hello, World!'
190
+ const signature = await account.signMessage({ message })
191
+
192
+ const valid = await verifyMessage(client, {
193
+ address: account.address,
194
+ message,
195
+ signature,
196
+ })
197
+
198
+ expect(valid).toBe(true)
199
+ })
200
+
201
+ test('as inherited: verifyMessage with p256', async () => {
202
+ const privateKey = P256.randomPrivateKey()
203
+ const account = Account.fromP256(privateKey)
204
+
205
+ const message = 'Hello, P256!'
206
+ const signature = await account.signMessage({ message })
207
+
208
+ const valid = await verifyMessage(client, {
209
+ address: account.address,
210
+ message,
211
+ signature,
212
+ })
213
+
214
+ expect(valid).toBe(true)
215
+ })
216
+
217
+ test('as inherited: verifyMessage with webCrypto p256', async () => {
218
+ const keyPair = await WebCryptoP256.createKeyPair()
219
+ const account = Account.fromWebCryptoP256(keyPair)
220
+
221
+ const message = 'Hello, WebCrypto!'
222
+ const signature = await account.signMessage({ message })
223
+
224
+ const valid = await verifyMessage(client, {
225
+ address: account.address,
226
+ message,
227
+ signature,
228
+ })
229
+
230
+ expect(valid).toBe(true)
231
+ })
232
+
233
+ test('as inherited: verifyMessage with headless webAuthn', async () => {
234
+ const privateKey = P256.randomPrivateKey()
235
+ const account = Account.fromHeadlessWebAuthn(privateKey, {
236
+ rpId: 'example.com',
237
+ origin: 'https://example.com',
238
+ })
239
+
240
+ const message = 'Hello, WebAuthn!'
241
+ const signature = await account.signMessage({ message })
242
+
243
+ const valid = await verifyMessage(client, {
244
+ address: account.address,
245
+ message,
246
+ signature,
247
+ })
248
+
249
+ expect(valid).toBe(true)
250
+ })
251
+
252
+ test('as inherited: verifyTypedData with secp256k1', async () => {
253
+ const privateKey = Secp256k1.randomPrivateKey()
254
+ const account = Account.fromSecp256k1(privateKey)
255
+
256
+ const domain = {
257
+ name: 'Test App',
258
+ version: '1',
259
+ chainId: 1,
260
+ }
261
+
262
+ const types = {
263
+ Person: [
264
+ { name: 'name', type: 'string' },
265
+ { name: 'wallet', type: 'address' },
266
+ ],
267
+ }
268
+
269
+ const message = {
270
+ name: 'Alice',
271
+ wallet: '0x0000000000000000000000000000000000000000',
272
+ }
273
+
274
+ const signature = await account.signTypedData({
275
+ domain,
276
+ types,
277
+ primaryType: 'Person',
278
+ message,
279
+ })
280
+
281
+ const valid = await verifyTypedData(client, {
282
+ address: account.address,
283
+ domain,
284
+ types,
285
+ primaryType: 'Person',
286
+ message,
287
+ signature,
288
+ })
289
+
290
+ expect(valid).toBe(true)
291
+ })
292
+
293
+ test('as inherited: verifyTypedData with p256', async () => {
294
+ const privateKey = P256.randomPrivateKey()
295
+ const account = Account.fromP256(privateKey)
296
+
297
+ const domain = {
298
+ name: 'P256 App',
299
+ version: '1',
300
+ chainId: 1,
301
+ }
302
+
303
+ const types = {
304
+ Message: [{ name: 'content', type: 'string' }],
305
+ }
306
+
307
+ const message = {
308
+ content: 'Hello from P256!',
309
+ }
310
+
311
+ const signature = await account.signTypedData({
312
+ domain,
313
+ types,
314
+ primaryType: 'Message',
315
+ message,
316
+ })
317
+
318
+ const valid = await verifyTypedData(client, {
319
+ address: account.address,
320
+ domain,
321
+ types,
322
+ primaryType: 'Message',
323
+ message,
324
+ signature,
325
+ })
326
+
327
+ expect(valid).toBe(true)
328
+ })
329
+
330
+ test('as inherited: verifyTypedData with webCrypto p256', async () => {
331
+ const keyPair = await WebCryptoP256.createKeyPair()
332
+ const account = Account.fromWebCryptoP256(keyPair)
333
+
334
+ const domain = {
335
+ name: 'WebCrypto App',
336
+ version: '1',
337
+ chainId: 1,
338
+ }
339
+
340
+ const types = {
341
+ Data: [
342
+ { name: 'value', type: 'uint256' },
343
+ { name: 'label', type: 'string' },
344
+ ],
345
+ }
346
+
347
+ const message = {
348
+ value: 42n,
349
+ label: 'test',
350
+ }
351
+
352
+ const signature = await account.signTypedData({
353
+ domain,
354
+ types,
355
+ primaryType: 'Data',
356
+ message,
357
+ })
358
+
359
+ const valid = await verifyTypedData(client, {
360
+ address: account.address,
361
+ domain,
362
+ types,
363
+ primaryType: 'Data',
364
+ message,
365
+ signature,
366
+ })
367
+
368
+ expect(valid).toBe(true)
369
+ })
370
+
371
+ test('as inherited: verifyTypedData with headless webAuthn', async () => {
372
+ const privateKey = P256.randomPrivateKey()
373
+ const account = Account.fromHeadlessWebAuthn(privateKey, {
374
+ rpId: 'example.com',
375
+ origin: 'https://example.com',
376
+ })
377
+
378
+ const domain = {
379
+ name: 'WebAuthn App',
380
+ version: '1',
381
+ chainId: 1,
382
+ }
383
+
384
+ const types = {
385
+ Auth: [
386
+ { name: 'user', type: 'address' },
387
+ { name: 'action', type: 'string' },
388
+ ],
389
+ }
390
+
391
+ const message = {
392
+ user: account.address,
393
+ action: 'login',
394
+ }
395
+
396
+ const signature = await account.signTypedData({
397
+ domain,
398
+ types,
399
+ primaryType: 'Auth',
400
+ message,
401
+ })
402
+
403
+ const valid = await verifyTypedData(client, {
404
+ address: account.address,
405
+ domain,
406
+ types,
407
+ primaryType: 'Auth',
408
+ message,
409
+ signature,
410
+ })
411
+
412
+ expect(valid).toBe(true)
413
+ })
414
+ })