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,12 +1,11 @@
|
|
|
1
|
-
import { Address, Provider as ox_Provider, RpcRequest as ox_RpcRequest } from 'ox'
|
|
1
|
+
import { Address, Provider as ox_Provider, RpcRequest as ox_RpcRequest, RpcResponse } from 'ox'
|
|
2
2
|
import { KeyAuthorization } from 'ox/tempo'
|
|
3
|
-
import { prepareTransactionRequest } from 'viem/actions'
|
|
4
|
-
import { Account as TempoAccount } from 'viem/tempo'
|
|
5
3
|
import { z } from 'zod/mini'
|
|
6
4
|
|
|
7
5
|
import * as AccessKey from '../AccessKey.js'
|
|
8
6
|
import * as Adapter from '../Adapter.js'
|
|
9
7
|
import * as Dialog from '../Dialog.js'
|
|
8
|
+
import * as AccessKeyTransaction from '../internal/AccessKeyTransaction.js'
|
|
10
9
|
import * as Schema from '../Schema.js'
|
|
11
10
|
import type * as Store from '../Store.js'
|
|
12
11
|
import * as Rpc from '../zod/rpc.js'
|
|
@@ -115,11 +114,16 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
115
114
|
async function generateAccessKey(options: Adapter.authorizeAccessKey.Parameters | undefined) {
|
|
116
115
|
if (!options) return undefined
|
|
117
116
|
if (options.publicKey || options.address) return undefined
|
|
117
|
+
if (options.keyType && options.keyType !== 'p256')
|
|
118
|
+
throw new RpcResponse.InvalidParamsError({
|
|
119
|
+
message: `\`keyType: "${options.keyType}"\` requires externally generated key material; provide \`publicKey\` or \`address\`.`,
|
|
120
|
+
})
|
|
118
121
|
|
|
119
|
-
const
|
|
122
|
+
const generated = await AccessKey.generate()
|
|
123
|
+
const { accessKey } = generated
|
|
120
124
|
return {
|
|
121
125
|
accessKey,
|
|
122
|
-
|
|
126
|
+
generated,
|
|
123
127
|
request: {
|
|
124
128
|
...options,
|
|
125
129
|
publicKey: accessKey.publicKey,
|
|
@@ -135,44 +139,15 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
135
139
|
function saveAccessKey(
|
|
136
140
|
address: Address.Address,
|
|
137
141
|
keyAuth: KeyAuthorization.Rpc,
|
|
138
|
-
|
|
142
|
+
generated: Awaited<ReturnType<typeof AccessKey.generate>>,
|
|
139
143
|
) {
|
|
140
144
|
const keyAuthorization = KeyAuthorization.fromRpc(keyAuth)
|
|
141
|
-
AccessKey.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
* Tries to execute `fn` with the local access key. Returns `undefined`
|
|
146
|
-
* when no access key exists so the caller can fall through to the dialog.
|
|
147
|
-
* On stale-key errors, removes the key and also returns `undefined`.
|
|
148
|
-
* On recoverable transaction errors, keeps the key and falls through to
|
|
149
|
-
* the dialog so the user can fund, approve, or retry.
|
|
150
|
-
*/
|
|
151
|
-
async function withAccessKey<result>(
|
|
152
|
-
options: Pick<Adapter.sendTransaction.Parameters, 'calls' | 'chainId' | 'from'>,
|
|
153
|
-
fn: (
|
|
154
|
-
account: TempoAccount.Account,
|
|
155
|
-
keyAuthorization?: KeyAuthorization.Signed,
|
|
156
|
-
) => Promise<result>,
|
|
157
|
-
): Promise<{ account: TempoAccount.Account; result: result } | undefined> {
|
|
158
|
-
if (!options.from || typeof options.chainId === 'undefined') return undefined
|
|
159
|
-
const account = AccessKey.selectAccount({
|
|
160
|
-
address: options.from,
|
|
161
|
-
calls: options.calls,
|
|
162
|
-
chainId: options.chainId,
|
|
145
|
+
AccessKey.add({
|
|
146
|
+
account: address,
|
|
147
|
+
authorization: keyAuthorization,
|
|
148
|
+
keyPair: generated.keyPair,
|
|
163
149
|
store,
|
|
164
150
|
})
|
|
165
|
-
if (!account) return undefined
|
|
166
|
-
const keyAuthorization = AccessKey.getPending(account, { store })
|
|
167
|
-
try {
|
|
168
|
-
const result = await fn(account, keyAuthorization ?? undefined)
|
|
169
|
-
return { account, result }
|
|
170
|
-
} catch (err) {
|
|
171
|
-
if (AccessKey.invalidate(account, err, { store }))
|
|
172
|
-
console.warn('[accounts] access key invalidated, falling through to dialog:', err)
|
|
173
|
-
else console.warn('[accounts] access key sign failed, falling through to dialog:', err)
|
|
174
|
-
return undefined
|
|
175
|
-
}
|
|
176
151
|
}
|
|
177
152
|
|
|
178
153
|
const dialogInstance = dialog({ host, store, theme })
|
|
@@ -224,20 +199,18 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
224
199
|
})
|
|
225
200
|
|
|
226
201
|
const address = accounts[0]?.address
|
|
227
|
-
const
|
|
202
|
+
const capabilities = accounts[0]?.capabilities
|
|
203
|
+
const keyAuthorization = capabilities?.keyAuthorization
|
|
228
204
|
|
|
229
205
|
if (accessKey && address && keyAuthorization)
|
|
230
|
-
saveAccessKey(address, keyAuthorization, accessKey.
|
|
206
|
+
saveAccessKey(address, keyAuthorization, accessKey.generated)
|
|
231
207
|
|
|
232
208
|
return {
|
|
233
209
|
accounts: accounts.map((a) => ({ address: a.address })),
|
|
210
|
+
...(capabilities?.auth ? { auth: capabilities.auth } : {}),
|
|
234
211
|
...(keyAuthorization ? { keyAuthorization } : {}),
|
|
235
|
-
...(
|
|
236
|
-
|
|
237
|
-
: {}),
|
|
238
|
-
...(accounts[0]?.capabilities.personalSign
|
|
239
|
-
? { personalSign: accounts[0].capabilities.personalSign }
|
|
240
|
-
: {}),
|
|
212
|
+
...(capabilities?.signature ? { signature: capabilities.signature } : {}),
|
|
213
|
+
...(capabilities?.personalSign ? { personalSign: capabilities.personalSign } : {}),
|
|
241
214
|
}
|
|
242
215
|
},
|
|
243
216
|
|
|
@@ -265,20 +238,18 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
265
238
|
})
|
|
266
239
|
|
|
267
240
|
const address = accounts[0]?.address
|
|
268
|
-
const
|
|
241
|
+
const capabilities = accounts[0]?.capabilities
|
|
242
|
+
const keyAuthorization = capabilities?.keyAuthorization
|
|
269
243
|
|
|
270
244
|
if (accessKey && address && keyAuthorization)
|
|
271
|
-
saveAccessKey(address, keyAuthorization, accessKey.
|
|
245
|
+
saveAccessKey(address, keyAuthorization, accessKey.generated)
|
|
272
246
|
|
|
273
247
|
return {
|
|
274
248
|
accounts: accounts.map((a) => ({ address: a.address })),
|
|
249
|
+
...(capabilities?.auth ? { auth: capabilities.auth } : {}),
|
|
275
250
|
...(keyAuthorization ? { keyAuthorization } : {}),
|
|
276
|
-
...(
|
|
277
|
-
|
|
278
|
-
: {}),
|
|
279
|
-
...(accounts[0]?.capabilities.personalSign
|
|
280
|
-
? { personalSign: accounts[0].capabilities.personalSign }
|
|
281
|
-
: {}),
|
|
251
|
+
...(capabilities?.signature ? { signature: capabilities.signature } : {}),
|
|
252
|
+
...(capabilities?.personalSign ? { personalSign: capabilities.personalSign } : {}),
|
|
282
253
|
}
|
|
283
254
|
},
|
|
284
255
|
|
|
@@ -287,26 +258,36 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
287
258
|
},
|
|
288
259
|
|
|
289
260
|
async signTransaction(parameters, request) {
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
feePayer
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
})(),
|
|
299
|
-
})
|
|
300
|
-
const prepared = await prepareTransactionRequest(client, {
|
|
301
|
-
account,
|
|
302
|
-
...rest,
|
|
303
|
-
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
304
|
-
keyAuthorization,
|
|
305
|
-
type: 'tempo',
|
|
306
|
-
})
|
|
307
|
-
return await account.signTransaction(prepared as never)
|
|
261
|
+
const { feePayer, ...rest } = parameters
|
|
262
|
+
const client = getClient({
|
|
263
|
+
chainId: parameters.chainId,
|
|
264
|
+
feePayer: (() => {
|
|
265
|
+
if (feePayer === false) return false
|
|
266
|
+
if (typeof feePayer === 'string') return feePayer
|
|
267
|
+
return undefined
|
|
268
|
+
})(),
|
|
308
269
|
})
|
|
309
|
-
|
|
270
|
+
const transaction =
|
|
271
|
+
parameters.from && typeof parameters.chainId !== 'undefined'
|
|
272
|
+
? await AccessKeyTransaction.create({
|
|
273
|
+
address: parameters.from,
|
|
274
|
+
calls: parameters.calls,
|
|
275
|
+
chainId: parameters.chainId,
|
|
276
|
+
client,
|
|
277
|
+
store,
|
|
278
|
+
})
|
|
279
|
+
: undefined
|
|
280
|
+
if (transaction) {
|
|
281
|
+
try {
|
|
282
|
+
const prepared = await transaction.prepare({
|
|
283
|
+
...rest,
|
|
284
|
+
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
285
|
+
})
|
|
286
|
+
return await prepared.sign()
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.warn('[accounts] access key sign failed, falling through to dialog:', error)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
310
291
|
return await provider.request({
|
|
311
292
|
...request,
|
|
312
293
|
params: [z.encode(Rpc.transactionRequest, parameters)] as const,
|
|
@@ -318,32 +299,35 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
318
299
|
},
|
|
319
300
|
|
|
320
301
|
async sendTransaction(parameters, request) {
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
feePayer
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
})(),
|
|
330
|
-
})
|
|
331
|
-
const prepared = await prepareTransactionRequest(client, {
|
|
332
|
-
account,
|
|
333
|
-
...rest,
|
|
334
|
-
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
335
|
-
keyAuthorization,
|
|
336
|
-
type: 'tempo',
|
|
337
|
-
})
|
|
338
|
-
const signed = await account.signTransaction(prepared as never)
|
|
339
|
-
return await client.request({
|
|
340
|
-
method: 'eth_sendRawTransaction' as never,
|
|
341
|
-
params: [signed],
|
|
342
|
-
})
|
|
302
|
+
const { feePayer, ...rest } = parameters
|
|
303
|
+
const client = getClient({
|
|
304
|
+
chainId: parameters.chainId,
|
|
305
|
+
feePayer: (() => {
|
|
306
|
+
if (feePayer === false) return false
|
|
307
|
+
if (typeof feePayer === 'string') return feePayer
|
|
308
|
+
return undefined
|
|
309
|
+
})(),
|
|
343
310
|
})
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
311
|
+
const transaction =
|
|
312
|
+
parameters.from && typeof parameters.chainId !== 'undefined'
|
|
313
|
+
? await AccessKeyTransaction.create({
|
|
314
|
+
address: parameters.from,
|
|
315
|
+
calls: parameters.calls,
|
|
316
|
+
chainId: parameters.chainId,
|
|
317
|
+
client,
|
|
318
|
+
store,
|
|
319
|
+
})
|
|
320
|
+
: undefined
|
|
321
|
+
if (transaction) {
|
|
322
|
+
try {
|
|
323
|
+
const prepared = await transaction.prepare({
|
|
324
|
+
...rest,
|
|
325
|
+
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
326
|
+
})
|
|
327
|
+
return await prepared.send()
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.warn('[accounts] access key sign failed, falling through to dialog:', error)
|
|
330
|
+
}
|
|
347
331
|
}
|
|
348
332
|
return await provider.request({
|
|
349
333
|
...request,
|
|
@@ -352,32 +336,35 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
352
336
|
},
|
|
353
337
|
|
|
354
338
|
async sendTransactionSync(parameters, request) {
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
feePayer
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
})(),
|
|
364
|
-
})
|
|
365
|
-
const prepared = await prepareTransactionRequest(client, {
|
|
366
|
-
account,
|
|
367
|
-
...rest,
|
|
368
|
-
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
369
|
-
keyAuthorization,
|
|
370
|
-
type: 'tempo',
|
|
371
|
-
})
|
|
372
|
-
const signed = await account.signTransaction(prepared as never)
|
|
373
|
-
return await client.request({
|
|
374
|
-
method: 'eth_sendRawTransactionSync' as never,
|
|
375
|
-
params: [signed],
|
|
376
|
-
})
|
|
339
|
+
const { feePayer, ...rest } = parameters
|
|
340
|
+
const client = getClient({
|
|
341
|
+
chainId: parameters.chainId,
|
|
342
|
+
feePayer: (() => {
|
|
343
|
+
if (feePayer === false) return false
|
|
344
|
+
if (typeof feePayer === 'string') return feePayer
|
|
345
|
+
return undefined
|
|
346
|
+
})(),
|
|
377
347
|
})
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
348
|
+
const transaction =
|
|
349
|
+
parameters.from && typeof parameters.chainId !== 'undefined'
|
|
350
|
+
? await AccessKeyTransaction.create({
|
|
351
|
+
address: parameters.from,
|
|
352
|
+
calls: parameters.calls,
|
|
353
|
+
chainId: parameters.chainId,
|
|
354
|
+
client,
|
|
355
|
+
store,
|
|
356
|
+
})
|
|
357
|
+
: undefined
|
|
358
|
+
if (transaction) {
|
|
359
|
+
try {
|
|
360
|
+
const prepared = await transaction.prepare({
|
|
361
|
+
...rest,
|
|
362
|
+
...(typeof feePayer !== 'undefined' ? { feePayer: !!feePayer as never } : {}),
|
|
363
|
+
})
|
|
364
|
+
return await prepared.sendSync()
|
|
365
|
+
} catch (error) {
|
|
366
|
+
console.warn('[accounts] access key sign failed, falling through to dialog:', error)
|
|
367
|
+
}
|
|
381
368
|
}
|
|
382
369
|
return await provider.request({
|
|
383
370
|
...request,
|
|
@@ -399,15 +386,21 @@ export function dialog(options: dialog.Options = {}): Adapter.Adapter {
|
|
|
399
386
|
})
|
|
400
387
|
|
|
401
388
|
if (accessKey) {
|
|
402
|
-
const account = getAccount({
|
|
403
|
-
saveAccessKey(account.address, result.keyAuthorization, accessKey.
|
|
389
|
+
const account = getAccount({ signable: false })
|
|
390
|
+
saveAccessKey(account.address, result.keyAuthorization, accessKey.generated)
|
|
404
391
|
}
|
|
405
392
|
|
|
406
393
|
return result
|
|
407
394
|
},
|
|
408
395
|
|
|
409
|
-
async revokeAccessKey(
|
|
396
|
+
async revokeAccessKey(params, request) {
|
|
410
397
|
await provider.request(request)
|
|
398
|
+
AccessKey.remove({
|
|
399
|
+
accessKey: params.accessKeyAddress,
|
|
400
|
+
account: params.address,
|
|
401
|
+
chainId: store.getState().chainId,
|
|
402
|
+
store,
|
|
403
|
+
})
|
|
411
404
|
},
|
|
412
405
|
|
|
413
406
|
async deposit(_params, request) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Provider as ox_Provider } from 'ox'
|
|
2
|
-
import { KeyAuthorization } from 'ox/tempo'
|
|
3
|
-
import {
|
|
2
|
+
import { KeyAuthorization, SignatureEnvelope } from 'ox/tempo'
|
|
3
|
+
import { hashMessage } from 'viem'
|
|
4
4
|
import { prepareTransactionRequest } from 'viem/actions'
|
|
5
|
-
import {
|
|
5
|
+
import { Actions } from 'viem/tempo'
|
|
6
6
|
|
|
7
7
|
import * as AccessKey from '../AccessKey.js'
|
|
8
8
|
import * as Account from '../Account.js'
|
|
9
9
|
import * as Adapter from '../Adapter.js'
|
|
10
|
+
import * as AccessKeyTransaction from '../internal/AccessKeyTransaction.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Creates a local adapter where the app manages keys and signing in-process.
|
|
@@ -28,22 +29,67 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
28
29
|
const { createAccount, icon, loadAccounts, name, rdns } = options
|
|
29
30
|
|
|
30
31
|
return Adapter.define({ icon, name, rdns }, ({ getAccount, getClient, store }) => {
|
|
31
|
-
async function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
async function prepareTransaction(parameters: Adapter.signTransaction.Parameters) {
|
|
33
|
+
const { feePayer, ...rest } = parameters
|
|
34
|
+
const client = getClient({
|
|
35
|
+
chainId: parameters.chainId,
|
|
36
|
+
feePayer: (() => {
|
|
37
|
+
if (feePayer === false) return false
|
|
38
|
+
if (typeof feePayer === 'string') return feePayer
|
|
39
|
+
return undefined
|
|
40
|
+
})(),
|
|
41
|
+
})
|
|
42
|
+
const request = {
|
|
43
|
+
...rest,
|
|
44
|
+
...(feePayer ? { feePayer: true as const } : {}),
|
|
45
|
+
}
|
|
46
|
+
const state = store.getState()
|
|
47
|
+
const address = parameters.from ?? state.accounts[state.activeAccount]?.address
|
|
48
|
+
const transaction = address
|
|
49
|
+
? await AccessKeyTransaction.create({
|
|
50
|
+
address,
|
|
51
|
+
calls: parameters.calls,
|
|
52
|
+
chainId: parameters.chainId ?? state.chainId,
|
|
53
|
+
client,
|
|
54
|
+
store,
|
|
55
|
+
})
|
|
56
|
+
: undefined
|
|
57
|
+
if (transaction) {
|
|
58
|
+
try {
|
|
59
|
+
return await transaction.prepare(request)
|
|
60
|
+
} catch {}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const account = getAccount({
|
|
64
|
+
address: parameters.from,
|
|
65
|
+
signable: true,
|
|
66
|
+
})
|
|
67
|
+
const prepared = await prepareTransactionRequest(client, {
|
|
68
|
+
account,
|
|
69
|
+
...request,
|
|
70
|
+
keyAuthorization: undefined,
|
|
71
|
+
type: 'tempo',
|
|
72
|
+
})
|
|
73
|
+
async function sign() {
|
|
74
|
+
return await account.signTransaction(prepared as never)
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
request: prepared,
|
|
78
|
+
sign,
|
|
79
|
+
async send() {
|
|
80
|
+
const signed = await sign()
|
|
81
|
+
return (await client.request({
|
|
82
|
+
method: 'eth_sendRawTransaction' as never,
|
|
83
|
+
params: [signed],
|
|
84
|
+
})) as Adapter.sendTransaction.ReturnType
|
|
85
|
+
},
|
|
86
|
+
async sendSync() {
|
|
87
|
+
const signed = await sign()
|
|
88
|
+
return (await client.request({
|
|
89
|
+
method: 'eth_sendRawTransactionSync' as never,
|
|
90
|
+
params: [signed],
|
|
91
|
+
})) as Adapter.sendTransactionSync.ReturnType
|
|
92
|
+
},
|
|
47
93
|
}
|
|
48
94
|
}
|
|
49
95
|
|
|
@@ -102,7 +148,7 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
102
148
|
}
|
|
103
149
|
},
|
|
104
150
|
async authorizeAccessKey(parameters) {
|
|
105
|
-
const account = getAccount({
|
|
151
|
+
const account = getAccount({ signable: true })
|
|
106
152
|
const keyAuthorization = await AccessKey.authorize({
|
|
107
153
|
account,
|
|
108
154
|
chainId: getClient().chain.id,
|
|
@@ -139,7 +185,7 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
139
185
|
|
|
140
186
|
// Slot allocation:
|
|
141
187
|
// 1. `personalSign` digest, if present.
|
|
142
|
-
// 2. Else key-auth digest (existing 1-prompt fold for `authorizeAccessKey`).
|
|
188
|
+
// 2. Else unsigned key-auth digest (existing 1-prompt fold for `authorizeAccessKey`).
|
|
143
189
|
// 3. Else caller's `rest.digest`.
|
|
144
190
|
// When BOTH `personalSign` and `authorizeAccessKey` are present,
|
|
145
191
|
// `personalSign` wins the load-accounts ceremony and the key
|
|
@@ -169,12 +215,21 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
169
215
|
peronsalSign_digest || !signature_
|
|
170
216
|
? await account.sign({ hash: keyAuthorization_digest! })
|
|
171
217
|
: signature_
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
218
|
+
const keyAuthorization = KeyAuthorization.from(
|
|
219
|
+
keyAuthorization_unsigned.keyAuthorization,
|
|
220
|
+
{
|
|
221
|
+
signature: SignatureEnvelope.from(signature_keyAuthorization),
|
|
222
|
+
},
|
|
223
|
+
)
|
|
224
|
+
AccessKey.add({
|
|
225
|
+
account: account.address,
|
|
226
|
+
authorization: keyAuthorization,
|
|
227
|
+
...(keyAuthorization_unsigned.keyPair
|
|
228
|
+
? { keyPair: keyAuthorization_unsigned.keyPair }
|
|
229
|
+
: {}),
|
|
176
230
|
store,
|
|
177
231
|
})
|
|
232
|
+
return KeyAuthorization.toRpc(keyAuthorization)
|
|
178
233
|
})()
|
|
179
234
|
|
|
180
235
|
return {
|
|
@@ -187,55 +242,30 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
187
242
|
}
|
|
188
243
|
},
|
|
189
244
|
async revokeAccessKey(parameters) {
|
|
190
|
-
const account = getAccount({
|
|
245
|
+
const account = getAccount({ signable: true })
|
|
191
246
|
const client = getClient()
|
|
192
247
|
try {
|
|
193
248
|
await Actions.accessKey.revoke(client, {
|
|
194
249
|
account,
|
|
195
250
|
accessKey: parameters.accessKeyAddress,
|
|
196
|
-
}
|
|
251
|
+
})
|
|
197
252
|
} catch (error) {
|
|
198
|
-
|
|
199
|
-
error instanceof BaseError &&
|
|
200
|
-
!!error.walk(
|
|
201
|
-
(e) => (e as { data?: { errorName?: string } }).data?.errorName === 'KeyNotFound',
|
|
202
|
-
)
|
|
203
|
-
if (!isKeyNotFound) throw error
|
|
253
|
+
if (!AccessKey.isUnavailableError(error)) throw error
|
|
204
254
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
255
|
+
AccessKey.remove({
|
|
256
|
+
accessKey: parameters.accessKeyAddress,
|
|
257
|
+
account: account.address,
|
|
258
|
+
chainId: client.chain.id,
|
|
259
|
+
store,
|
|
260
|
+
})
|
|
210
261
|
},
|
|
211
262
|
async signPersonalMessage({ data, address }) {
|
|
212
263
|
const account = getAccount({ address, signable: true })
|
|
213
264
|
return await account.signMessage({ message: { raw: data } })
|
|
214
265
|
},
|
|
215
266
|
async signTransaction(parameters) {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
chainId: parameters.chainId,
|
|
219
|
-
feePayer: (() => {
|
|
220
|
-
if (feePayer === false) return false
|
|
221
|
-
if (typeof feePayer === 'string') return feePayer
|
|
222
|
-
return undefined
|
|
223
|
-
})(),
|
|
224
|
-
})
|
|
225
|
-
const { account, prepared } = await withAccessKey(
|
|
226
|
-
{ address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
|
|
227
|
-
async (account, keyAuthorization) => ({
|
|
228
|
-
account,
|
|
229
|
-
prepared: await prepareTransactionRequest(client, {
|
|
230
|
-
account,
|
|
231
|
-
...rest,
|
|
232
|
-
...(feePayer ? { feePayer: true } : {}),
|
|
233
|
-
keyAuthorization,
|
|
234
|
-
type: 'tempo',
|
|
235
|
-
}),
|
|
236
|
-
}),
|
|
237
|
-
)
|
|
238
|
-
return await account.signTransaction(prepared as never)
|
|
267
|
+
const prepared = await prepareTransaction(parameters)
|
|
268
|
+
return await prepared.sign()
|
|
239
269
|
},
|
|
240
270
|
async signTypedData({ data, address }) {
|
|
241
271
|
const account = getAccount({ address, signable: true })
|
|
@@ -248,66 +278,12 @@ export function local(options: local.Options): Adapter.Adapter {
|
|
|
248
278
|
return await account.signTypedData(parsed)
|
|
249
279
|
},
|
|
250
280
|
async sendTransaction(parameters) {
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
chainId: parameters.chainId,
|
|
254
|
-
feePayer: (() => {
|
|
255
|
-
if (feePayer === false) return false
|
|
256
|
-
if (typeof feePayer === 'string') return feePayer
|
|
257
|
-
return undefined
|
|
258
|
-
})(),
|
|
259
|
-
})
|
|
260
|
-
const { account, prepared } = await withAccessKey(
|
|
261
|
-
{ address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
|
|
262
|
-
async (account, keyAuthorization) => ({
|
|
263
|
-
account,
|
|
264
|
-
prepared: await prepareTransactionRequest(client, {
|
|
265
|
-
account,
|
|
266
|
-
...rest,
|
|
267
|
-
...(feePayer ? { feePayer: true } : {}),
|
|
268
|
-
keyAuthorization,
|
|
269
|
-
type: 'tempo',
|
|
270
|
-
}),
|
|
271
|
-
}),
|
|
272
|
-
)
|
|
273
|
-
const signed = await account.signTransaction(prepared as never)
|
|
274
|
-
const result = await client.request({
|
|
275
|
-
method: 'eth_sendRawTransaction' as never,
|
|
276
|
-
params: [signed],
|
|
277
|
-
})
|
|
278
|
-
AccessKey.removePending(account, { store })
|
|
279
|
-
return result
|
|
281
|
+
const prepared = await prepareTransaction(parameters)
|
|
282
|
+
return await prepared.send()
|
|
280
283
|
},
|
|
281
284
|
async sendTransactionSync(parameters) {
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
chainId: parameters.chainId,
|
|
285
|
-
feePayer: (() => {
|
|
286
|
-
if (feePayer === false) return false
|
|
287
|
-
if (typeof feePayer === 'string') return feePayer
|
|
288
|
-
return undefined
|
|
289
|
-
})(),
|
|
290
|
-
})
|
|
291
|
-
const { account, prepared } = await withAccessKey(
|
|
292
|
-
{ address: parameters.from, calls: parameters.calls, chainId: parameters.chainId },
|
|
293
|
-
async (account, keyAuthorization) => ({
|
|
294
|
-
account,
|
|
295
|
-
prepared: await prepareTransactionRequest(client, {
|
|
296
|
-
account,
|
|
297
|
-
...rest,
|
|
298
|
-
...(feePayer ? { feePayer: true } : {}),
|
|
299
|
-
keyAuthorization,
|
|
300
|
-
type: 'tempo',
|
|
301
|
-
}),
|
|
302
|
-
}),
|
|
303
|
-
)
|
|
304
|
-
const signed = await account.signTransaction(prepared as never)
|
|
305
|
-
const result = await client.request({
|
|
306
|
-
method: 'eth_sendRawTransactionSync' as never,
|
|
307
|
-
params: [signed],
|
|
308
|
-
})
|
|
309
|
-
AccessKey.removePending(account, { store })
|
|
310
|
-
return result
|
|
285
|
+
const prepared = await prepareTransaction(parameters)
|
|
286
|
+
return await prepared.sendSync()
|
|
311
287
|
},
|
|
312
288
|
},
|
|
313
289
|
}
|