accounts 0.12.2 → 0.13.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 (99) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +6 -5
  3. package/dist/cli/adapter.d.ts.map +1 -1
  4. package/dist/cli/adapter.js +53 -67
  5. package/dist/cli/adapter.js.map +1 -1
  6. package/dist/core/AccessKey.d.ts +89 -106
  7. package/dist/core/AccessKey.d.ts.map +1 -1
  8. package/dist/core/AccessKey.js +226 -210
  9. package/dist/core/AccessKey.js.map +1 -1
  10. package/dist/core/Account.d.ts +0 -9
  11. package/dist/core/Account.d.ts.map +1 -1
  12. package/dist/core/Account.js +1 -13
  13. package/dist/core/Account.js.map +1 -1
  14. package/dist/core/Adapter.d.ts +10 -2
  15. package/dist/core/Adapter.d.ts.map +1 -1
  16. package/dist/core/Provider.d.ts +4 -5
  17. package/dist/core/Provider.d.ts.map +1 -1
  18. package/dist/core/Provider.js +66 -76
  19. package/dist/core/Provider.js.map +1 -1
  20. package/dist/core/Schema.d.ts +7 -7
  21. package/dist/core/adapters/dialog.d.ts.map +1 -1
  22. package/dist/core/adapters/dialog.js +114 -124
  23. package/dist/core/adapters/dialog.js.map +1 -1
  24. package/dist/core/adapters/local.d.ts.map +1 -1
  25. package/dist/core/adapters/local.js +92 -105
  26. package/dist/core/adapters/local.js.map +1 -1
  27. package/dist/core/adapters/privy.d.ts +164 -0
  28. package/dist/core/adapters/privy.d.ts.map +1 -0
  29. package/dist/core/adapters/privy.js +574 -0
  30. package/dist/core/adapters/privy.js.map +1 -0
  31. package/dist/core/adapters/turnkey.d.ts.map +1 -1
  32. package/dist/core/adapters/turnkey.js +136 -133
  33. package/dist/core/adapters/turnkey.js.map +1 -1
  34. package/dist/core/internal/AccessKeyTransaction.d.ts +59 -0
  35. package/dist/core/internal/AccessKeyTransaction.d.ts.map +1 -0
  36. package/dist/core/internal/AccessKeyTransaction.js +155 -0
  37. package/dist/core/internal/AccessKeyTransaction.js.map +1 -0
  38. package/dist/core/zod/rpc.d.ts +9 -4
  39. package/dist/core/zod/rpc.d.ts.map +1 -1
  40. package/dist/core/zod/rpc.js +9 -4
  41. package/dist/core/zod/rpc.js.map +1 -1
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/react-native/adapter.d.ts.map +1 -1
  47. package/dist/react-native/adapter.js +61 -72
  48. package/dist/react-native/adapter.js.map +1 -1
  49. package/dist/server/Kv.d.ts +19 -9
  50. package/dist/server/Kv.d.ts.map +1 -1
  51. package/dist/server/Kv.js +32 -9
  52. package/dist/server/Kv.js.map +1 -1
  53. package/dist/server/internal/handlers/auth.d.ts.map +1 -1
  54. package/dist/server/internal/handlers/auth.js +2 -0
  55. package/dist/server/internal/handlers/auth.js.map +1 -1
  56. package/dist/server/internal/handlers/relay.d.ts +18 -12
  57. package/dist/server/internal/handlers/relay.d.ts.map +1 -1
  58. package/dist/server/internal/handlers/relay.js +115 -2
  59. package/dist/server/internal/handlers/relay.js.map +1 -1
  60. package/dist/server/internal/handlers/webAuthn.d.ts +6 -1
  61. package/dist/server/internal/handlers/webAuthn.d.ts.map +1 -1
  62. package/dist/server/internal/handlers/webAuthn.js +16 -9
  63. package/dist/server/internal/handlers/webAuthn.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/cli/adapter.ts +69 -74
  66. package/src/core/AccessKey.test.ts +525 -559
  67. package/src/core/AccessKey.ts +323 -327
  68. package/src/core/Account.test.ts +5 -50
  69. package/src/core/Account.ts +1 -19
  70. package/src/core/Adapter.ts +6 -2
  71. package/src/core/{Provider.test.ts → Provider.localnet.test.ts} +97 -31
  72. package/src/core/Provider.ts +110 -110
  73. package/src/core/Schema.test-d.ts +18 -0
  74. package/src/core/adapters/dialog.test.ts +137 -13
  75. package/src/core/adapters/dialog.ts +109 -121
  76. package/src/core/adapters/local.ts +95 -119
  77. package/src/core/adapters/privy.test-d.ts +128 -0
  78. package/src/core/adapters/privy.test.ts +634 -0
  79. package/src/core/adapters/privy.ts +805 -0
  80. package/src/core/adapters/turnkey.test.ts +117 -13
  81. package/src/core/adapters/turnkey.ts +132 -149
  82. package/src/core/internal/AccessKeyTransaction.ts +243 -0
  83. package/src/core/{mppx.test.ts → mppx.localnet.test.ts} +32 -2
  84. package/src/core/zod/request.test.ts +36 -0
  85. package/src/core/zod/rpc.ts +17 -10
  86. package/src/index.ts +1 -1
  87. package/src/react-native/adapter.ts +77 -84
  88. package/src/server/Kv.test.ts +51 -0
  89. package/src/server/Kv.ts +43 -9
  90. package/src/server/internal/handlers/auth.test.ts +10 -5
  91. package/src/server/internal/handlers/auth.ts +3 -0
  92. package/src/server/internal/handlers/{relay.test.ts → relay.localnet.test.ts} +3 -0
  93. package/src/server/internal/handlers/relay.ts +138 -13
  94. package/src/server/internal/handlers/session.test.ts +1 -1
  95. package/src/server/internal/handlers/webAuthn.test.ts +20 -0
  96. package/src/server/internal/handlers/webAuthn.ts +24 -12
  97. /package/src/cli/{Provider.test.ts → Provider.localnet.test.ts} +0 -0
  98. /package/src/react-native/{Provider.test.ts → Provider.localnet.test.ts} +0 -0
  99. /package/src/server/internal/handlers/{exchange.test.ts → exchange.localnet.test.ts} +0 -0
@@ -1,5 +1,7 @@
1
1
  import { Hex, PublicKey } from 'ox'
2
+ import { decodeFunctionData } from 'viem'
2
3
  import type { Address } from 'viem/accounts'
4
+ import { Abis } from 'viem/tempo'
3
5
  import { describe, expect, test } from 'vp/test'
4
6
 
5
7
  import { accounts } from '../../../test/config.js'
@@ -94,10 +96,10 @@ describe('turnkey', () => {
94
96
  `)
95
97
  })
96
98
 
97
- test('default: loadAccounts delegates login and caches wallet accounts for signing', async () => {
98
- const { adapter, client } = setup()
99
+ test('default: loadAccounts returns accounts for store-backed signing', async () => {
100
+ const { adapter, client, store } = setup()
99
101
 
100
- await adapter.actions.loadAccounts(undefined, { method: 'wallet_connect', params: undefined })
102
+ await connect({ adapter, store })
101
103
  const result = await adapter.actions.signPersonalMessage(
102
104
  { address, data: '0x68656c6c6f' },
103
105
  { method: 'personal_sign', params: ['0x68656c6c6f', address] },
@@ -148,9 +150,9 @@ describe('turnkey', () => {
148
150
  })
149
151
 
150
152
  test('default: signs transactions with a hydrated Tempo account', async () => {
151
- const { adapter, client } = setup()
153
+ const { adapter, client, store } = setup()
152
154
 
153
- await adapter.actions.loadAccounts(undefined, { method: 'wallet_connect', params: undefined })
155
+ await connect({ adapter, store })
154
156
  const result = await adapter.actions.signTransaction(
155
157
  {
156
158
  chainId: 1,
@@ -181,7 +183,7 @@ describe('turnkey', () => {
181
183
  })
182
184
 
183
185
  test('default: accepts prefixed Turnkey public keys', async () => {
184
- const { adapter, client } = setup()
186
+ const { adapter, client, store } = setup()
185
187
  const walletAccount = toWalletAccount(account)
186
188
  client.wallets = [
187
189
  {
@@ -194,7 +196,7 @@ describe('turnkey', () => {
194
196
  },
195
197
  ]
196
198
 
197
- await adapter.actions.loadAccounts(undefined, { method: 'wallet_connect', params: undefined })
199
+ await connect({ adapter, store })
198
200
  const result = await adapter.actions.signTransaction(
199
201
  {
200
202
  chainId: 1,
@@ -292,6 +294,53 @@ describe('turnkey', () => {
292
294
  `)
293
295
  })
294
296
 
297
+ test('default: revokeAccessKey revokes with the connected Turnkey account', async () => {
298
+ const { adapter, client, store } = setup()
299
+ store.setState({
300
+ accounts: [{ address }],
301
+ activeAccount: 0,
302
+ accessKeys: [
303
+ {
304
+ access: address,
305
+ address: other,
306
+ chainId: 1,
307
+ keyType: 'secp256k1',
308
+ } as never,
309
+ ],
310
+ })
311
+
312
+ await adapter.actions.revokeAccessKey!(
313
+ { accessKeyAddress: other, address },
314
+ { method: 'wallet_revokeAccessKey', params: [{ accessKeyAddress: other, address }] },
315
+ )
316
+
317
+ const transaction = client.transactions[0] as
318
+ | { account: { address: Address }; data: Hex.Hex; to: Address }
319
+ | undefined
320
+ const decoded = transaction
321
+ ? decodeFunctionData({ abi: Abis.accountKeychain, data: transaction.data })
322
+ : undefined
323
+ expect(
324
+ transaction &&
325
+ decoded && {
326
+ account: transaction.account.address,
327
+ args: decoded.args,
328
+ functionName: decoded.functionName,
329
+ to: transaction.to,
330
+ },
331
+ ).toMatchInlineSnapshot(`
332
+ {
333
+ "account": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
334
+ "args": [
335
+ "0x8C8d35429F74ec245F8Ef2f4Fd1e551cFF97d650",
336
+ ],
337
+ "functionName": "revokeKey",
338
+ "to": "0xaAAAaaAA00000000000000000000000000000000",
339
+ }
340
+ `)
341
+ expect(store.getState().accessKeys).toMatchInlineSnapshot(`[]`)
342
+ })
343
+
295
344
  test('behavior: signing silently restores wallet accounts from an existing session', async () => {
296
345
  const { adapter, client, store } = setup()
297
346
  store.setState({ accounts: [{ address }], activeAccount: 0 })
@@ -319,7 +368,7 @@ describe('turnkey', () => {
319
368
  expect(client.signPayloads).toMatchInlineSnapshot(`[]`)
320
369
  })
321
370
 
322
- test('behavior: silent restore only reconnects persisted provider accounts', async () => {
371
+ test('behavior: silent restore uses persisted provider accounts', async () => {
323
372
  const { adapter, client, store } = setup()
324
373
  client.wallets = [
325
374
  {
@@ -347,7 +396,7 @@ describe('turnkey', () => {
347
396
  `)
348
397
  })
349
398
 
350
- test('behavior: silent restore ignores non-Ethereum wallet accounts', async () => {
399
+ test('behavior: silent restore rejects connected accounts missing from Turnkey metadata', async () => {
351
400
  const { adapter, client, store } = setup()
352
401
  client.wallets = [
353
402
  {
@@ -367,9 +416,43 @@ describe('turnkey', () => {
367
416
  { address, data: '0x68656c6c6f' },
368
417
  { method: 'personal_sign', params: ['0x68656c6c6f', address] },
369
418
  ),
370
- ).rejects.toMatchInlineSnapshot('[Provider.DisconnectedError: No Turnkey account connected.]')
419
+ ).rejects.toMatchInlineSnapshot(
420
+ '[RpcResponse.InternalError: Connected Turnkey account "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" was not found in fetched Turnkey wallet accounts. Reconnect with Turnkey.]',
421
+ )
371
422
 
423
+ expect(client.fetchCalls).toMatchInlineSnapshot(`1`)
372
424
  expect(client.signPayloads).toMatchInlineSnapshot(`[]`)
425
+ expect(store.getState().accounts).toMatchInlineSnapshot(`
426
+ [
427
+ {
428
+ "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
429
+ },
430
+ ]
431
+ `)
432
+ })
433
+
434
+ test('behavior: reconnecting refreshes wallet account metadata', async () => {
435
+ const { adapter, client, store } = setup()
436
+
437
+ await connect({ adapter, store })
438
+ client.wallets = [
439
+ {
440
+ accounts: [toWalletAccount(account), toWalletAccount(account_2)],
441
+ },
442
+ ]
443
+ await connect({ adapter, store })
444
+
445
+ await adapter.actions.signPersonalMessage(
446
+ { address, data: '0x68656c6c6f' },
447
+ { method: 'personal_sign', params: ['0x68656c6c6f', address] },
448
+ )
449
+
450
+ expect(client.fetchCalls).toMatchInlineSnapshot(`2`)
451
+ expect(client.signPayloads).toMatchInlineSnapshot(`
452
+ [
453
+ "0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750",
454
+ ]
455
+ `)
373
456
  })
374
457
 
375
458
  test('behavior: expired sessions clear provider accounts', async () => {
@@ -404,8 +487,8 @@ describe('turnkey', () => {
404
487
  })
405
488
 
406
489
  test('error: signing an unconnected account fails', async () => {
407
- const { adapter } = setup()
408
- await adapter.actions.loadAccounts(undefined, { method: 'wallet_connect', params: undefined })
490
+ const { adapter, store } = setup()
491
+ await connect({ adapter, store })
409
492
 
410
493
  await expect(
411
494
  adapter.actions.signPersonalMessage(
@@ -474,13 +557,29 @@ function setup(options: setup.Options = {}) {
474
557
  getAccount: (() => {
475
558
  throw new Error('not implemented')
476
559
  }) as never,
477
- getClient: (() => ({ chain: { id: 1 } })) as never,
560
+ getClient: (() => ({
561
+ chain: { id: 1 },
562
+ sendTransaction: async (parameters: unknown) => {
563
+ client.transactions.push(parameters)
564
+ return Hex.padLeft('0x1', 32)
565
+ },
566
+ })) as never,
478
567
  storage,
479
568
  store,
480
569
  })
481
570
  return { adapter, client, store }
482
571
  }
483
572
 
573
+ async function connect(options: Pick<ReturnType<typeof setup>, 'adapter' | 'store'>) {
574
+ const { adapter, store } = options
575
+ const loaded = await adapter.actions.loadAccounts(undefined, {
576
+ method: 'wallet_connect',
577
+ params: undefined,
578
+ })
579
+ store.setState({ accounts: loaded.accounts, activeAccount: 0 })
580
+ return loaded
581
+ }
582
+
484
583
  declare namespace setup {
485
584
  type Options = {
486
585
  createAccount?: boolean | undefined
@@ -502,6 +601,7 @@ function createClient(options: setup.Options = {}) {
502
601
  loadCalls: 0,
503
602
  signPayloads: [] as Hex.Hex[],
504
603
  signWith: [] as string[],
604
+ transactions: [] as unknown[],
505
605
  wallets: [{ accounts: [toWalletAccount(account)] }] as WalletShape[],
506
606
  }
507
607
  const client = {
@@ -529,6 +629,9 @@ function createClient(options: setup.Options = {}) {
529
629
  get signWith() {
530
630
  return state.signWith
531
631
  },
632
+ get transactions() {
633
+ return state.transactions
634
+ },
532
635
  get wallets() {
533
636
  return state.wallets
534
637
  },
@@ -566,6 +669,7 @@ function createClient(options: setup.Options = {}) {
566
669
  loadCalls: number
567
670
  signPayloads: Hex.Hex[]
568
671
  signWith: string[]
672
+ transactions: unknown[]
569
673
  wallets: WalletShape[]
570
674
  }
571
675
 
@@ -7,14 +7,14 @@ import {
7
7
  RpcResponse,
8
8
  Secp256k1,
9
9
  } from 'ox'
10
- import { KeyAuthorization } from 'ox/tempo'
11
10
  import { hashMessage, hashTypedData, isAddressEqual } from 'viem'
12
11
  import type { Address } from 'viem/accounts'
13
12
  import { prepareTransactionRequest } from 'viem/actions'
14
- import { Account as TempoAccount } from 'viem/tempo'
13
+ import { Account as TempoAccount, Actions } from 'viem/tempo'
15
14
 
16
15
  import * as AccessKey from '../AccessKey.js'
17
16
  import * as Adapter from '../Adapter.js'
17
+ import * as AccessKeyTransaction from '../internal/AccessKeyTransaction.js'
18
18
  import * as Store from '../Store.js'
19
19
 
20
20
  const turnkeySessionErrorCodes = new Set([
@@ -70,11 +70,11 @@ export function turnkey<const client extends turnkey.Client>(
70
70
  ): Adapter.Adapter {
71
71
  const { icon, name = 'Turnkey', rdns = 'com.turnkey', sessionSkewMs = 10_000 } = options
72
72
 
73
- return Adapter.define({ icon, name, rdns }, ({ getAccount, getClient, store }) => {
73
+ return Adapter.define({ icon, name, rdns }, ({ getClient, store }) => {
74
74
  let turnkeyClient_promise: Promise<client> | undefined
75
75
  let expiry_timeout: ReturnType<typeof setTimeout> | undefined
76
76
  let restore_promise: Promise<void> | undefined
77
- let walletAccounts: readonly turnkey.WalletAccount[] = []
77
+ let walletAccounts_cache: readonly turnkey.WalletAccount[] | undefined
78
78
 
79
79
  async function getTurnkeyClient(): Promise<client> {
80
80
  turnkeyClient_promise ??= (async () => {
@@ -135,6 +135,16 @@ export function turnkey<const client extends turnkey.Client>(
135
135
  )
136
136
  }
137
137
 
138
+ async function refreshWalletAccounts() {
139
+ walletAccounts_cache = await fetchWalletAccounts()
140
+ return walletAccounts_cache
141
+ }
142
+
143
+ async function getWalletAccounts() {
144
+ walletAccounts_cache ??= await fetchWalletAccounts()
145
+ return walletAccounts_cache
146
+ }
147
+
138
148
  function selectWalletAccounts(
139
149
  accounts: readonly turnkey.WalletAccount[],
140
150
  addresses: turnkey.AccountSelection,
@@ -158,7 +168,7 @@ export function turnkey<const client extends turnkey.Client>(
158
168
  if (expiry_timeout) clearTimeout(expiry_timeout)
159
169
  expiry_timeout = undefined
160
170
  restore_promise = undefined
161
- walletAccounts = []
171
+ walletAccounts_cache = undefined
162
172
  store.setState({ accessKeys: [], accounts: [], activeAccount: 0 })
163
173
  }
164
174
 
@@ -185,7 +195,7 @@ export function turnkey<const client extends turnkey.Client>(
185
195
 
186
196
  async function restore() {
187
197
  await Store.waitForHydration(store)
188
- if (walletAccounts.length > 0) return
198
+ if (walletAccounts_cache) return
189
199
  if (restore_promise) return await restore_promise
190
200
 
191
201
  restore_promise = (async () => {
@@ -196,21 +206,7 @@ export function turnkey<const client extends turnkey.Client>(
196
206
  const session = await getValidSession()
197
207
  if (!session) return
198
208
 
199
- const restored = await fetchWalletAccounts()
200
- walletAccounts = persisted
201
- .map((account) =>
202
- restored.find((walletAccount) =>
203
- isAddressEqual(core_Address.from(walletAccount.address), account.address),
204
- ),
205
- )
206
- .filter((account): account is turnkey.WalletAccount => !!account)
207
-
208
- if (walletAccounts.length === 0) return
209
-
210
- store.setState({
211
- accounts: walletAccounts.map((account) => toStoreAccount(account)),
212
- activeAccount: Math.min(state.activeAccount, walletAccounts.length - 1),
213
- })
209
+ await refreshWalletAccounts()
214
210
  })()
215
211
 
216
212
  try {
@@ -225,24 +221,32 @@ export function turnkey<const client extends turnkey.Client>(
225
221
  if (!session) throw new ox_Provider.DisconnectedError({ message: 'Turnkey session expired.' })
226
222
  }
227
223
 
228
- async function accountForSigning(address: Address | undefined) {
224
+ async function getTurnkeyAccount(address: Address | undefined) {
229
225
  await restore()
230
226
  await requireSession()
231
227
 
232
- const address_ = address ?? store.getState().accounts[store.getState().activeAccount]?.address
233
- if (!address_) throw new ox_Provider.DisconnectedError({ message: 'No accounts connected.' })
234
-
235
- const account = walletAccounts.find((account) =>
236
- isAddressEqual(core_Address.from(account.address), address_),
237
- )
238
- if (account) return account
228
+ const state = store.getState()
229
+ const address_ = address ?? state.accounts[state.activeAccount]?.address
230
+ if (!address_) throw new ox_Provider.DisconnectedError({ message: 'No active account.' })
239
231
 
240
- if (walletAccounts.length === 0)
232
+ if (state.accounts.length === 0)
241
233
  throw new ox_Provider.DisconnectedError({
242
234
  message: 'No Turnkey account connected.',
243
235
  })
244
236
 
245
- throw new ox_Provider.UnauthorizedError({ message: `Account "${address_}" not found.` })
237
+ const connected = state.accounts.some((account) => isAddressEqual(account.address, address_))
238
+ if (!connected)
239
+ throw new ox_Provider.UnauthorizedError({ message: `Account "${address_}" not found.` })
240
+
241
+ const find = (accounts: readonly turnkey.WalletAccount[]) =>
242
+ accounts.find((account) => isAddressEqual(core_Address.from(account.address), address_))
243
+
244
+ const account = find(await getWalletAccounts())
245
+ if (account) return toTempoAccount(account)
246
+
247
+ throw new RpcResponse.InternalError({
248
+ message: `Connected Turnkey account "${address_}" was not found in fetched Turnkey wallet accounts. Reconnect with Turnkey.`,
249
+ })
246
250
  }
247
251
 
248
252
  function signatureToHex(value: turnkey.SignatureResponse): Hex.Hex {
@@ -273,38 +277,8 @@ export function turnkey<const client extends turnkey.Client>(
273
277
  return signatureToHex(result)
274
278
  }
275
279
 
276
- async function withAccessKey<result>(
277
- options: {
278
- address?: Address | undefined
279
- calls?: Adapter.signTransaction.Parameters['calls']
280
- chainId?: number | undefined
281
- },
282
- fn: (
283
- account: TempoAccount.Account,
284
- keyAuthorization?: KeyAuthorization.Signed,
285
- ) => Promise<result>,
286
- ): Promise<{ account: TempoAccount.Account; result: result } | undefined> {
287
- const account = (() => {
288
- try {
289
- return getAccount({ ...options, signable: true })
290
- } catch {
291
- return undefined
292
- }
293
- })()
294
- if (!account || account.source !== 'accessKey') return undefined
295
-
296
- const keyAuthorization = AccessKey.getPending(account, { store })
297
- try {
298
- const result = await fn(account, keyAuthorization ?? undefined)
299
- return { account, result }
300
- } catch (error) {
301
- AccessKey.invalidate(account, error, { store })
302
- return undefined
303
- }
304
- }
305
-
306
280
  async function signTransaction(parameters: Adapter.signTransaction.Parameters) {
307
- const account = toTempoAccount(await accountForSigning(parameters.from))
281
+ const account = await getTurnkeyAccount(parameters.from)
308
282
  const { feePayer, ...rest } = parameters
309
283
  const viemClient = getClient({
310
284
  chainId: parameters.chainId,
@@ -370,11 +344,11 @@ export function turnkey<const client extends turnkey.Client>(
370
344
  },
371
345
  })
372
346
  await requireSession()
373
- walletAccounts = selectWalletAccounts(await fetchWalletAccounts(), addresses)
347
+ const accounts = selectWalletAccounts(await refreshWalletAccounts(), addresses)
374
348
  restore_promise = undefined
375
349
 
376
350
  const digest = personalSign ? hashMessage(personalSign.message) : parameters.digest
377
- const account = walletAccounts[0]
351
+ const account = accounts[0]
378
352
  const keyAuthorization = authorizeAccessKey
379
353
  ? account
380
354
  ? await AccessKey.authorize({
@@ -387,7 +361,7 @@ export function turnkey<const client extends turnkey.Client>(
387
361
  : undefined
388
362
 
389
363
  return {
390
- accounts: walletAccounts.map((account, index) =>
364
+ accounts: accounts.map((account, index) =>
391
365
  toStoreAccount(account, index === 0 ? parameters.name : undefined),
392
366
  ),
393
367
  ...(personalSign ? { personalSign: { message: personalSign.message } } : {}),
@@ -414,11 +388,11 @@ export function turnkey<const client extends turnkey.Client>(
414
388
  const turnkeyClient = await getTurnkeyClient()
415
389
  const addresses = await options.loadAccounts({ client: turnkeyClient, parameters })
416
390
  await requireSession()
417
- walletAccounts = selectWalletAccounts(await fetchWalletAccounts(), addresses)
391
+ const accounts = selectWalletAccounts(await refreshWalletAccounts(), addresses)
418
392
  restore_promise = undefined
419
393
 
420
394
  const digest = personalSign ? hashMessage(personalSign.message) : parameters?.digest
421
- const account = walletAccounts[0]
395
+ const account = accounts[0]
422
396
  const keyAuthorization =
423
397
  authorizeAccessKey && account
424
398
  ? await AccessKey.authorize({
@@ -430,7 +404,7 @@ export function turnkey<const client extends turnkey.Client>(
430
404
  : undefined
431
405
 
432
406
  return {
433
- accounts: walletAccounts.map((account) => toStoreAccount(account)),
407
+ accounts: accounts.map((account) => toStoreAccount(account)),
434
408
  ...(personalSign ? { personalSign: { message: personalSign.message } } : {}),
435
409
  ...(keyAuthorization ? { keyAuthorization } : {}),
436
410
  signature:
@@ -444,130 +418,139 @@ export function turnkey<const client extends turnkey.Client>(
444
418
  }
445
419
  },
446
420
  async authorizeAccessKey(parameters) {
447
- const account = await accountForSigning(undefined)
421
+ const account = await getTurnkeyAccount(undefined)
448
422
  const keyAuthorization = await AccessKey.authorize({
449
- account: toTempoAccount(account),
423
+ account,
450
424
  chainId: getClient().chain.id,
451
425
  parameters,
452
426
  store,
453
427
  })
454
- return { keyAuthorization, rootAddress: core_Address.from(account.address) }
428
+ return { keyAuthorization, rootAddress: account.address }
429
+ },
430
+ async revokeAccessKey(parameters) {
431
+ const account = await getTurnkeyAccount(parameters.address)
432
+ try {
433
+ await Actions.accessKey.revoke(getClient(), {
434
+ account,
435
+ accessKey: parameters.accessKeyAddress,
436
+ })
437
+ } catch (error) {
438
+ if (!AccessKey.isUnavailableError(error)) throw error
439
+ }
440
+ AccessKey.remove({
441
+ accessKey: parameters.accessKeyAddress,
442
+ account: account.address,
443
+ chainId: store.getState().chainId,
444
+ store,
445
+ })
455
446
  },
456
447
  async signPersonalMessage(parameters) {
457
- const turnkeyClient = await getTurnkeyClient()
458
- const account = await accountForSigning(parameters.address)
459
- return await signPayload({
460
- payload: hashMessage({ raw: parameters.data }),
461
- turnkeyClient,
462
- walletAccount: account,
448
+ return await (
449
+ await getTurnkeyAccount(parameters.address)
450
+ ).sign({
451
+ hash: hashMessage({ raw: parameters.data }),
463
452
  })
464
453
  },
465
454
  async signTransaction(parameters) {
466
- const result = await withAccessKey(
467
- { address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
468
- async (account, keyAuthorization) => {
469
- const { feePayer, ...rest } = parameters
470
- const viemClient = getClient({
471
- chainId: parameters.chainId,
472
- feePayer: feePayer === true ? undefined : feePayer,
455
+ const { feePayer, ...rest } = parameters
456
+ const viemClient = getClient({
457
+ chainId: parameters.chainId,
458
+ feePayer: feePayer === true ? undefined : feePayer,
459
+ })
460
+ const state = store.getState()
461
+ const address = parameters.from ?? state.accounts[state.activeAccount]?.address
462
+ const transaction = address
463
+ ? await AccessKeyTransaction.create({
464
+ address,
465
+ calls: parameters.calls,
466
+ chainId: parameters.chainId ?? state.chainId,
467
+ client: viemClient,
468
+ store,
473
469
  })
474
- const prepared = await prepareTransactionRequest(viemClient, {
475
- account,
470
+ : undefined
471
+ if (transaction) {
472
+ try {
473
+ const prepared = await transaction.prepare({
476
474
  ...rest,
477
475
  ...(feePayer ? { feePayer: true } : {}),
478
- keyAuthorization,
479
- type: 'tempo',
480
- } as never)
481
- return await account.signTransaction(prepared as never)
482
- },
483
- )
484
- if (result !== undefined) return result.result
476
+ })
477
+ return await prepared.sign()
478
+ } catch {}
479
+ }
485
480
  return await signTransaction(parameters)
486
481
  },
487
482
  async signTypedData(parameters) {
488
- const turnkeyClient = await getTurnkeyClient()
489
- const account = await accountForSigning(parameters.address)
490
483
  const typedData = JSON.parse(parameters.data) as {
491
484
  domain: Record<string, unknown>
492
485
  message: Record<string, unknown>
493
486
  primaryType: string
494
487
  types: Record<string, unknown>
495
488
  }
496
- return await signPayload({
497
- payload: hashTypedData(typedData as never),
498
- turnkeyClient,
499
- walletAccount: account,
489
+ return await (
490
+ await getTurnkeyAccount(parameters.address)
491
+ ).sign({
492
+ hash: hashTypedData(typedData as never),
500
493
  })
501
494
  },
502
495
  async sendTransaction(parameters) {
503
- const result = await withAccessKey(
504
- { address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
505
- async (account, keyAuthorization) => {
506
- const { feePayer, ...rest } = parameters
507
- const viemClient = getClient({
508
- chainId: parameters.chainId,
509
- feePayer: feePayer === true ? undefined : feePayer,
496
+ const { feePayer, ...rest } = parameters
497
+ const viemClient = getClient({
498
+ chainId: parameters.chainId,
499
+ feePayer: feePayer === true ? undefined : feePayer,
500
+ })
501
+ const state = store.getState()
502
+ const address = parameters.from ?? state.accounts[state.activeAccount]?.address
503
+ const transaction = address
504
+ ? await AccessKeyTransaction.create({
505
+ address,
506
+ calls: parameters.calls,
507
+ chainId: parameters.chainId ?? state.chainId,
508
+ client: viemClient,
509
+ store,
510
510
  })
511
- const prepared = await prepareTransactionRequest(viemClient, {
512
- account,
511
+ : undefined
512
+ if (transaction) {
513
+ try {
514
+ const prepared = await transaction.prepare({
513
515
  ...rest,
514
516
  ...(feePayer ? { feePayer: true } : {}),
515
- keyAuthorization,
516
- type: 'tempo',
517
- } as never)
518
- const signed = await account.signTransaction(prepared as never)
519
- return await viemClient.request({
520
- method: 'eth_sendRawTransaction' as never,
521
- params: [signed],
522
517
  })
523
- },
524
- )
525
- if (result !== undefined) {
526
- AccessKey.removePending(result.account, { store })
527
- return result.result
518
+ return await prepared.send()
519
+ } catch {}
528
520
  }
529
521
  const signed = await signTransaction(parameters)
530
- const viemClient = getClient({
531
- chainId: parameters.chainId,
532
- feePayer: parameters.feePayer === true ? undefined : parameters.feePayer,
533
- })
534
522
  return await viemClient.request({
535
523
  method: 'eth_sendRawTransaction' as never,
536
524
  params: [signed],
537
525
  })
538
526
  },
539
527
  async sendTransactionSync(parameters) {
540
- const result = await withAccessKey(
541
- { address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
542
- async (account, keyAuthorization) => {
543
- const { feePayer, ...rest } = parameters
544
- const viemClient = getClient({
545
- chainId: parameters.chainId,
546
- feePayer: feePayer === true ? undefined : feePayer,
528
+ const { feePayer, ...rest } = parameters
529
+ const viemClient = getClient({
530
+ chainId: parameters.chainId,
531
+ feePayer: feePayer === true ? undefined : feePayer,
532
+ })
533
+ const state = store.getState()
534
+ const address = parameters.from ?? state.accounts[state.activeAccount]?.address
535
+ const transaction = address
536
+ ? await AccessKeyTransaction.create({
537
+ address,
538
+ calls: parameters.calls,
539
+ chainId: parameters.chainId ?? state.chainId,
540
+ client: viemClient,
541
+ store,
547
542
  })
548
- const prepared = await prepareTransactionRequest(viemClient, {
549
- account,
543
+ : undefined
544
+ if (transaction) {
545
+ try {
546
+ const prepared = await transaction.prepare({
550
547
  ...rest,
551
548
  ...(feePayer ? { feePayer: true } : {}),
552
- keyAuthorization,
553
- type: 'tempo',
554
- } as never)
555
- const signed = await account.signTransaction(prepared as never)
556
- return await viemClient.request({
557
- method: 'eth_sendRawTransactionSync' as never,
558
- params: [signed],
559
549
  })
560
- },
561
- )
562
- if (result !== undefined) {
563
- AccessKey.removePending(result.account, { store })
564
- return result.result
550
+ return await prepared.sendSync()
551
+ } catch {}
565
552
  }
566
553
  const signed = await signTransaction(parameters)
567
- const viemClient = getClient({
568
- chainId: parameters.chainId,
569
- feePayer: parameters.feePayer === true ? undefined : parameters.feePayer,
570
- })
571
554
  return await viemClient.request({
572
555
  method: 'eth_sendRawTransactionSync' as never,
573
556
  params: [signed],