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.
- package/CHANGELOG.md +23 -0
- package/README.md +6 -5
- package/dist/cli/adapter.d.ts.map +1 -1
- package/dist/cli/adapter.js +53 -67
- 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 +226 -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 +10 -2
- package/dist/core/Adapter.d.ts.map +1 -1
- package/dist/core/Provider.d.ts +4 -5
- package/dist/core/Provider.d.ts.map +1 -1
- package/dist/core/Provider.js +66 -76
- package/dist/core/Provider.js.map +1 -1
- package/dist/core/Schema.d.ts +7 -7
- package/dist/core/adapters/dialog.d.ts.map +1 -1
- package/dist/core/adapters/dialog.js +114 -124
- 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 +574 -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 +9 -4
- package/dist/core/zod/rpc.d.ts.map +1 -1
- package/dist/core/zod/rpc.js +9 -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 +61 -72
- package/dist/react-native/adapter.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 +2 -0
- package/dist/server/internal/handlers/auth.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 +115 -2
- 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 +2 -2
- package/src/cli/adapter.ts +69 -74
- package/src/core/AccessKey.test.ts +525 -559
- package/src/core/AccessKey.ts +323 -327
- package/src/core/Account.test.ts +5 -50
- package/src/core/Account.ts +1 -19
- package/src/core/Adapter.ts +6 -2
- package/src/core/{Provider.test.ts → Provider.localnet.test.ts} +97 -31
- package/src/core/Provider.ts +110 -110
- package/src/core/Schema.test-d.ts +18 -0
- package/src/core/adapters/dialog.test.ts +137 -13
- package/src/core/adapters/dialog.ts +109 -121
- 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 +634 -0
- package/src/core/adapters/privy.ts +805 -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.ts +17 -10
- package/src/index.ts +1 -1
- package/src/react-native/adapter.ts +77 -84
- 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 +3 -0
- package/src/server/internal/handlers/{relay.test.ts → relay.localnet.test.ts} +3 -0
- package/src/server/internal/handlers/relay.ts +138 -13
- 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/cli/{Provider.test.ts → Provider.localnet.test.ts} +0 -0
- /package/src/react-native/{Provider.test.ts → Provider.localnet.test.ts} +0 -0
- /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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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: (() => ({
|
|
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 }, ({
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
224
|
+
async function getTurnkeyAccount(address: Address | undefined) {
|
|
229
225
|
await restore()
|
|
230
226
|
await requireSession()
|
|
231
227
|
|
|
232
|
-
const
|
|
233
|
-
|
|
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 (
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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
|
|
421
|
+
const account = await getTurnkeyAccount(undefined)
|
|
448
422
|
const keyAuthorization = await AccessKey.authorize({
|
|
449
|
-
account
|
|
423
|
+
account,
|
|
450
424
|
chainId: getClient().chain.id,
|
|
451
425
|
parameters,
|
|
452
426
|
store,
|
|
453
427
|
})
|
|
454
|
-
return { keyAuthorization, rootAddress:
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
475
|
-
|
|
470
|
+
: undefined
|
|
471
|
+
if (transaction) {
|
|
472
|
+
try {
|
|
473
|
+
const prepared = await transaction.prepare({
|
|
476
474
|
...rest,
|
|
477
475
|
...(feePayer ? { feePayer: true } : {}),
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
|
|
512
|
-
|
|
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
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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
|
-
|
|
549
|
-
|
|
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],
|