accounts 0.5.5 → 0.5.7
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 +12 -0
- package/dist/core/Client.d.ts +1 -1
- package/dist/core/Client.d.ts.map +1 -1
- package/dist/core/Client.js +43 -4
- package/dist/core/Client.js.map +1 -1
- package/dist/core/Dialog.d.ts.map +1 -1
- package/dist/core/Dialog.js +64 -23
- package/dist/core/Dialog.js.map +1 -1
- package/dist/core/Provider.d.ts.map +1 -1
- package/dist/core/Provider.js +27 -10
- package/dist/core/Provider.js.map +1 -1
- package/dist/core/adapters/dangerous_secp256k1.d.ts +3 -0
- package/dist/core/adapters/dangerous_secp256k1.d.ts.map +1 -1
- package/dist/core/adapters/dangerous_secp256k1.js +15 -4
- package/dist/core/adapters/dangerous_secp256k1.js.map +1 -1
- package/dist/server/Handler.d.ts +7 -3
- package/dist/server/Handler.d.ts.map +1 -1
- package/dist/server/Handler.js +142 -13
- package/dist/server/Handler.js.map +1 -1
- package/dist/wagmi/Connector.js +2 -2
- package/dist/wagmi/Connector.js.map +1 -1
- package/package.json +2 -2
- package/src/core/Client.ts +53 -5
- package/src/core/Dialog.ts +69 -26
- package/src/core/Provider.test.ts +14 -0
- package/src/core/Provider.ts +28 -8
- package/src/core/adapters/dangerous_secp256k1.test.ts +24 -0
- package/src/core/adapters/dangerous_secp256k1.ts +17 -4
- package/src/server/Handler.test.ts +96 -4
- package/src/server/Handler.ts +180 -24
- package/src/wagmi/Connector.ts +2 -2
package/src/server/Handler.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono'
|
|
2
|
-
import { Base64, Bytes, Hex, RpcRequest, RpcResponse } from 'ox'
|
|
2
|
+
import { Base64, Bytes, Hex, RpcRequest, RpcResponse, Signature } from 'ox'
|
|
3
|
+
import { Transaction as core_Transaction, TxEnvelopeTempo } from 'ox/tempo'
|
|
3
4
|
import { Credential } from 'ox/webauthn'
|
|
4
5
|
import { type Chain, type Client, createClient, http, type Transport } from 'viem'
|
|
5
6
|
import type { LocalAccount } from 'viem/accounts'
|
|
@@ -15,7 +16,7 @@ import * as z from 'zod/mini'
|
|
|
15
16
|
|
|
16
17
|
import * as CliAuth from './CliAuth.js'
|
|
17
18
|
import * as RequestListener from './internal/requestListener.js'
|
|
18
|
-
import
|
|
19
|
+
import * as Kv from './Kv.js'
|
|
19
20
|
|
|
20
21
|
export type Handler = Hono & {
|
|
21
22
|
listener: (req: any, res: any) => void
|
|
@@ -228,7 +229,7 @@ export declare namespace from {
|
|
|
228
229
|
* chains: [tempo, tempoModerato],
|
|
229
230
|
* transports: {
|
|
230
231
|
* [tempo.id]: http('https://rpc.tempo.xyz'),
|
|
231
|
-
* [tempoModerato.id]: http('https://rpc.
|
|
232
|
+
* [tempoModerato.id]: http('https://rpc.testnet.tempo.xyz'),
|
|
232
233
|
* },
|
|
233
234
|
* })
|
|
234
235
|
* ```
|
|
@@ -240,9 +241,12 @@ export function feePayer(options: feePayer.Options) {
|
|
|
240
241
|
const {
|
|
241
242
|
account,
|
|
242
243
|
chains = [tempo, tempoModerato],
|
|
244
|
+
name,
|
|
243
245
|
onRequest,
|
|
244
246
|
path = '/',
|
|
245
247
|
transports = {},
|
|
248
|
+
url,
|
|
249
|
+
...rest
|
|
246
250
|
} = options
|
|
247
251
|
|
|
248
252
|
const clients = new Map<number, Client>()
|
|
@@ -260,7 +264,13 @@ export function feePayer(options: feePayer.Options) {
|
|
|
260
264
|
return clients.get(chains[0]!.id)!
|
|
261
265
|
}
|
|
262
266
|
|
|
263
|
-
const
|
|
267
|
+
const sponsor = {
|
|
268
|
+
address: account.address,
|
|
269
|
+
...(name ? { name } : {}),
|
|
270
|
+
...(url ? { url } : {}),
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const router = from(rest)
|
|
264
274
|
|
|
265
275
|
router.post(path, async (c) => {
|
|
266
276
|
const request = RpcRequest.from((await c.req.raw.json()) as any)
|
|
@@ -270,6 +280,7 @@ export function feePayer(options: feePayer.Options) {
|
|
|
270
280
|
|
|
271
281
|
const method = request.method as string
|
|
272
282
|
if (
|
|
283
|
+
method !== 'eth_fillTransaction' &&
|
|
273
284
|
method !== 'eth_signRawTransaction' &&
|
|
274
285
|
method !== 'eth_sendRawTransaction' &&
|
|
275
286
|
method !== 'eth_sendRawTransactionSync'
|
|
@@ -285,14 +296,65 @@ export function feePayer(options: feePayer.Options) {
|
|
|
285
296
|
),
|
|
286
297
|
)
|
|
287
298
|
|
|
288
|
-
|
|
299
|
+
if (method === 'eth_fillTransaction') {
|
|
300
|
+
const [parameters] = z
|
|
301
|
+
.readonly(z.tuple([z.record(z.string(), z.unknown())]))
|
|
302
|
+
.parse(request.params) as [Record<string, unknown>]
|
|
303
|
+
const chainId = resolveChainId(parameters.chainId)
|
|
304
|
+
const client = getClient(chainId)
|
|
305
|
+
const transaction = await (async () => {
|
|
306
|
+
if (isPreparedFeePayerTransaction(parameters))
|
|
307
|
+
return normalizeTempoTransaction(parameters)
|
|
308
|
+
|
|
309
|
+
const fillRequest = formatFillTransactionRequest(client, {
|
|
310
|
+
...normalizeFillTransactionRequest(parameters),
|
|
311
|
+
...(typeof chainId !== 'undefined' ? { chainId } : {}),
|
|
312
|
+
feePayer: true,
|
|
313
|
+
})
|
|
314
|
+
const result = (await client.request({
|
|
315
|
+
method: 'eth_fillTransaction' as never,
|
|
316
|
+
params: [fillRequest],
|
|
317
|
+
})) as { tx?: Record<string, unknown> | undefined }
|
|
318
|
+
return normalizeTempoTransaction(result.tx)
|
|
319
|
+
})()
|
|
320
|
+
|
|
321
|
+
const from =
|
|
322
|
+
(transaction.from as `0x${string}` | undefined) ??
|
|
323
|
+
(typeof parameters.from === 'string' ? (parameters.from as `0x${string}`) : undefined)
|
|
324
|
+
const { signature: _, ...withoutSenderSig } = transaction as Record<string, unknown>
|
|
325
|
+
const prepared = { ...withoutSenderSig, from }
|
|
326
|
+
|
|
327
|
+
if (!prepared.from)
|
|
328
|
+
throw new RpcResponse.InvalidParamsError({
|
|
329
|
+
message: 'Transaction sender must be provided before fee payer signing.',
|
|
330
|
+
})
|
|
331
|
+
if (!account.sign) throw new Error('Fee payer account cannot sign transactions.')
|
|
332
|
+
|
|
333
|
+
const feePayerSignature = Signature.from(
|
|
334
|
+
await account.sign({
|
|
335
|
+
hash: TxEnvelopeTempo.getFeePayerSignPayload(TxEnvelopeTempo.from(prepared as never), {
|
|
336
|
+
sender: prepared.from,
|
|
337
|
+
}),
|
|
338
|
+
}),
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
return rpcResult(request, {
|
|
342
|
+
sponsor,
|
|
343
|
+
tx: core_Transaction.toRpc({
|
|
344
|
+
...prepared,
|
|
345
|
+
feePayerSignature,
|
|
346
|
+
} as core_Transaction.Transaction),
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const serialized = request.params?.[0] as `0x76${string}` | undefined
|
|
289
351
|
|
|
290
352
|
if (!serialized?.startsWith('0x76') && !serialized?.startsWith('0x78'))
|
|
291
353
|
throw new RpcResponse.InvalidParamsError({
|
|
292
354
|
message: 'Only Tempo (0x76/0x78) transactions are supported.',
|
|
293
355
|
})
|
|
294
356
|
|
|
295
|
-
const transaction = Transaction.deserialize(serialized)
|
|
357
|
+
const transaction = Transaction.deserialize(serialized)
|
|
296
358
|
|
|
297
359
|
if (!transaction.signature || !transaction.from)
|
|
298
360
|
throw new RpcResponse.InvalidParamsError({
|
|
@@ -300,32 +362,25 @@ export function feePayer(options: feePayer.Options) {
|
|
|
300
362
|
})
|
|
301
363
|
|
|
302
364
|
const client = getClient(transaction.chainId)
|
|
303
|
-
const serializedTransaction =
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
365
|
+
const serializedTransaction = toSerializedTransaction(
|
|
366
|
+
await signTransaction(client, {
|
|
367
|
+
...transaction,
|
|
368
|
+
account,
|
|
369
|
+
feePayer: account,
|
|
370
|
+
} as never),
|
|
371
|
+
)
|
|
308
372
|
|
|
309
373
|
if (method === 'eth_signRawTransaction')
|
|
310
374
|
return Response.json(RpcResponse.from({ result: serializedTransaction }, { request }))
|
|
311
375
|
|
|
312
|
-
const result = await
|
|
313
|
-
method,
|
|
376
|
+
const result = await client.request({
|
|
377
|
+
method: method as never,
|
|
314
378
|
params: [serializedTransaction],
|
|
315
379
|
})
|
|
316
380
|
|
|
317
381
|
return Response.json(RpcResponse.from({ result }, { request }))
|
|
318
382
|
} catch (error) {
|
|
319
|
-
return
|
|
320
|
-
RpcResponse.from(
|
|
321
|
-
{
|
|
322
|
-
error: new RpcResponse.InternalError({
|
|
323
|
-
message: (error as Error).message,
|
|
324
|
-
}),
|
|
325
|
-
},
|
|
326
|
-
{ request },
|
|
327
|
-
),
|
|
328
|
-
)
|
|
383
|
+
return rpcError(request, error)
|
|
329
384
|
}
|
|
330
385
|
})
|
|
331
386
|
|
|
@@ -346,8 +401,12 @@ export declare namespace feePayer {
|
|
|
346
401
|
onRequest?: (request: RpcRequest.RpcRequest) => Promise<void>
|
|
347
402
|
/** Path to use for the handler. */
|
|
348
403
|
path?: string | undefined
|
|
404
|
+
/** Sponsor display name returned from `eth_fillTransaction`. */
|
|
405
|
+
name?: string | undefined
|
|
349
406
|
/** Transports keyed by chain ID. Defaults to `http()` for each chain. */
|
|
350
407
|
transports?: Record<number, Transport> | undefined
|
|
408
|
+
/** Sponsor URL returned from `eth_fillTransaction`. */
|
|
409
|
+
url?: string | undefined
|
|
351
410
|
}
|
|
352
411
|
}
|
|
353
412
|
|
|
@@ -658,7 +717,7 @@ export declare namespace webAuthn {
|
|
|
658
717
|
/** Maximum age of a challenge in seconds before it expires. @default 300 */
|
|
659
718
|
challengeTtl?: number | undefined
|
|
660
719
|
/** Key-value store for challenges and credentials. */
|
|
661
|
-
kv: Kv
|
|
720
|
+
kv: Kv.Kv
|
|
662
721
|
/** Called after a successful registration. The returned response is merged onto the default JSON response. */
|
|
663
722
|
onRegister?: (parameters: {
|
|
664
723
|
credentialId: string
|
|
@@ -681,6 +740,103 @@ export declare namespace webAuthn {
|
|
|
681
740
|
}
|
|
682
741
|
}
|
|
683
742
|
|
|
743
|
+
/** @internal */
|
|
744
|
+
function resolveChainId(value: unknown) {
|
|
745
|
+
if (typeof value === 'number') return value
|
|
746
|
+
if (typeof value === 'bigint') return Number(value)
|
|
747
|
+
if (typeof value === 'string' && Hex.validate(value)) return Hex.toNumber(value)
|
|
748
|
+
return undefined
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/** @internal */
|
|
752
|
+
function isPreparedFeePayerTransaction(value: Record<string, unknown>) {
|
|
753
|
+
return (
|
|
754
|
+
typeof value.from === 'string' &&
|
|
755
|
+
typeof resolveChainId(value.chainId) === 'number' &&
|
|
756
|
+
typeof value.gas !== 'undefined' &&
|
|
757
|
+
typeof value.nonce !== 'undefined' &&
|
|
758
|
+
(typeof value.maxFeePerGas !== 'undefined' || typeof value.gasPrice !== 'undefined')
|
|
759
|
+
)
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/** @internal */
|
|
763
|
+
function formatFillTransactionRequest(client: Client, value: Record<string, unknown>) {
|
|
764
|
+
const format = client.chain?.formatters?.transactionRequest?.format
|
|
765
|
+
if (!format) return value
|
|
766
|
+
return format({ ...value } as never, 'fillTransaction') as Record<string, unknown>
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/** @internal */
|
|
770
|
+
function normalizeFillTransactionRequest(value: Record<string, unknown>) {
|
|
771
|
+
if (typeof value.to !== 'undefined' || typeof value.data !== 'undefined') return value
|
|
772
|
+
if (!Array.isArray(value.calls) || value.calls.length !== 1) return value
|
|
773
|
+
const [call] = value.calls as Array<Record<string, unknown>>
|
|
774
|
+
const { calls: _, ...rest } = value
|
|
775
|
+
return {
|
|
776
|
+
...rest,
|
|
777
|
+
...(typeof call?.data !== 'undefined' ? { data: call.data } : {}),
|
|
778
|
+
...(typeof call?.to !== 'undefined' ? { to: call.to } : {}),
|
|
779
|
+
...(typeof call?.value !== 'undefined' ? { value: normalizeFillValue(call.value) } : {}),
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/** @internal */
|
|
784
|
+
function normalizeFillValue(value: unknown) {
|
|
785
|
+
if (typeof value !== 'string' || !value.startsWith('0x')) return value
|
|
786
|
+
return BigInt(value === '0x' ? '0x0' : value)
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/** @internal */
|
|
790
|
+
function normalizeTempoTransaction(value: Record<string, unknown> | undefined) {
|
|
791
|
+
if (!value) throw new Error('Expected `tx` in eth_fillTransaction response.')
|
|
792
|
+
return core_Transaction.fromRpc({ type: '0x76', ...value } as core_Transaction.Rpc)!
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/** @internal */
|
|
796
|
+
function rpcError(request: RpcRequest.RpcRequest, error: unknown) {
|
|
797
|
+
if (error instanceof RpcResponse.InvalidParamsError)
|
|
798
|
+
return Response.json(RpcResponse.from({ error }, { request }))
|
|
799
|
+
|
|
800
|
+
if (error instanceof RpcResponse.MethodNotSupportedError)
|
|
801
|
+
return Response.json(RpcResponse.from({ error }, { request }))
|
|
802
|
+
|
|
803
|
+
if ((error as { name?: string | undefined }).name === 'ZodError')
|
|
804
|
+
return Response.json(
|
|
805
|
+
RpcResponse.from(
|
|
806
|
+
{
|
|
807
|
+
error: new RpcResponse.InvalidParamsError({
|
|
808
|
+
message: (error as Error).message,
|
|
809
|
+
}),
|
|
810
|
+
},
|
|
811
|
+
{ request },
|
|
812
|
+
),
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
return Response.json(
|
|
816
|
+
RpcResponse.from(
|
|
817
|
+
{
|
|
818
|
+
error: new RpcResponse.InternalError({
|
|
819
|
+
message: (error as Error).message,
|
|
820
|
+
}),
|
|
821
|
+
},
|
|
822
|
+
{ request },
|
|
823
|
+
),
|
|
824
|
+
)
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/** @internal */
|
|
828
|
+
function rpcResult(request: RpcRequest.RpcRequest, result: unknown) {
|
|
829
|
+
return Response.json(RpcResponse.from({ result }, { request }))
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/** @internal */
|
|
833
|
+
function toSerializedTransaction(value: unknown) {
|
|
834
|
+
if (typeof value === 'string') return value
|
|
835
|
+
if (value && typeof value === 'object' && 'raw' in value && typeof value.raw === 'string')
|
|
836
|
+
return value.raw
|
|
837
|
+
throw new Error('Expected a serialized transaction result.')
|
|
838
|
+
}
|
|
839
|
+
|
|
684
840
|
/** @internal */
|
|
685
841
|
async function mergeResponse(
|
|
686
842
|
json: Record<string, unknown>,
|
package/src/wagmi/Connector.ts
CHANGED
|
@@ -318,10 +318,10 @@ export declare namespace dialog {
|
|
|
318
318
|
* ```
|
|
319
319
|
*/
|
|
320
320
|
export function dangerous_secp256k1(options: dangerous_secp256k1.Options = {}) {
|
|
321
|
-
const { icon, name, rdns, ...rest } = options
|
|
321
|
+
const { icon, name, privateKey, rdns, ...rest } = options
|
|
322
322
|
return setup({
|
|
323
323
|
...rest,
|
|
324
|
-
adapter: dangerous_secp256k1_adapter({ icon, name, rdns }),
|
|
324
|
+
adapter: dangerous_secp256k1_adapter({ icon, name, privateKey, rdns }),
|
|
325
325
|
})
|
|
326
326
|
}
|
|
327
327
|
|