accounts 0.17.0 → 0.17.2
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/cli/Provider.d.ts.map +1 -1
- package/dist/cli/Provider.js +3 -1
- package/dist/cli/Provider.js.map +1 -1
- package/dist/cli/adapter.d.ts.map +1 -1
- package/dist/cli/adapter.js +2 -26
- package/dist/cli/adapter.js.map +1 -1
- package/dist/cli/storage.js +3 -2
- package/dist/cli/storage.js.map +1 -1
- package/dist/core/Provider.d.ts.map +1 -1
- package/dist/core/Provider.js +4 -2
- package/dist/core/Provider.js.map +1 -1
- package/dist/core/Schema.d.ts +8 -0
- package/dist/core/Schema.d.ts.map +1 -1
- package/dist/core/adapters/internal/fromRequest.d.ts.map +1 -1
- package/dist/core/adapters/internal/fromRequest.js +2 -1
- package/dist/core/adapters/internal/fromRequest.js.map +1 -1
- package/dist/core/internal/withDedupe.d.ts +3 -2
- package/dist/core/internal/withDedupe.d.ts.map +1 -1
- package/dist/core/internal/withDedupe.js +6 -5
- package/dist/core/internal/withDedupe.js.map +1 -1
- package/dist/core/zod/rpc.d.ts +5 -603
- package/dist/core/zod/rpc.d.ts.map +1 -1
- package/dist/core/zod/rpc.js +1 -0
- package/dist/core/zod/rpc.js.map +1 -1
- package/dist/server/internal/handlers/auth.d.ts +0 -20
- package/dist/server/internal/handlers/auth.d.ts.map +1 -1
- package/dist/server/internal/handlers/oidcProvider.d.ts +0 -7
- package/dist/server/internal/handlers/oidcProvider.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cli/Provider.localnet.test.ts +124 -9
- package/src/cli/Provider.ts +4 -0
- package/src/cli/adapter.ts +3 -27
- package/src/cli/storage.test.ts +20 -1
- package/src/cli/storage.ts +2 -2
- package/src/core/Provider.localnet.test.ts +24 -18
- package/src/core/Provider.test.ts +48 -0
- package/src/core/Provider.ts +4 -2
- package/src/core/adapters/internal/fromRequest.ts +2 -1
- package/src/core/internal/withDedupe.test.ts +17 -0
- package/src/core/internal/withDedupe.ts +7 -5
- package/src/core/zod/rpc.ts +1 -0
|
@@ -23,7 +23,7 @@ import { Account as TempoAccount, Actions, Addresses, Transaction } from 'viem/t
|
|
|
23
23
|
import { tempo, tempoModerato } from 'viem/tempo/chains'
|
|
24
24
|
import { afterAll, beforeAll, describe, expect, test } from 'vp/test'
|
|
25
25
|
|
|
26
|
-
import { headlessWebAuthn, secp256k1 } from '../../test/adapters.js'
|
|
26
|
+
import { cli, headlessWebAuthn, secp256k1 } from '../../test/adapters.js'
|
|
27
27
|
import { accounts, chain, getClient, http } from '../../test/config.js'
|
|
28
28
|
import { createJsonStorage, createServer, type Server } from '../../test/utils.js'
|
|
29
29
|
import * as Handler from '../server/Handler.js'
|
|
@@ -34,7 +34,11 @@ import * as Keystore from './Keystore.js'
|
|
|
34
34
|
import * as Provider from './Provider.js'
|
|
35
35
|
import * as Storage from './Storage.js'
|
|
36
36
|
|
|
37
|
+
beforeAll(cli.setup)
|
|
38
|
+
afterAll(cli.teardown)
|
|
39
|
+
|
|
37
40
|
const adapters = [
|
|
41
|
+
{ name: 'cli', adapter: cli },
|
|
38
42
|
{ name: 'headlessWebAuthn', adapter: headlessWebAuthn },
|
|
39
43
|
{ name: 'secp256k1', adapter: secp256k1 },
|
|
40
44
|
] as const
|
|
@@ -856,7 +860,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
856
860
|
|
|
857
861
|
test('behavior: provider mints identity when configured with an issuer', async () => {
|
|
858
862
|
const provider = Provider.create({
|
|
859
|
-
adapter: adapter(),
|
|
863
|
+
adapter: adapter({ identity: { audience: 'https://app.example.com', issuer } }),
|
|
860
864
|
identity: { audience: 'https://app.example.com', issuer },
|
|
861
865
|
})
|
|
862
866
|
|
|
@@ -889,7 +893,9 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
889
893
|
|
|
890
894
|
test('behavior: provider identity mint is best-effort (failure omits the claim)', async () => {
|
|
891
895
|
const provider = Provider.create({
|
|
892
|
-
adapter: adapter(
|
|
896
|
+
adapter: adapter({
|
|
897
|
+
identity: { audience: 'https://app.example.com', issuer: `${server.url}/nowhere` },
|
|
898
|
+
}),
|
|
893
899
|
identity: { audience: 'https://app.example.com', issuer: `${server.url}/nowhere` },
|
|
894
900
|
})
|
|
895
901
|
|
|
@@ -904,7 +910,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
904
910
|
|
|
905
911
|
test('behavior: provider identity is not minted unless requested', async () => {
|
|
906
912
|
const provider = Provider.create({
|
|
907
|
-
adapter: adapter(),
|
|
913
|
+
adapter: adapter({ identity: { audience: 'https://app.example.com', issuer } }),
|
|
908
914
|
identity: { audience: 'https://app.example.com', issuer },
|
|
909
915
|
})
|
|
910
916
|
|
|
@@ -1564,7 +1570,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
1564
1570
|
|
|
1565
1571
|
test('behavior: includes feePayer when configured', async () => {
|
|
1566
1572
|
const provider = Provider.create({
|
|
1567
|
-
adapter: adapter(),
|
|
1573
|
+
adapter: adapter({ feePayer: 'https://fee-payer.example.com' }),
|
|
1568
1574
|
feePayer: 'https://fee-payer.example.com',
|
|
1569
1575
|
})
|
|
1570
1576
|
|
|
@@ -1783,7 +1789,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
1783
1789
|
const storage = Storage.memory({ key: 'persist-invalid' })
|
|
1784
1790
|
storage.setItem('store', {
|
|
1785
1791
|
state: {
|
|
1786
|
-
accounts: [{ address: '
|
|
1792
|
+
accounts: [{ address: 'invalid' }],
|
|
1787
1793
|
activeAccount: 0,
|
|
1788
1794
|
chainId: chain.id,
|
|
1789
1795
|
},
|
|
@@ -3228,7 +3234,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3228
3234
|
|
|
3229
3235
|
test('behavior: feePayer: true uses default from Provider.create', async () => {
|
|
3230
3236
|
const provider = Provider.create({
|
|
3231
|
-
adapter: adapter(),
|
|
3237
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3232
3238
|
chains: [chain],
|
|
3233
3239
|
feePayer: server.url,
|
|
3234
3240
|
})
|
|
@@ -3251,7 +3257,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3251
3257
|
|
|
3252
3258
|
test('behavior: feePayer: true on eth_sendTransactionSync', async () => {
|
|
3253
3259
|
const provider = Provider.create({
|
|
3254
|
-
adapter: adapter(),
|
|
3260
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3255
3261
|
chains: [chain],
|
|
3256
3262
|
feePayer: server.url,
|
|
3257
3263
|
})
|
|
@@ -3293,7 +3299,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3293
3299
|
|
|
3294
3300
|
test('behavior: precedence fee-payer-first (default) on eth_sendTransaction', async () => {
|
|
3295
3301
|
const provider = Provider.create({
|
|
3296
|
-
adapter: adapter(),
|
|
3302
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3297
3303
|
chains: [chain],
|
|
3298
3304
|
feePayer: server.url,
|
|
3299
3305
|
})
|
|
@@ -3314,7 +3320,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3314
3320
|
|
|
3315
3321
|
test('behavior: precedence fee-payer-first (default) on eth_sendTransactionSync', async () => {
|
|
3316
3322
|
const provider = Provider.create({
|
|
3317
|
-
adapter: adapter(),
|
|
3323
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3318
3324
|
chains: [chain],
|
|
3319
3325
|
feePayer: server.url,
|
|
3320
3326
|
})
|
|
@@ -3337,7 +3343,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3337
3343
|
|
|
3338
3344
|
test('behavior: precedence user-first on eth_sendTransaction', async () => {
|
|
3339
3345
|
const provider = Provider.create({
|
|
3340
|
-
adapter: adapter(),
|
|
3346
|
+
adapter: adapter({ feePayer: { url: server.url, precedence: 'user-first' } }),
|
|
3341
3347
|
chains: [chain],
|
|
3342
3348
|
feePayer: { url: server.url, precedence: 'user-first' },
|
|
3343
3349
|
})
|
|
@@ -3358,7 +3364,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3358
3364
|
|
|
3359
3365
|
test('behavior: precedence user-first on eth_sendTransactionSync', async () => {
|
|
3360
3366
|
const provider = Provider.create({
|
|
3361
|
-
adapter: adapter(),
|
|
3367
|
+
adapter: adapter({ feePayer: { url: server.url, precedence: 'user-first' } }),
|
|
3362
3368
|
chains: [chain],
|
|
3363
3369
|
feePayer: { url: server.url, precedence: 'user-first' },
|
|
3364
3370
|
})
|
|
@@ -3381,7 +3387,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3381
3387
|
|
|
3382
3388
|
test('behavior: precedence user-first on eth_signTransaction', async () => {
|
|
3383
3389
|
const provider = Provider.create({
|
|
3384
|
-
adapter: adapter(),
|
|
3390
|
+
adapter: adapter({ feePayer: { url: server.url, precedence: 'user-first' } }),
|
|
3385
3391
|
chains: [chain],
|
|
3386
3392
|
feePayer: { url: server.url, precedence: 'user-first' },
|
|
3387
3393
|
})
|
|
@@ -3399,7 +3405,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3399
3405
|
|
|
3400
3406
|
test('behavior: feePayer: false opts out on eth_sendTransaction', async () => {
|
|
3401
3407
|
const provider = Provider.create({
|
|
3402
|
-
adapter: adapter(),
|
|
3408
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3403
3409
|
chains: [chain],
|
|
3404
3410
|
feePayer: server.url,
|
|
3405
3411
|
})
|
|
@@ -3422,7 +3428,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3422
3428
|
|
|
3423
3429
|
test('behavior: feePayer: false opts out on eth_sendTransactionSync', async () => {
|
|
3424
3430
|
const provider = Provider.create({
|
|
3425
|
-
adapter: adapter(),
|
|
3431
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3426
3432
|
chains: [chain],
|
|
3427
3433
|
feePayer: server.url,
|
|
3428
3434
|
})
|
|
@@ -3445,7 +3451,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3445
3451
|
|
|
3446
3452
|
test('behavior: feePayer: false opts out on eth_signTransaction', async () => {
|
|
3447
3453
|
const provider = Provider.create({
|
|
3448
|
-
adapter: adapter(),
|
|
3454
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3449
3455
|
chains: [chain],
|
|
3450
3456
|
feePayer: server.url,
|
|
3451
3457
|
})
|
|
@@ -3488,7 +3494,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3488
3494
|
|
|
3489
3495
|
test('behavior: wallet_sendCalls with feePayer: true uses provider default', async () => {
|
|
3490
3496
|
const provider = Provider.create({
|
|
3491
|
-
adapter: adapter(),
|
|
3497
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3492
3498
|
chains: [chain],
|
|
3493
3499
|
feePayer: server.url,
|
|
3494
3500
|
})
|
|
@@ -3517,7 +3523,7 @@ describe.each(adapters)('$name', ({ adapter, name }: (typeof adapters)[number])
|
|
|
3517
3523
|
|
|
3518
3524
|
test('behavior: wallet_sendCalls with feePayer: false opts out', async () => {
|
|
3519
3525
|
const provider = Provider.create({
|
|
3520
|
-
adapter: adapter(),
|
|
3526
|
+
adapter: adapter({ feePayer: server.url }),
|
|
3521
3527
|
chains: [chain],
|
|
3522
3528
|
feePayer: server.url,
|
|
3523
3529
|
})
|
|
@@ -11,6 +11,54 @@ import * as Storage from './Storage.js'
|
|
|
11
11
|
|
|
12
12
|
const address = '0x0000000000000000000000000000000000000001'
|
|
13
13
|
|
|
14
|
+
describe('eth_fillTransaction', () => {
|
|
15
|
+
test('behavior: forwards Tempo-formatted request capabilities', async () => {
|
|
16
|
+
const capabilities: unknown[] = []
|
|
17
|
+
const request = tempo.formatters.transactionRequest.format(
|
|
18
|
+
{
|
|
19
|
+
capabilities: { balanceDiffs: false, errors: true },
|
|
20
|
+
from: address,
|
|
21
|
+
to: address,
|
|
22
|
+
type: 'tempo',
|
|
23
|
+
},
|
|
24
|
+
'fillTransaction',
|
|
25
|
+
)
|
|
26
|
+
const provider = Provider.create({
|
|
27
|
+
chains: [tempo],
|
|
28
|
+
storage: Storage.memory(),
|
|
29
|
+
transports: {
|
|
30
|
+
[tempo.id]: custom(
|
|
31
|
+
{
|
|
32
|
+
async request(request) {
|
|
33
|
+
if (request.method === 'eth_fillTransaction')
|
|
34
|
+
capabilities.push(
|
|
35
|
+
(request.params?.[0] as { capabilities?: unknown } | undefined)?.capabilities,
|
|
36
|
+
)
|
|
37
|
+
throw new Error('capture complete')
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{ retryCount: 0 },
|
|
41
|
+
),
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
await expect(
|
|
46
|
+
provider.request({
|
|
47
|
+
method: 'eth_fillTransaction',
|
|
48
|
+
params: [request as never],
|
|
49
|
+
}),
|
|
50
|
+
).rejects.toThrow('capture complete')
|
|
51
|
+
expect(capabilities).toMatchInlineSnapshot(`
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
"balanceDiffs": false,
|
|
55
|
+
"errors": true,
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
`)
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
14
62
|
describe('getMppxParameters', () => {
|
|
15
63
|
test('error: rejects unsupported chain IDs', () => {
|
|
16
64
|
const provider = Provider.create({ storage: Storage.memory() })
|
package/src/core/Provider.ts
CHANGED
|
@@ -176,6 +176,7 @@ export function create(options: create.Options = {}): create.ReturnType {
|
|
|
176
176
|
Object.assign(keystores, keystores_configured ?? Keystore.defaults)
|
|
177
177
|
|
|
178
178
|
const emitter = ox_Provider.createEmitter()
|
|
179
|
+
const requestCache = new Map<string, Promise<unknown>>()
|
|
179
180
|
|
|
180
181
|
// Emit EIP-1193 events on state changes.
|
|
181
182
|
store.subscribe(
|
|
@@ -573,7 +574,7 @@ export function create(options: create.Options = {}): create.ReturnType {
|
|
|
573
574
|
})
|
|
574
575
|
} else {
|
|
575
576
|
try {
|
|
576
|
-
await Actions.accessKey.
|
|
577
|
+
await Actions.accessKey.revokeSync(getClient(), {
|
|
577
578
|
account: selected.account as TempoAccount.Account,
|
|
578
579
|
accessKey: parameters.accessKeyAddress,
|
|
579
580
|
})
|
|
@@ -1157,7 +1158,7 @@ export function create(options: create.Options = {}): create.ReturnType {
|
|
|
1157
1158
|
calls,
|
|
1158
1159
|
chainId,
|
|
1159
1160
|
from: from_,
|
|
1160
|
-
...(feePayer ? { feePayer } : {}),
|
|
1161
|
+
...(feePayer !== undefined ? { feePayer } : {}),
|
|
1161
1162
|
}
|
|
1162
1163
|
if (!sync) {
|
|
1163
1164
|
const hash = await sendTransactionAction(txRequest, {
|
|
@@ -1783,6 +1784,7 @@ export function create(options: create.Options = {}): create.ReturnType {
|
|
|
1783
1784
|
return result
|
|
1784
1785
|
},
|
|
1785
1786
|
{
|
|
1787
|
+
cache: requestCache,
|
|
1786
1788
|
enabled: shouldDedupe,
|
|
1787
1789
|
id: Json.stringify({ method, params }),
|
|
1788
1790
|
},
|
|
@@ -5,6 +5,7 @@ import { z } from 'zod/mini'
|
|
|
5
5
|
import * as Adapter from '../../Adapter.js'
|
|
6
6
|
import type * as Keystore from '../../Keystore.js'
|
|
7
7
|
import * as Rpc from '../../zod/rpc.js'
|
|
8
|
+
import * as u from '../../zod/utils.js'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Builds an adapter that forwards wallet RPC to a remote wallet through a
|
|
@@ -29,7 +30,7 @@ export function fromRequest(options: fromRequest.Options): Adapter.Adapter {
|
|
|
29
30
|
} = options
|
|
30
31
|
|
|
31
32
|
return Adapter.define(
|
|
32
|
-
{ ...(icon ? { icon } : {}), name, rdns },
|
|
33
|
+
{ ...(icon ? { icon } : {}), name, rdns, schema: z.object({ address: u.address() }) },
|
|
33
34
|
({ getAccount, getClient, store }) => {
|
|
34
35
|
// Late-bind the store so the request channel can reconcile local
|
|
35
36
|
// connection state (e.g. a wallet `accountsChanged` notification).
|
|
@@ -41,6 +41,23 @@ describe('withDedupe', () => {
|
|
|
41
41
|
expect(b).toMatchInlineSnapshot(`2`)
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
+
test('behavior: separate caches execute independently', async () => {
|
|
45
|
+
let calls = 0
|
|
46
|
+
const fn = () => Promise.resolve(++calls)
|
|
47
|
+
|
|
48
|
+
const [a, b] = await Promise.all([
|
|
49
|
+
withDedupe(fn, { cache: new Map(), id: 'same' }),
|
|
50
|
+
withDedupe(fn, { cache: new Map(), id: 'same' }),
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
expect([a, b]).toMatchInlineSnapshot(`
|
|
54
|
+
[
|
|
55
|
+
1,
|
|
56
|
+
2,
|
|
57
|
+
]
|
|
58
|
+
`)
|
|
59
|
+
})
|
|
60
|
+
|
|
44
61
|
test('behavior: cache is cleared after promise resolves', async () => {
|
|
45
62
|
const fn = () => Promise.resolve('ok')
|
|
46
63
|
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
/** Deduplicates in-flight promises by key. */
|
|
2
2
|
export function withDedupe<data>(
|
|
3
3
|
fn: () => Promise<data>,
|
|
4
|
-
{ enabled = true, id }: withDedupe.Options,
|
|
4
|
+
{ cache = withDedupe.cache, enabled = true, id }: withDedupe.Options,
|
|
5
5
|
): Promise<data> {
|
|
6
6
|
if (!enabled || !id) return fn()
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const cached = cache.get(id)
|
|
8
|
+
if (cached) return cached as Promise<data>
|
|
9
|
+
const promise = fn().finally(() => cache.delete(id))
|
|
10
|
+
cache.set(id, promise)
|
|
10
11
|
return promise
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export declare namespace withDedupe {
|
|
14
15
|
type Options = {
|
|
16
|
+
cache?: Map<string, Promise<unknown>> | undefined
|
|
15
17
|
enabled?: boolean | undefined
|
|
16
18
|
id?: string | undefined
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
withDedupe.cache = new Map<string, Promise<
|
|
22
|
+
withDedupe.cache = new Map<string, Promise<unknown>>()
|
package/src/core/zod/rpc.ts
CHANGED
|
@@ -171,6 +171,7 @@ export const transactionRequest = z.object({
|
|
|
171
171
|
z.array(z.object({ address: u.address(), storageKeys: z.array(u.hex()) })),
|
|
172
172
|
),
|
|
173
173
|
calls: z.optional(z.readonly(z.array(call))),
|
|
174
|
+
capabilities: z.optional(z.record(z.string(), z.unknown())),
|
|
174
175
|
chainId: z.optional(u.number()),
|
|
175
176
|
data: z.optional(u.hex()),
|
|
176
177
|
feePayer: z.optional(z.union([z.boolean(), z.string()])),
|