accounts 0.12.2 → 0.14.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.
- package/CHANGELOG.md +35 -0
- package/README.md +6 -5
- package/dist/cli/adapter.d.ts.map +1 -1
- package/dist/cli/adapter.js +76 -69
- package/dist/cli/adapter.js.map +1 -1
- package/dist/core/AccessKey.d.ts +89 -106
- package/dist/core/AccessKey.d.ts.map +1 -1
- package/dist/core/AccessKey.js +230 -210
- package/dist/core/AccessKey.js.map +1 -1
- package/dist/core/Account.d.ts +0 -9
- package/dist/core/Account.d.ts.map +1 -1
- package/dist/core/Account.js +1 -13
- package/dist/core/Account.js.map +1 -1
- package/dist/core/Adapter.d.ts +24 -4
- package/dist/core/Adapter.d.ts.map +1 -1
- package/dist/core/Client.d.ts +1 -1
- package/dist/core/Client.d.ts.map +1 -1
- package/dist/core/Client.js.map +1 -1
- package/dist/core/Provider.d.ts +6 -7
- package/dist/core/Provider.d.ts.map +1 -1
- package/dist/core/Provider.js +73 -77
- package/dist/core/Provider.js.map +1 -1
- package/dist/core/Remote.d.ts +2 -0
- package/dist/core/Remote.d.ts.map +1 -1
- package/dist/core/Remote.js +3 -1
- package/dist/core/Remote.js.map +1 -1
- package/dist/core/Schema.d.ts +17 -7
- package/dist/core/Schema.d.ts.map +1 -1
- package/dist/core/adapters/dialog.d.ts.map +1 -1
- package/dist/core/adapters/dialog.js +126 -131
- package/dist/core/adapters/dialog.js.map +1 -1
- package/dist/core/adapters/local.d.ts.map +1 -1
- package/dist/core/adapters/local.js +92 -105
- package/dist/core/adapters/local.js.map +1 -1
- package/dist/core/adapters/privy.d.ts +164 -0
- package/dist/core/adapters/privy.d.ts.map +1 -0
- package/dist/core/adapters/privy.js +578 -0
- package/dist/core/adapters/privy.js.map +1 -0
- package/dist/core/adapters/turnkey.d.ts.map +1 -1
- package/dist/core/adapters/turnkey.js +136 -133
- package/dist/core/adapters/turnkey.js.map +1 -1
- package/dist/core/internal/AccessKeyTransaction.d.ts +59 -0
- package/dist/core/internal/AccessKeyTransaction.d.ts.map +1 -0
- package/dist/core/internal/AccessKeyTransaction.js +155 -0
- package/dist/core/internal/AccessKeyTransaction.js.map +1 -0
- package/dist/core/zod/rpc.d.ts +71 -4
- package/dist/core/zod/rpc.d.ts.map +1 -1
- package/dist/core/zod/rpc.js +33 -4
- package/dist/core/zod/rpc.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react-native/adapter.d.ts.map +1 -1
- package/dist/react-native/adapter.js +86 -75
- package/dist/react-native/adapter.js.map +1 -1
- package/dist/server/CliAuth.d.ts +55 -0
- package/dist/server/CliAuth.d.ts.map +1 -1
- package/dist/server/CliAuth.js +18 -1
- package/dist/server/CliAuth.js.map +1 -1
- package/dist/server/Kv.d.ts +19 -9
- package/dist/server/Kv.d.ts.map +1 -1
- package/dist/server/Kv.js +32 -9
- package/dist/server/Kv.js.map +1 -1
- package/dist/server/internal/handlers/auth.d.ts.map +1 -1
- package/dist/server/internal/handlers/auth.js +3 -1
- package/dist/server/internal/handlers/auth.js.map +1 -1
- package/dist/server/internal/handlers/codeAuth.js +1 -1
- package/dist/server/internal/handlers/codeAuth.js.map +1 -1
- package/dist/server/internal/handlers/exchange.js +1 -1
- package/dist/server/internal/handlers/exchange.js.map +1 -1
- package/dist/server/internal/handlers/relay.d.ts +18 -12
- package/dist/server/internal/handlers/relay.d.ts.map +1 -1
- package/dist/server/internal/handlers/relay.js +116 -3
- package/dist/server/internal/handlers/relay.js.map +1 -1
- package/dist/server/internal/handlers/webAuthn.d.ts +6 -1
- package/dist/server/internal/handlers/webAuthn.d.ts.map +1 -1
- package/dist/server/internal/handlers/webAuthn.js +16 -9
- package/dist/server/internal/handlers/webAuthn.js.map +1 -1
- package/package.json +3 -3
- package/src/cli/{Provider.test.ts → Provider.localnet.test.ts} +49 -1
- package/src/cli/adapter.ts +95 -76
- package/src/core/AccessKey.test.ts +563 -560
- package/src/core/AccessKey.ts +327 -327
- package/src/core/Account.test.ts +6 -51
- package/src/core/Account.ts +1 -19
- package/src/core/Adapter.ts +22 -4
- package/src/core/Client.test.ts +1 -1
- package/src/core/Client.ts +1 -1
- package/src/core/Provider.connect.browser.test.ts +1 -1
- package/src/core/{Provider.test.ts → Provider.localnet.test.ts} +98 -32
- package/src/core/Provider.ts +118 -112
- package/src/core/Remote.test.ts +28 -0
- package/src/core/Remote.ts +4 -1
- package/src/core/Schema.test-d.ts +41 -0
- package/src/core/adapters/dialog.test.ts +335 -15
- package/src/core/adapters/dialog.ts +120 -127
- package/src/core/adapters/local.test.ts +1 -1
- package/src/core/adapters/local.ts +95 -119
- package/src/core/adapters/privy.test-d.ts +128 -0
- package/src/core/adapters/privy.test.ts +648 -0
- package/src/core/adapters/privy.ts +811 -0
- package/src/core/adapters/turnkey.test.ts +117 -13
- package/src/core/adapters/turnkey.ts +132 -149
- package/src/core/internal/AccessKeyTransaction.ts +243 -0
- package/src/core/{mppx.test.ts → mppx.localnet.test.ts} +32 -2
- package/src/core/zod/request.test.ts +36 -0
- package/src/core/zod/rpc.test.ts +139 -0
- package/src/core/zod/rpc.ts +44 -10
- package/src/index.ts +1 -1
- package/src/react-native/{Provider.test.ts → Provider.localnet.test.ts} +65 -0
- package/src/react-native/adapter.ts +107 -87
- package/src/server/CliAuth.test-d.ts +23 -0
- package/src/server/CliAuth.test.ts +47 -0
- package/src/server/CliAuth.ts +20 -1
- package/src/server/Handler.test-d.ts +1 -1
- package/src/server/Kv.test.ts +51 -0
- package/src/server/Kv.ts +43 -9
- package/src/server/internal/handlers/auth.test.ts +10 -5
- package/src/server/internal/handlers/auth.ts +4 -1
- package/src/server/internal/handlers/codeAuth.ts +1 -1
- package/src/server/internal/handlers/exchange.ts +1 -1
- package/src/server/internal/handlers/{relay.test.ts → relay.localnet.test.ts} +4 -1
- package/src/server/internal/handlers/relay.ts +139 -14
- package/src/server/internal/handlers/session.test.ts +1 -1
- package/src/server/internal/handlers/webAuthn.test.ts +20 -0
- package/src/server/internal/handlers/webAuthn.ts +24 -12
- /package/src/server/internal/handlers/{exchange.test.ts → exchange.localnet.test.ts} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Provider as ox_Provider } from 'ox'
|
|
2
|
-
import {
|
|
1
|
+
import { Address, Hex, Provider as ox_Provider, PublicKey } from 'ox'
|
|
2
|
+
import { KeyAuthorization, SignatureEnvelope } from 'ox/tempo'
|
|
3
|
+
import { tempoLocalnet } from 'viem/tempo/chains'
|
|
3
4
|
import { afterEach, describe, expect, test, vi } from 'vp/test'
|
|
4
5
|
|
|
5
|
-
import * as AccessKey from '../AccessKey.js'
|
|
6
6
|
import * as Dialog from '../Dialog.js'
|
|
7
|
+
import * as AccessKeyTransaction from '../internal/AccessKeyTransaction.js'
|
|
7
8
|
import * as Storage from '../Storage.js'
|
|
8
9
|
import * as Store from '../Store.js'
|
|
9
10
|
import { dialog } from './dialog.js'
|
|
@@ -11,6 +12,47 @@ import { dialog } from './dialog.js'
|
|
|
11
12
|
const address = '0x0000000000000000000000000000000000000001'
|
|
12
13
|
const recipient = '0x0000000000000000000000000000000000000002'
|
|
13
14
|
|
|
15
|
+
function createKeyAuthorization(options: {
|
|
16
|
+
expiry: number
|
|
17
|
+
keyType: 'secp256k1' | 'p256'
|
|
18
|
+
publicKey: Hex.Hex
|
|
19
|
+
}) {
|
|
20
|
+
const { expiry, keyType, publicKey } = options
|
|
21
|
+
return KeyAuthorization.toRpc(
|
|
22
|
+
KeyAuthorization.from(
|
|
23
|
+
{
|
|
24
|
+
address: Address.fromPublicKey(PublicKey.from(publicKey)),
|
|
25
|
+
chainId: BigInt(tempoLocalnet.id),
|
|
26
|
+
expiry,
|
|
27
|
+
type: keyType,
|
|
28
|
+
},
|
|
29
|
+
{ signature: SignatureEnvelope.from(`0x${'00'.repeat(65)}`) },
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function setup() {
|
|
35
|
+
const storage = Storage.memory()
|
|
36
|
+
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
37
|
+
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
38
|
+
getAccount: (options) => {
|
|
39
|
+
if (options?.signable) throw new ox_Provider.UnauthorizedError({ message: 'No signer.' })
|
|
40
|
+
return { address, type: 'json-rpc' } as never
|
|
41
|
+
},
|
|
42
|
+
getClient: () => ({}) as never,
|
|
43
|
+
storage,
|
|
44
|
+
store,
|
|
45
|
+
})
|
|
46
|
+
return { adapter, store }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function takeRequest(store: Store.Store) {
|
|
50
|
+
await vi.waitFor(() => {
|
|
51
|
+
if (!store.getState().requestQueue[0]) throw new Error('request not queued')
|
|
52
|
+
})
|
|
53
|
+
return store.getState().requestQueue[0]!
|
|
54
|
+
}
|
|
55
|
+
|
|
14
56
|
describe('dialog', () => {
|
|
15
57
|
afterEach(() => {
|
|
16
58
|
vi.restoreAllMocks()
|
|
@@ -21,16 +63,24 @@ describe('dialog', () => {
|
|
|
21
63
|
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
22
64
|
const clientRequests: unknown[] = []
|
|
23
65
|
const signRequests: unknown[] = []
|
|
24
|
-
vi.spyOn(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
66
|
+
vi.spyOn(AccessKeyTransaction, 'create').mockResolvedValue({
|
|
67
|
+
fill: async () => ({ capabilities: { sponsored: false }, tx: {} }),
|
|
68
|
+
prepare: async (request) => ({
|
|
69
|
+
request: request as never,
|
|
70
|
+
send: async () => {
|
|
71
|
+
signRequests.push(request)
|
|
72
|
+
clientRequests.push({ method: 'eth_sendRawTransaction', params: ['0xsigned'] })
|
|
73
|
+
return '0xtransaction'
|
|
74
|
+
},
|
|
75
|
+
sendSync: async () => {
|
|
76
|
+
throw new Error('unexpected sendSync')
|
|
77
|
+
},
|
|
78
|
+
sign: async () => {
|
|
79
|
+
signRequests.push(request)
|
|
80
|
+
return '0xsigned'
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
})
|
|
34
84
|
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
35
85
|
getAccount: () => {
|
|
36
86
|
throw new ox_Provider.UnauthorizedError({ message: 'No local signer.' })
|
|
@@ -84,10 +134,76 @@ describe('dialog', () => {
|
|
|
84
134
|
expect(store.getState().requestQueue).toMatchInlineSnapshot(`[]`)
|
|
85
135
|
})
|
|
86
136
|
|
|
137
|
+
test('behavior: loadAccounts forwards auth capabilities returned by the dialog', async () => {
|
|
138
|
+
const storage = Storage.memory()
|
|
139
|
+
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
140
|
+
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
141
|
+
getAccount: () => {
|
|
142
|
+
throw new ox_Provider.UnauthorizedError({ message: 'No local signer.' })
|
|
143
|
+
},
|
|
144
|
+
getClient: () => ({}) as never,
|
|
145
|
+
storage,
|
|
146
|
+
store,
|
|
147
|
+
})
|
|
148
|
+
const request = {
|
|
149
|
+
method: 'wallet_connect' as const,
|
|
150
|
+
params: [
|
|
151
|
+
{
|
|
152
|
+
capabilities: {
|
|
153
|
+
auth: {
|
|
154
|
+
url: 'https://app.example/auth',
|
|
155
|
+
returnToken: true,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
chainId: '0x1079' as const,
|
|
159
|
+
},
|
|
160
|
+
] as const,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const promise = adapter.actions.loadAccounts(undefined, request)
|
|
164
|
+
|
|
165
|
+
await vi.waitFor(() => {
|
|
166
|
+
if (!store.getState().requestQueue[0]) throw new Error('request not queued')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const queued = store.getState().requestQueue[0]!
|
|
170
|
+
store.setState({
|
|
171
|
+
requestQueue: [
|
|
172
|
+
{
|
|
173
|
+
request: queued.request,
|
|
174
|
+
result: {
|
|
175
|
+
accounts: [
|
|
176
|
+
{
|
|
177
|
+
address,
|
|
178
|
+
capabilities: {
|
|
179
|
+
auth: { token: 'test-token' },
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
status: 'success',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
await expect(promise).resolves.toMatchInlineSnapshot(`
|
|
190
|
+
{
|
|
191
|
+
"accounts": [
|
|
192
|
+
{
|
|
193
|
+
"address": "0x0000000000000000000000000000000000000001",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
"auth": {
|
|
197
|
+
"token": "test-token",
|
|
198
|
+
},
|
|
199
|
+
}
|
|
200
|
+
`)
|
|
201
|
+
})
|
|
202
|
+
|
|
87
203
|
test('behavior: sendTransaction falls through when no access key is selected', async () => {
|
|
88
204
|
const storage = Storage.memory()
|
|
89
205
|
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
90
|
-
vi.spyOn(
|
|
206
|
+
vi.spyOn(AccessKeyTransaction, 'create').mockResolvedValue(undefined)
|
|
91
207
|
const lookups: unknown[] = []
|
|
92
208
|
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
93
209
|
getAccount: (options) => {
|
|
@@ -137,10 +253,214 @@ describe('dialog', () => {
|
|
|
137
253
|
expect(lookups).toMatchInlineSnapshot(`[]`)
|
|
138
254
|
})
|
|
139
255
|
|
|
256
|
+
test('behavior: revokeAccessKey clears the forwarded key from local state', async () => {
|
|
257
|
+
const storage = Storage.memory()
|
|
258
|
+
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
259
|
+
store.setState({
|
|
260
|
+
accessKeys: [
|
|
261
|
+
{
|
|
262
|
+
access: address,
|
|
263
|
+
address: recipient,
|
|
264
|
+
chainId: tempoLocalnet.id,
|
|
265
|
+
keyType: 'p256',
|
|
266
|
+
} as never,
|
|
267
|
+
],
|
|
268
|
+
})
|
|
269
|
+
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
270
|
+
getAccount: () => {
|
|
271
|
+
throw new ox_Provider.UnauthorizedError({ message: 'No local signer.' })
|
|
272
|
+
},
|
|
273
|
+
getClient: () => ({}) as never,
|
|
274
|
+
storage,
|
|
275
|
+
store,
|
|
276
|
+
})
|
|
277
|
+
const request = {
|
|
278
|
+
method: 'wallet_revokeAccessKey' as const,
|
|
279
|
+
params: [{ accessKeyAddress: recipient, address }] as const,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const promise = adapter.actions.revokeAccessKey!(
|
|
283
|
+
{ accessKeyAddress: recipient, address },
|
|
284
|
+
request,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
await vi.waitFor(() => {
|
|
288
|
+
if (!store.getState().requestQueue[0]) throw new Error('request not queued')
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
const queued = store.getState().requestQueue[0]!
|
|
292
|
+
store.setState({
|
|
293
|
+
requestQueue: [
|
|
294
|
+
{
|
|
295
|
+
request: queued.request,
|
|
296
|
+
result: undefined,
|
|
297
|
+
status: 'success',
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
await expect(promise).resolves.toMatchInlineSnapshot(`undefined`)
|
|
303
|
+
expect(store.getState().accessKeys).toMatchInlineSnapshot(`[]`)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
test('behavior: authorizeAccessKey forwards an external secp256k1 key', async () => {
|
|
307
|
+
const { adapter, store } = setup()
|
|
308
|
+
const expiry = 123
|
|
309
|
+
const promise = adapter.actions.authorizeAccessKey!(
|
|
310
|
+
{ address: recipient, expiry, keyType: 'secp256k1' },
|
|
311
|
+
{
|
|
312
|
+
method: 'wallet_authorizeAccessKey',
|
|
313
|
+
params: [{ address: recipient, expiry, keyType: 'secp256k1' }],
|
|
314
|
+
},
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
const queued = await takeRequest(store)
|
|
318
|
+
const request = queued.request as {
|
|
319
|
+
params: [{ address: typeof recipient; expiry: number; keyType: 'secp256k1' }]
|
|
320
|
+
}
|
|
321
|
+
const params = request.params[0]
|
|
322
|
+
const keyAuthorization = KeyAuthorization.toRpc(
|
|
323
|
+
KeyAuthorization.from(
|
|
324
|
+
{
|
|
325
|
+
address: recipient,
|
|
326
|
+
chainId: BigInt(tempoLocalnet.id),
|
|
327
|
+
expiry,
|
|
328
|
+
type: 'secp256k1',
|
|
329
|
+
},
|
|
330
|
+
{ signature: SignatureEnvelope.from(`0x${'00'.repeat(65)}`) },
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
store.setState({
|
|
334
|
+
requestQueue: [
|
|
335
|
+
{
|
|
336
|
+
request: queued.request,
|
|
337
|
+
result: {
|
|
338
|
+
keyAuthorization,
|
|
339
|
+
rootAddress: address,
|
|
340
|
+
},
|
|
341
|
+
status: 'success',
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
await expect(promise).resolves.toMatchObject({ rootAddress: address })
|
|
347
|
+
expect(params.keyType).toMatchInlineSnapshot(`"secp256k1"`)
|
|
348
|
+
expect(params.address).toMatchInlineSnapshot(`"0x0000000000000000000000000000000000000002"`)
|
|
349
|
+
expect(store.getState().accessKeys).toMatchInlineSnapshot(`[]`)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
test('behavior: authorizeAccessKey generates a p256 key by default', async () => {
|
|
353
|
+
const { adapter, store } = setup()
|
|
354
|
+
const expiry = 123
|
|
355
|
+
const promise = adapter.actions.authorizeAccessKey!(
|
|
356
|
+
{ expiry },
|
|
357
|
+
{ method: 'wallet_authorizeAccessKey', params: [{ expiry }] },
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
const queued = await takeRequest(store)
|
|
361
|
+
const request = queued.request as {
|
|
362
|
+
params: [{ expiry: number; keyType: 'p256'; publicKey: Hex.Hex }]
|
|
363
|
+
}
|
|
364
|
+
const params = request.params[0]
|
|
365
|
+
store.setState({
|
|
366
|
+
requestQueue: [
|
|
367
|
+
{
|
|
368
|
+
request: queued.request,
|
|
369
|
+
result: {
|
|
370
|
+
keyAuthorization: createKeyAuthorization(params),
|
|
371
|
+
rootAddress: address,
|
|
372
|
+
},
|
|
373
|
+
status: 'success',
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
await expect(promise).resolves.toMatchObject({ rootAddress: address })
|
|
379
|
+
expect(params.keyType).toMatchInlineSnapshot(`"p256"`)
|
|
380
|
+
expect(store.getState().accessKeys).toMatchObject([
|
|
381
|
+
{
|
|
382
|
+
access: address,
|
|
383
|
+
keyType: 'p256',
|
|
384
|
+
},
|
|
385
|
+
])
|
|
386
|
+
expect('keyPair' in store.getState().accessKeys[0]!).toMatchInlineSnapshot(`true`)
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
test('behavior: authorizeAccessKey generates a p256 key when requested', async () => {
|
|
390
|
+
const { adapter, store } = setup()
|
|
391
|
+
const expiry = 123
|
|
392
|
+
const promise = adapter.actions.authorizeAccessKey!(
|
|
393
|
+
{ expiry, keyType: 'p256' },
|
|
394
|
+
{ method: 'wallet_authorizeAccessKey', params: [{ expiry, keyType: 'p256' }] },
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
const queued = await takeRequest(store)
|
|
398
|
+
const request = queued.request as {
|
|
399
|
+
params: [{ expiry: number; keyType: 'p256'; publicKey: Hex.Hex }]
|
|
400
|
+
}
|
|
401
|
+
const params = request.params[0]
|
|
402
|
+
store.setState({
|
|
403
|
+
requestQueue: [
|
|
404
|
+
{
|
|
405
|
+
request: queued.request,
|
|
406
|
+
result: {
|
|
407
|
+
keyAuthorization: createKeyAuthorization(params),
|
|
408
|
+
rootAddress: address,
|
|
409
|
+
},
|
|
410
|
+
status: 'success',
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
await expect(promise).resolves.toMatchObject({ rootAddress: address })
|
|
416
|
+
expect(params.keyType).toMatchInlineSnapshot(`"p256"`)
|
|
417
|
+
expect(store.getState().accessKeys).toMatchObject([
|
|
418
|
+
{
|
|
419
|
+
access: address,
|
|
420
|
+
keyType: 'p256',
|
|
421
|
+
},
|
|
422
|
+
])
|
|
423
|
+
expect('keyPair' in store.getState().accessKeys[0]!).toMatchInlineSnapshot(`true`)
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
test('error: secp256k1 access key requires external key material', async () => {
|
|
427
|
+
const { adapter, store } = setup()
|
|
428
|
+
|
|
429
|
+
await expect(
|
|
430
|
+
adapter.actions.authorizeAccessKey!(
|
|
431
|
+
{ expiry: 123, keyType: 'secp256k1' },
|
|
432
|
+
{
|
|
433
|
+
method: 'wallet_authorizeAccessKey',
|
|
434
|
+
params: [{ expiry: 123, keyType: 'secp256k1' }],
|
|
435
|
+
},
|
|
436
|
+
),
|
|
437
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
438
|
+
`[RpcResponse.InvalidParamsError: \`keyType: "secp256k1"\` requires externally generated key material; provide \`publicKey\` or \`address\`.]`,
|
|
439
|
+
)
|
|
440
|
+
expect(store.getState().requestQueue).toMatchInlineSnapshot(`[]`)
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
test('error: webAuthn access key requires external key material', async () => {
|
|
444
|
+
const { adapter, store } = setup()
|
|
445
|
+
|
|
446
|
+
await expect(
|
|
447
|
+
adapter.actions.authorizeAccessKey!(
|
|
448
|
+
{ expiry: 123, keyType: 'webAuthn' },
|
|
449
|
+
{
|
|
450
|
+
method: 'wallet_authorizeAccessKey',
|
|
451
|
+
params: [{ expiry: 123, keyType: 'webAuthn' }],
|
|
452
|
+
},
|
|
453
|
+
),
|
|
454
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
455
|
+
`[RpcResponse.InvalidParamsError: \`keyType: "webAuthn"\` requires externally generated key material; provide \`publicKey\` or \`address\`.]`,
|
|
456
|
+
)
|
|
457
|
+
expect(store.getState().requestQueue).toMatchInlineSnapshot(`[]`)
|
|
458
|
+
})
|
|
459
|
+
|
|
140
460
|
test('error: wallet validation errors keep their RPC code', async () => {
|
|
141
461
|
const storage = Storage.memory()
|
|
142
462
|
const store = Store.create({ chainId: tempoLocalnet.id, storage })
|
|
143
|
-
vi.spyOn(
|
|
463
|
+
vi.spyOn(AccessKeyTransaction, 'create').mockResolvedValue(undefined)
|
|
144
464
|
const adapter = dialog({ dialog: Dialog.noop() })({
|
|
145
465
|
getAccount: () => {
|
|
146
466
|
throw new ox_Provider.UnauthorizedError({ message: 'No local signer.' })
|