Skip to content

Commit 39050a0

Browse files
rekmarksclaude
andcommitted
Migrate to JsonRpcEngineV2
Update middleware to use the V2 API from @metamask/json-rpc-engine/v2: - Use new middleware signature: async ({ request, context, next }) => result - Return results directly instead of mutating res.result - Use createScaffoldMiddleware from /v2 subpath - Update test infrastructure to use JsonRpcEngineV2.create() Also bump dev dependencies: - @metamask/eth-block-tracker: ^11.0.1 → ^15.0.0 - @metamask/eth-json-rpc-middleware: ^15.0.0 → ^22.0.1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6cd9c68 commit 39050a0

File tree

5 files changed

+315
-128
lines changed

5 files changed

+315
-128
lines changed

index.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const Mutex = require('async-mutex').Mutex
2-
const { createAsyncMiddleware, createScaffoldMiddleware } = require('@metamask/json-rpc-engine')
2+
const { createScaffoldMiddleware } = require('@metamask/json-rpc-engine/v2')
33
const LogFilter = require('./log-filter.js')
44
const BlockFilter = require('./block-filter.js')
55
const TxFilter = require('./tx-filter.js')
@@ -22,10 +22,10 @@ function createEthFilterMiddleware({ blockTracker, provider }) {
2222
eth_newBlockFilter: waitForFree(toFilterCreationMiddleware(newBlockFilter)),
2323
eth_newPendingTransactionFilter: waitForFree(toFilterCreationMiddleware(newPendingTransactionFilter)),
2424
// uninstall filters
25-
eth_uninstallFilter: waitForFree(toAsyncRpcMiddleware(uninstallFilterHandler)),
25+
eth_uninstallFilter: waitForFree(toRpcMiddleware(uninstallFilterHandler)),
2626
// checking filter changes
27-
eth_getFilterChanges: waitForFree(toAsyncRpcMiddleware(getFilterChanges)),
28-
eth_getFilterLogs: waitForFree(toAsyncRpcMiddleware(getFilterLogs)),
27+
eth_getFilterChanges: waitForFree(toRpcMiddleware(getFilterChanges)),
28+
eth_getFilterLogs: waitForFree(toRpcMiddleware(getFilterLogs)),
2929
})
3030

3131
// setup filter updating and destroy handler
@@ -72,19 +72,19 @@ function createEthFilterMiddleware({ blockTracker, provider }) {
7272

7373
async function newLogFilter(params) {
7474
const filter = new LogFilter({ provider, params })
75-
const filterIndex = await installFilter(filter)
75+
await installFilter(filter)
7676
return filter
7777
}
7878

7979
async function newBlockFilter() {
8080
const filter = new BlockFilter({ provider })
81-
const filterIndex = await installFilter(filter)
81+
await installFilter(filter)
8282
return filter
8383
}
8484

8585
async function newPendingTransactionFilter() {
8686
const filter = new TxFilter({ provider })
87-
const filterIndex = await installFilter(filter)
87+
await installFilter(filter)
8888
return filter
8989
}
9090

@@ -185,30 +185,30 @@ function createEthFilterMiddleware({ blockTracker, provider }) {
185185

186186
// helper for turning filter constructors into rpc middleware
187187
function toFilterCreationMiddleware(createFilterFn) {
188-
return toAsyncRpcMiddleware(async (...args) => {
188+
return toRpcMiddleware(async (...args) => {
189189
const filter = await createFilterFn(...args)
190190
const result = intToHex(filter.id)
191191
return result
192192
})
193193
}
194194

195-
// helper for pulling out req.params and setting res.result
196-
function toAsyncRpcMiddleware(asyncFn) {
197-
return createAsyncMiddleware(async (req, res) => {
198-
const result = await asyncFn.apply(null, req.params)
199-
res.result = result
200-
})
195+
// helper for pulling out request.params and returning result (V2 middleware)
196+
function toRpcMiddleware(asyncFn) {
197+
return async ({ request }) => {
198+
const result = await asyncFn.apply(null, request.params)
199+
return result
200+
}
201201
}
202202

203203
function mutexMiddlewareWrapper({ mutex }) {
204204
return (middleware) => {
205-
return async (req, res, next, end) => {
205+
return async (args) => {
206206
// wait for mutex available
207207
// we can release immediately because
208208
// we just need to make sure updates aren't active
209209
const releaseLock = await mutex.acquire()
210210
releaseLock()
211-
middleware(req, res, next, end)
211+
return middleware(args)
212212
}
213213
}
214214
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@
2020
],
2121
"dependencies": {
2222
"@metamask/eth-query": "^4.0.0",
23-
"@metamask/json-rpc-engine": "^10.0.0",
23+
"@metamask/json-rpc-engine": "^10.2.0",
2424
"@metamask/safe-event-emitter": "^3.0.0",
2525
"async-mutex": "^0.5.0",
2626
"pify": "^5.0.0"
2727
},
2828
"devDependencies": {
2929
"@lavamoat/allow-scripts": "^2.5.1",
3030
"@metamask/auto-changelog": "^3.3.0",
31-
"@metamask/eth-json-rpc-middleware": "^15.0.0",
32-
"@metamask/eth-block-tracker": "^11.0.1",
31+
"@metamask/eth-block-tracker": "^15.0.0",
32+
"@metamask/eth-json-rpc-middleware": "^22.0.1",
3333
"ganache": "^7.9.2",
3434
"sinon": "^15.2.0",
3535
"tape": "^5.7.0"

subscriptionManager.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const SafeEventEmitter = require('@metamask/safe-event-emitter').default
2-
const { createAsyncMiddleware, createScaffoldMiddleware } = require('@metamask/json-rpc-engine')
2+
const { createScaffoldMiddleware } = require('@metamask/json-rpc-engine/v2')
33
const createFilterMiddleware = require('./index.js')
44
const { unsafeRandomBytes, incrementHexInt } = require('./hexUtils.js')
55
const getBlocksForRange = require('./getBlocksForRange.js')
@@ -18,19 +18,19 @@ function createSubscriptionMiddleware({ blockTracker, provider }) {
1818
// create subscriptionManager api object
1919
const events = new SafeEventEmitter()
2020
const middleware = createScaffoldMiddleware({
21-
eth_subscribe: createAsyncMiddleware(subscribe),
22-
eth_unsubscribe: createAsyncMiddleware(unsubscribe),
21+
eth_subscribe: subscribe,
22+
eth_unsubscribe: unsubscribe,
2323
})
2424
middleware.destroy = destroy
2525
return { events, middleware }
2626

27-
async function subscribe(req, res) {
27+
async function subscribe({ request }) {
2828

2929
if (isDestroyed) throw new Error(
3030
'SubscriptionManager - attempting to use after destroying'
3131
)
3232

33-
const subscriptionType = req.params[0]
33+
const subscriptionType = request.params[0]
3434
// subId is 16 byte hex string
3535
const subId = unsafeRandomBytes(16)
3636

@@ -41,7 +41,7 @@ function createSubscriptionMiddleware({ blockTracker, provider }) {
4141
sub = createSubNewHeads({ subId })
4242
break
4343
case 'logs':
44-
const filterParams = req.params[1]
44+
const filterParams = request.params[1]
4545
const filter = await filterManager.newLogFilter(filterParams)
4646
sub = createSubFromFilter({ subId, filter })
4747
break
@@ -51,8 +51,7 @@ function createSubscriptionMiddleware({ blockTracker, provider }) {
5151
}
5252
subscriptions[subId] = sub
5353

54-
res.result = subId
55-
return
54+
return subId
5655

5756
function createSubNewHeads({ subId }) {
5857
const sub = {
@@ -88,23 +87,22 @@ function createSubscriptionMiddleware({ blockTracker, provider }) {
8887
}
8988
}
9089

91-
async function unsubscribe(req, res) {
90+
async function unsubscribe({ request }) {
9291

9392
if (isDestroyed) throw new Error(
9493
'SubscriptionManager - attempting to use after destroying'
9594
)
9695

97-
const id = req.params[0]
96+
const id = request.params[0]
9897
const subscription = subscriptions[id]
9998
// if missing, return "false" to indicate it was not removed
10099
if (!subscription) {
101-
res.result = false
102-
return
100+
return false
103101
}
104102
// cleanup subscription
105103
delete subscriptions[id]
106104
await subscription.destroy()
107-
res.result = true
105+
return true
108106
}
109107

110108
function _emitSubscriptionResult(filterIdHex, value) {

test/util.js

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
const EventEmitter = require('events')
22
const { PollingBlockTracker } = require('@metamask/eth-block-tracker')
3-
const { JsonRpcEngine } = require('@metamask/json-rpc-engine')
4-
const { providerAsMiddleware } = require('@metamask/eth-json-rpc-middleware')
5-
const { providerFromEngine } = require('@metamask/eth-json-rpc-provider')
3+
const { JsonRpcEngineV2 } = require('@metamask/json-rpc-engine/v2')
4+
const { providerAsMiddlewareV2 } = require('@metamask/eth-json-rpc-middleware')
5+
const { InternalProvider } = require('@metamask/eth-json-rpc-provider')
66
const Ganache = require('ganache')
77
const createFilterMiddleware = require('../index.js')
88
const createSubscriptionMiddleware = require('../subscriptionManager.js')
@@ -20,28 +20,42 @@ module.exports = {
2020
function createTestSetup() {
2121
// raw data source
2222
const { ganacheProvider, forceNextBlock } = createEngineFromGanache()
23-
// create block trackerfilterId
23+
// create block tracker
2424
const blockTracker = new PollingBlockTracker({
2525
provider: ganacheProvider,
2626
pollingInterval: 200,
2727
})
28-
// create higher level
29-
const engine = new JsonRpcEngine()
30-
const provider = providerFromEngine(engine)
31-
const request = provider.request.bind(provider);
32-
// add filter middleware
33-
engine.push(createFilterMiddleware({ blockTracker, provider }))
34-
// add subscription middleware
35-
const subscriptionManager = createSubscriptionMiddleware({ blockTracker, provider })
36-
engine.push(subscriptionManager.middleware)
37-
subscriptionManager.events.on('notification', (message) => engine.emit('notification', message))
38-
// add data source
39-
engine.push(providerAsMiddleware(ganacheProvider))
28+
29+
// create filter and subscription middleware
30+
// these use ganacheProvider directly for data queries
31+
const filterMiddleware = createFilterMiddleware({ blockTracker, provider: ganacheProvider })
32+
const subscriptionManager = createSubscriptionMiddleware({ blockTracker, provider: ganacheProvider })
33+
34+
// create engine with all middleware
35+
const engine = JsonRpcEngineV2.create({
36+
middleware: [
37+
filterMiddleware,
38+
subscriptionManager.middleware,
39+
providerAsMiddlewareV2(ganacheProvider),
40+
]
41+
})
42+
43+
// create provider from engine with event support
44+
const internalProvider = new InternalProvider({ engine })
45+
const provider = Object.assign(new EventEmitter(), {
46+
request: internalProvider.request.bind(internalProvider)
47+
})
48+
49+
// forward subscription notifications
50+
subscriptionManager.events.on('notification', (message) => {
51+
provider.emit('notification', message)
52+
provider.emit('data', null, message)
53+
})
4054

4155
// subs helper
4256
const subs = createSubsHelper({ provider })
4357

44-
return { ganacheProvider, forceNextBlock, engine, provider, request, subs, blockTracker, trackNextBlock }
58+
return { ganacheProvider, forceNextBlock, provider, request: provider.request, subs, blockTracker, trackNextBlock }
4559

4660
async function trackNextBlock() {
4761
return new Promise((resolve) => blockTracker.once('latest', resolve))
@@ -102,9 +116,10 @@ function createEngineFromGanache () {
102116
}
103117

104118
function createEngineFromTestBlockMiddleware() {
105-
const engine = new JsonRpcEngine()
106119
const testBlockSource = new TestBlockMiddleware()
107-
engine.push(testBlockSource.createMiddleware())
120+
const engine = JsonRpcEngineV2.create({
121+
middleware: [testBlockSource.createMiddleware()]
122+
})
108123
return { engine, testBlockSource }
109124
}
110125

0 commit comments

Comments
 (0)