@0xsequence/network
Advanced tools
Comparing version 0.0.0-20240812142652 to 0.0.0-20240814043648
@@ -6,4 +6,4 @@ 'use strict'; | ||
var constants_dist_0xsequenceNetworkConstants = require('../constants/dist/0xsequence-network-constants.cjs.dev.js'); | ||
var ethers = require('ethers'); | ||
var utils = require('@0xsequence/utils'); | ||
var ethers = require('ethers'); | ||
@@ -35,3 +35,3 @@ function _extends() { | ||
} | ||
return Number(chainId); | ||
return ethers.ethers.BigNumber.from(chainId).toNumber(); | ||
}; | ||
@@ -143,3 +143,3 @@ const maybeChainId = chainId => { | ||
if (chainId.startsWith('0x')) { | ||
const id = Number(chainId); | ||
const id = ethers.ethers.BigNumber.from(chainId).toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -153,4 +153,4 @@ } else { | ||
return networks.find(n => n.chainId === chainId.chainId); | ||
} else if (typeof chainId === 'bigint') { | ||
const id = Number(chainId); | ||
} else if (ethers.ethers.BigNumber.isBigNumber(chainId)) { | ||
const id = chainId.toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -224,9 +224,9 @@ } else { | ||
function toChainIdNumber(chainIdLike) { | ||
if (typeof chainIdLike === 'bigint') { | ||
if (ethers.ethers.BigNumber.isBigNumber(chainIdLike)) { | ||
return chainIdLike; | ||
} | ||
if (utils.isBigNumberish(chainIdLike)) { | ||
return BigInt(chainIdLike); | ||
return ethers.ethers.BigNumber.from(chainIdLike); | ||
} | ||
return BigInt(chainIdLike.chainId); | ||
return ethers.ethers.BigNumber.from(chainIdLike.chainId); | ||
} | ||
@@ -278,2 +278,6 @@ const createNetworkConfig = (chainId, options) => { | ||
const JsonRpcVersion = '2.0'; | ||
// EIP-1193 function signature | ||
class JsonRpcRouter { | ||
@@ -289,6 +293,10 @@ constructor(middlewares, sender) { | ||
setMiddleware(middlewares) { | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender); | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender.sendAsync); | ||
} | ||
request(request) { | ||
return this.handler.request(request); | ||
sendAsync(request, callback, chainId) { | ||
try { | ||
this.handler(request, callback, chainId); | ||
} catch (err) { | ||
callback(err, undefined); | ||
} | ||
} | ||
@@ -299,4 +307,4 @@ } | ||
const toMiddleware = v => { | ||
if (v.requestHandler) { | ||
return v.requestHandler; | ||
if (v.sendAsyncMiddleware) { | ||
return v.sendAsyncMiddleware; | ||
} else { | ||
@@ -307,49 +315,80 @@ return v; | ||
let chain; | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler.request); | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler); | ||
for (let i = middlewares.length - 2; i >= 0; i--) { | ||
chain = toMiddleware(middlewares[i])(chain); | ||
} | ||
return { | ||
request: chain | ||
}; | ||
return chain; | ||
}; | ||
// TODOXXX: review.. | ||
function isJsonRpcProvider(cand) { | ||
return cand !== undefined && cand.send !== undefined && cand.constructor.defaultUrl !== undefined && cand.detectNetwork !== undefined && cand.getSigner !== undefined && cand.perform !== undefined; | ||
} | ||
function isJsonRpcSender(cand) { | ||
return cand !== undefined && cand.send !== undefined; | ||
function isJsonRpcHandler(cand) { | ||
return cand !== undefined && cand.sendAsync !== undefined; | ||
} | ||
class JsonRpcHandler { | ||
let _nextId = 0; | ||
class JsonRpcSender { | ||
constructor(provider, defaultChainId) { | ||
this.provider = void 0; | ||
this.send = void 0; | ||
this.request = void 0; | ||
this.defaultChainId = void 0; | ||
this.request = request => { | ||
if (!request.chainId) { | ||
request.chainId = this.defaultChainId; | ||
} | ||
return this.provider(request); | ||
this.sendAsync = (request, callback, chainId) => { | ||
this.send(request.method, request.params, chainId || this.defaultChainId).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
if (isJsonRpcSender(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params, request.chainId); | ||
this.defaultChainId = defaultChainId; | ||
if (isJsonRpcProvider(provider)) { | ||
// we can ignore defaultChainId for JsonRpcProviders as they are already chain-bound | ||
this.send = provider.send.bind(provider); | ||
} else if (isJsonRpcHandler(provider)) { | ||
this.send = (method, params, chainId) => { | ||
return new Promise((resolve, reject) => { | ||
provider.sendAsync({ | ||
// TODO: really shouldn't have to set these here? | ||
jsonrpc: JsonRpcVersion, | ||
id: ++_nextId, | ||
method, | ||
params | ||
}, (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else if (response) { | ||
resolve(response.result); | ||
} else { | ||
resolve(undefined); | ||
} | ||
}, chainId || this.defaultChainId); | ||
}); | ||
}; | ||
} else if (isJsonRpcProvider(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params || []); | ||
}; | ||
} else { | ||
this.provider = provider; | ||
this.send = provider; | ||
} | ||
this.defaultChainId = defaultChainId; | ||
this.request = (request, chainId) => { | ||
return this.send(request.method, request.params, chainId); | ||
}; | ||
} | ||
send(method, params, chainId) { | ||
const request = { | ||
method, | ||
params, | ||
chainId | ||
} | ||
class JsonRpcExternalProvider { | ||
constructor(provider) { | ||
this.provider = provider; | ||
this.sendAsync = (request, callback) => { | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
return this.request(request); | ||
this.send = this.sendAsync; | ||
} | ||
@@ -360,3 +399,3 @@ } | ||
constructor(isAllowedFunc) { | ||
this.requestHandler = void 0; | ||
this.sendAsyncMiddleware = void 0; | ||
this.isAllowedFunc = void 0; | ||
@@ -368,11 +407,11 @@ if (isAllowedFunc) { | ||
} | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
setIsAllowedFunc(fn) { | ||
this.isAllowedFunc = fn; | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
} | ||
const allowProviderMiddleware = isAllowed => next => { | ||
return request => { | ||
return (request, callback, chainId) => { | ||
// ensure precondition is met or do not allow the request to continue | ||
@@ -384,3 +423,3 @@ if (!isAllowed(request)) { | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -391,3 +430,2 @@ }; | ||
constructor(options) { | ||
var _this = this; | ||
// cachableJsonRpcMethods which can be permanently cached for lifetime | ||
@@ -411,13 +449,15 @@ // of the provider. | ||
this.defaultChainId = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Respond early with cached result | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
const _result = _this.getCacheValue(key); | ||
if (_result && _result !== '') { | ||
return { | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
const result = this.getCacheValue(key); | ||
if (result && result !== '') { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: _result | ||
}; | ||
result: result | ||
}); | ||
return; | ||
} | ||
@@ -427,17 +467,19 @@ } | ||
// Continue down the handler chain | ||
const result = await next(request); | ||
// Store result in cache and continue | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (result && _this.shouldCacheResponse(request, result)) { | ||
// cache the value | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
if (_this.cachableJsonRpcMethods.includes(request.method)) { | ||
_this.setCacheValue(key, result); | ||
} else { | ||
_this.setCacheByBlockValue(key, result); | ||
next(request, (error, response, chainId) => { | ||
// Store result in cache and continue | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (response && response.result && this.shouldCacheResponse(request, response)) { | ||
// cache the value | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
if (this.cachableJsonRpcMethods.includes(request.method)) { | ||
this.setCacheValue(key, response.result); | ||
} else { | ||
this.setCacheByBlockValue(key, response.result); | ||
} | ||
} | ||
} | ||
} | ||
return result; | ||
// Exec next handler | ||
callback(error, response); | ||
}, chainId || this.defaultChainId); | ||
}; | ||
@@ -491,5 +533,5 @@ }; | ||
}; | ||
this.shouldCacheResponse = (request, result) => { | ||
this.shouldCacheResponse = (request, response) => { | ||
// skip if we do not have response result | ||
if (!result) { | ||
if (!response || !response.result) { | ||
return false; | ||
@@ -499,3 +541,3 @@ } | ||
// skip caching eth_getCode where resposne value is '0x' or empty | ||
if (request.method === 'eth_getCode' && result.length <= 2) { | ||
if (request.method === 'eth_getCode' && response.result.length <= 2) { | ||
return false; | ||
@@ -532,29 +574,52 @@ } | ||
constructor(options) { | ||
var _this = this; | ||
this.options = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
switch (request.method) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
if (_this.options.chainId) { | ||
return `${_this.options.chainId}`; | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${this.options.chainId}` | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_chainId': | ||
if (_this.options.chainId) { | ||
return ethers.ethers.toQuantity(_this.options.chainId); | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.ethers.utils.hexlify(this.options.chainId) | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_accounts': | ||
if (_this.options.accountAddress) { | ||
return [ethers.ethers.getAddress(_this.options.accountAddress)]; | ||
if (this.options.accountAddress) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: [ethers.ethers.utils.getAddress(this.options.accountAddress)] | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'sequence_getWalletContext': | ||
if (_this.options.walletContext) { | ||
return _this.options.walletContext; | ||
if (this.options.walletContext) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: this.options.walletContext | ||
}); | ||
return; | ||
} | ||
break; | ||
} | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -567,12 +632,13 @@ }; | ||
const exceptionProviderMiddleware = next => { | ||
return async request => { | ||
try { | ||
return await next(request); | ||
} catch (error) { | ||
if (typeof error === 'string') { | ||
throw new Error(error); | ||
} else { | ||
throw new Error(error.message); | ||
return (request, callback, chainId) => { | ||
next(request, (error, response) => { | ||
if (!error && response && response.error) { | ||
if (typeof response.error === 'string') { | ||
throw new Error(response.error); | ||
} else { | ||
throw new Error(response.error.message); | ||
} | ||
} | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -583,12 +649,13 @@ }; | ||
const loggingProviderMiddleware = next => { | ||
return async request => { | ||
const chainIdLabel = request.chainId ? ` chainId:${request.chainId}` : ''; | ||
return (request, callback, chainId) => { | ||
const chainIdLabel = chainId ? ` chainId:${chainId}` : ''; | ||
utils.logger.info(`[provider request]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params); | ||
try { | ||
const result = await next(request); | ||
utils.logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `result:`, result); | ||
return result; | ||
} catch (error) { | ||
utils.logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} | ||
next(request, (error, response) => { | ||
if (error) { | ||
utils.logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} else { | ||
utils.logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `response:`, response); | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -598,17 +665,27 @@ }; | ||
const networkProviderMiddleware = getChainId => next => { | ||
return async request => { | ||
return (request, callback, chainId) => { | ||
const networkChainId = getChainId(request); | ||
switch (request.method) { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
{ | ||
return `${networkChainId}`; | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${networkChainId}` | ||
}); | ||
return; | ||
case 'eth_chainId': | ||
{ | ||
return ethers.ethers.toQuantity(networkChainId); | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.ethers.utils.hexlify(networkChainId) | ||
}); | ||
return; | ||
} | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -626,11 +703,12 @@ }; | ||
this.provider = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Forward signing requests to the signing provider | ||
if (SignerJsonRpcMethods.includes(request.method)) { | ||
return this.provider.request(request); | ||
this.provider.sendAsync(request, callback, chainId); | ||
return; | ||
} | ||
// Continue to next handler | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -647,7 +725,14 @@ }; | ||
this.rpcUrl = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback) => { | ||
// When provider is configured, send non-private methods to our local public provider | ||
if (this.provider && !this.privateJsonRpcMethods.includes(request.method)) { | ||
return this.provider.send(request.method, request.params || []); | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => callback(e)); | ||
return; | ||
} | ||
@@ -657,3 +742,3 @@ | ||
utils.logger.debug('[public-provider] sending request to signer window', request.method); | ||
return next(request); | ||
next(request, callback); | ||
}; | ||
@@ -676,3 +761,3 @@ }; | ||
// which supports better caching. | ||
this.provider = new ethers.ethers.JsonRpcProvider(rpcUrl); | ||
this.provider = new ethers.providers.JsonRpcProvider(rpcUrl); | ||
} | ||
@@ -684,48 +769,47 @@ } | ||
constructor() { | ||
var _this = this; | ||
this.singleflightJsonRpcMethods = ['eth_chainId', 'net_version', 'eth_call', 'eth_getCode', 'eth_blockNumber', 'eth_getBalance', 'eth_getStorageAt', 'eth_getTransactionCount', 'eth_getBlockTransactionCountByHash', 'eth_getBlockTransactionCountByNumber', 'eth_getUncleCountByBlockHash', 'eth_getUncleCountByBlockNumber', 'eth_getBlockByHash', 'eth_getBlockByNumber', 'eth_getTransactionByHash', 'eth_getTransactionByBlockHashAndIndex', 'eth_getTransactionByBlockNumberAndIndex', 'eth_getTransactionReceipt', 'eth_getUncleByBlockHashAndIndex', 'eth_getUncleByBlockNumberAndIndex', 'eth_getLogs']; | ||
this.inflight = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// continue to next handler if method isn't part of methods list | ||
if (!_this.singleflightJsonRpcMethods.includes(request.method)) { | ||
return next(request); | ||
if (!this.singleflightJsonRpcMethods.includes(request.method)) { | ||
next(request, callback, chainId); | ||
return; | ||
} | ||
const key = _this.requestKey(request.method, request.params || [], request.chainId); | ||
if (!_this.inflight[key]) { | ||
const key = this.requestKey(request.method, request.params || [], chainId); | ||
if (!this.inflight[key]) { | ||
// first request -- init the empty list | ||
_this.inflight[key] = []; | ||
this.inflight[key] = []; | ||
} else { | ||
// already in-flight, add the callback to the list and return | ||
return new Promise((resolve, reject) => { | ||
_this.inflight[key].push({ | ||
id: request.id, | ||
callback: (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(response); | ||
} | ||
} | ||
}); | ||
this.inflight[key].push({ | ||
id: request.id, | ||
callback | ||
}); | ||
return; | ||
} | ||
// Continue down the handler chain | ||
try { | ||
// Exec the handler, and on success resolve all other promises | ||
const response = await next(request); | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(undefined, response)); | ||
return response; | ||
} catch (error) { | ||
// If the request fails, reject all queued promises. | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(error, undefined)); | ||
throw error; | ||
} finally { | ||
delete _this.inflight[key]; | ||
} | ||
next(request, (error, response, chainId) => { | ||
// callback the original request | ||
callback(error, response); | ||
// callback all other requests of the same kind in queue, with the | ||
// same response result as from the first response. | ||
for (let i = 0; i < this.inflight[key].length; i++) { | ||
const sub = this.inflight[key][i]; | ||
if (error) { | ||
sub.callback(error, response); | ||
} else if (response) { | ||
sub.callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: sub.id, | ||
result: response.result | ||
}); | ||
} | ||
} | ||
// clear request key | ||
delete this.inflight[key]; | ||
}, chainId); | ||
}; | ||
@@ -749,84 +833,24 @@ }; | ||
function _classPrivateFieldBase(receiver, privateKey) { | ||
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { | ||
throw new TypeError("attempted to use private field on non-instance"); | ||
} | ||
return receiver; | ||
} | ||
var id = 0; | ||
function _classPrivateFieldKey(name) { | ||
return "__private_" + id++ + "_" + name; | ||
} | ||
var _chainId = /*#__PURE__*/_classPrivateFieldKey("chainId"); | ||
var _nextId = /*#__PURE__*/_classPrivateFieldKey("nextId"); | ||
var _sender = /*#__PURE__*/_classPrivateFieldKey("sender"); | ||
// JsonRpcProvider with a middleware stack. By default it will use a simple caching middleware. | ||
class JsonRpcProvider extends ethers.ethers.JsonRpcProvider { | ||
constructor(url, options, jsonRpcApiProviderOptions) { | ||
var _this; | ||
super(url, options == null ? void 0 : options.chainId, jsonRpcApiProviderOptions); | ||
_this = this; | ||
this.url = url; | ||
Object.defineProperty(this, _chainId, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _nextId, { | ||
writable: true, | ||
value: 1 | ||
}); | ||
Object.defineProperty(this, _sender, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.fetch = async function (request) { | ||
if (_this.url === undefined) { | ||
throw new Error('missing provider URL'); | ||
} | ||
const { | ||
method, | ||
params | ||
} = request; | ||
const jsonRpcRequest = { | ||
method, | ||
params, | ||
id: _classPrivateFieldBase(_this, _nextId)[_nextId]++, | ||
class JsonRpcProvider extends ethers.ethers.providers.JsonRpcProvider { | ||
constructor(url, options) { | ||
super(url, options == null ? void 0 : options.chainId); | ||
this._chainId = void 0; | ||
this._sender = void 0; | ||
this.send = (method, params) => { | ||
return this._sender.send(method, params); | ||
}; | ||
this.fetch = (method, params) => { | ||
const request = { | ||
method: method, | ||
params: params, | ||
id: this._nextId++, | ||
jsonrpc: '2.0' | ||
}; | ||
// const result = ethers.fetchJson(this.connection, JSON.stringify(request), getResult).then( | ||
// result => { | ||
// return result | ||
// }, | ||
// error => { | ||
// throw error | ||
// } | ||
// ) | ||
const fetchRequest = typeof _this.url === 'string' ? new ethers.ethers.FetchRequest(_this.url) : _this.url; | ||
fetchRequest.body = JSON.stringify(jsonRpcRequest); | ||
// TODOXXX: what about headers, etc..? | ||
// we probably need these in the options of the construtor, etc.. | ||
try { | ||
const res = await fetchRequest.send(); | ||
if (res.body) { | ||
try { | ||
const result = JSON.parse(ethers.ethers.toUtf8String(res.body)); | ||
// TODO: Process result | ||
return getResult(result); | ||
} catch (err) { | ||
throw new Error('invalid JSON response'); | ||
} | ||
} | ||
return null; | ||
} catch (err) { | ||
// TODO - error handling | ||
throw err; | ||
} | ||
const result = ethers.ethers.utils.fetchJson(this.connection, JSON.stringify(request), getResult).then(result => { | ||
return result; | ||
}, error => { | ||
throw error; | ||
}); | ||
return result; | ||
}; | ||
@@ -836,3 +860,3 @@ const chainId = options == null ? void 0 : options.chainId; | ||
const blockCache = options == null ? void 0 : options.blockCache; | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = chainId; | ||
this._chainId = chainId; | ||
@@ -850,17 +874,7 @@ // NOTE: it will either use the middleware stack passed to the constructor | ||
blockCache: blockCache | ||
})], new JsonRpcHandler(this.fetch, chainId)); | ||
_classPrivateFieldBase(this, _sender)[_sender] = router; | ||
})], new JsonRpcSender(this.fetch, chainId)); | ||
this._sender = new JsonRpcSender(router, chainId); | ||
} | ||
async request(request) { | ||
return _classPrivateFieldBase(this, _sender)[_sender].request(request); | ||
} | ||
async send(method, params, chainId) { | ||
return this.request({ | ||
method, | ||
params: params, | ||
chainId | ||
}); | ||
} | ||
async getNetwork() { | ||
const chainId = _classPrivateFieldBase(this, _chainId)[_chainId]; | ||
const chainId = this._chainId; | ||
if (chainId) { | ||
@@ -870,10 +884,10 @@ const network = constants_dist_0xsequenceNetworkConstants.networks[chainId]; | ||
const ensAddress = network == null ? void 0 : network.ensAddress; | ||
return ethers.ethers.Network.from({ | ||
name, | ||
chainId, | ||
ensAddress | ||
}); | ||
return { | ||
name: name, | ||
chainId: chainId, | ||
ensAddress: ensAddress | ||
}; | ||
} else { | ||
const chainIdHex = await this.send('eth_chainId', []); | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = Number(chainIdHex); | ||
this._chainId = ethers.ethers.BigNumber.from(chainIdHex).toNumber(); | ||
return this.getNetwork(); | ||
@@ -900,5 +914,7 @@ } | ||
exports.EagerProvider = EagerProvider; | ||
exports.JsonRpcHandler = JsonRpcHandler; | ||
exports.JsonRpcExternalProvider = JsonRpcExternalProvider; | ||
exports.JsonRpcProvider = JsonRpcProvider; | ||
exports.JsonRpcRouter = JsonRpcRouter; | ||
exports.JsonRpcSender = JsonRpcSender; | ||
exports.JsonRpcVersion = JsonRpcVersion; | ||
exports.PublicProvider = PublicProvider; | ||
@@ -919,4 +935,4 @@ exports.SigningProvider = SigningProvider; | ||
exports.indexerURL = indexerURL; | ||
exports.isJsonRpcHandler = isJsonRpcHandler; | ||
exports.isJsonRpcProvider = isJsonRpcProvider; | ||
exports.isJsonRpcSender = isJsonRpcSender; | ||
exports.isNetworkConfig = isNetworkConfig; | ||
@@ -923,0 +939,0 @@ exports.isValidNetworkConfig = isValidNetworkConfig; |
@@ -6,4 +6,4 @@ 'use strict'; | ||
var constants_dist_0xsequenceNetworkConstants = require('../constants/dist/0xsequence-network-constants.cjs.prod.js'); | ||
var ethers = require('ethers'); | ||
var utils = require('@0xsequence/utils'); | ||
var ethers = require('ethers'); | ||
@@ -35,3 +35,3 @@ function _extends() { | ||
} | ||
return Number(chainId); | ||
return ethers.ethers.BigNumber.from(chainId).toNumber(); | ||
}; | ||
@@ -143,3 +143,3 @@ const maybeChainId = chainId => { | ||
if (chainId.startsWith('0x')) { | ||
const id = Number(chainId); | ||
const id = ethers.ethers.BigNumber.from(chainId).toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -153,4 +153,4 @@ } else { | ||
return networks.find(n => n.chainId === chainId.chainId); | ||
} else if (typeof chainId === 'bigint') { | ||
const id = Number(chainId); | ||
} else if (ethers.ethers.BigNumber.isBigNumber(chainId)) { | ||
const id = chainId.toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -224,9 +224,9 @@ } else { | ||
function toChainIdNumber(chainIdLike) { | ||
if (typeof chainIdLike === 'bigint') { | ||
if (ethers.ethers.BigNumber.isBigNumber(chainIdLike)) { | ||
return chainIdLike; | ||
} | ||
if (utils.isBigNumberish(chainIdLike)) { | ||
return BigInt(chainIdLike); | ||
return ethers.ethers.BigNumber.from(chainIdLike); | ||
} | ||
return BigInt(chainIdLike.chainId); | ||
return ethers.ethers.BigNumber.from(chainIdLike.chainId); | ||
} | ||
@@ -278,2 +278,6 @@ const createNetworkConfig = (chainId, options) => { | ||
const JsonRpcVersion = '2.0'; | ||
// EIP-1193 function signature | ||
class JsonRpcRouter { | ||
@@ -289,6 +293,10 @@ constructor(middlewares, sender) { | ||
setMiddleware(middlewares) { | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender); | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender.sendAsync); | ||
} | ||
request(request) { | ||
return this.handler.request(request); | ||
sendAsync(request, callback, chainId) { | ||
try { | ||
this.handler(request, callback, chainId); | ||
} catch (err) { | ||
callback(err, undefined); | ||
} | ||
} | ||
@@ -299,4 +307,4 @@ } | ||
const toMiddleware = v => { | ||
if (v.requestHandler) { | ||
return v.requestHandler; | ||
if (v.sendAsyncMiddleware) { | ||
return v.sendAsyncMiddleware; | ||
} else { | ||
@@ -307,49 +315,80 @@ return v; | ||
let chain; | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler.request); | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler); | ||
for (let i = middlewares.length - 2; i >= 0; i--) { | ||
chain = toMiddleware(middlewares[i])(chain); | ||
} | ||
return { | ||
request: chain | ||
}; | ||
return chain; | ||
}; | ||
// TODOXXX: review.. | ||
function isJsonRpcProvider(cand) { | ||
return cand !== undefined && cand.send !== undefined && cand.constructor.defaultUrl !== undefined && cand.detectNetwork !== undefined && cand.getSigner !== undefined && cand.perform !== undefined; | ||
} | ||
function isJsonRpcSender(cand) { | ||
return cand !== undefined && cand.send !== undefined; | ||
function isJsonRpcHandler(cand) { | ||
return cand !== undefined && cand.sendAsync !== undefined; | ||
} | ||
class JsonRpcHandler { | ||
let _nextId = 0; | ||
class JsonRpcSender { | ||
constructor(provider, defaultChainId) { | ||
this.provider = void 0; | ||
this.send = void 0; | ||
this.request = void 0; | ||
this.defaultChainId = void 0; | ||
this.request = request => { | ||
if (!request.chainId) { | ||
request.chainId = this.defaultChainId; | ||
} | ||
return this.provider(request); | ||
this.sendAsync = (request, callback, chainId) => { | ||
this.send(request.method, request.params, chainId || this.defaultChainId).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
if (isJsonRpcSender(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params, request.chainId); | ||
this.defaultChainId = defaultChainId; | ||
if (isJsonRpcProvider(provider)) { | ||
// we can ignore defaultChainId for JsonRpcProviders as they are already chain-bound | ||
this.send = provider.send.bind(provider); | ||
} else if (isJsonRpcHandler(provider)) { | ||
this.send = (method, params, chainId) => { | ||
return new Promise((resolve, reject) => { | ||
provider.sendAsync({ | ||
// TODO: really shouldn't have to set these here? | ||
jsonrpc: JsonRpcVersion, | ||
id: ++_nextId, | ||
method, | ||
params | ||
}, (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else if (response) { | ||
resolve(response.result); | ||
} else { | ||
resolve(undefined); | ||
} | ||
}, chainId || this.defaultChainId); | ||
}); | ||
}; | ||
} else if (isJsonRpcProvider(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params || []); | ||
}; | ||
} else { | ||
this.provider = provider; | ||
this.send = provider; | ||
} | ||
this.defaultChainId = defaultChainId; | ||
this.request = (request, chainId) => { | ||
return this.send(request.method, request.params, chainId); | ||
}; | ||
} | ||
send(method, params, chainId) { | ||
const request = { | ||
method, | ||
params, | ||
chainId | ||
} | ||
class JsonRpcExternalProvider { | ||
constructor(provider) { | ||
this.provider = provider; | ||
this.sendAsync = (request, callback) => { | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
return this.request(request); | ||
this.send = this.sendAsync; | ||
} | ||
@@ -360,3 +399,3 @@ } | ||
constructor(isAllowedFunc) { | ||
this.requestHandler = void 0; | ||
this.sendAsyncMiddleware = void 0; | ||
this.isAllowedFunc = void 0; | ||
@@ -368,11 +407,11 @@ if (isAllowedFunc) { | ||
} | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
setIsAllowedFunc(fn) { | ||
this.isAllowedFunc = fn; | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
} | ||
const allowProviderMiddleware = isAllowed => next => { | ||
return request => { | ||
return (request, callback, chainId) => { | ||
// ensure precondition is met or do not allow the request to continue | ||
@@ -384,3 +423,3 @@ if (!isAllowed(request)) { | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -391,3 +430,2 @@ }; | ||
constructor(options) { | ||
var _this = this; | ||
// cachableJsonRpcMethods which can be permanently cached for lifetime | ||
@@ -411,13 +449,15 @@ // of the provider. | ||
this.defaultChainId = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Respond early with cached result | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
const _result = _this.getCacheValue(key); | ||
if (_result && _result !== '') { | ||
return { | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
const result = this.getCacheValue(key); | ||
if (result && result !== '') { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: _result | ||
}; | ||
result: result | ||
}); | ||
return; | ||
} | ||
@@ -427,17 +467,19 @@ } | ||
// Continue down the handler chain | ||
const result = await next(request); | ||
// Store result in cache and continue | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (result && _this.shouldCacheResponse(request, result)) { | ||
// cache the value | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
if (_this.cachableJsonRpcMethods.includes(request.method)) { | ||
_this.setCacheValue(key, result); | ||
} else { | ||
_this.setCacheByBlockValue(key, result); | ||
next(request, (error, response, chainId) => { | ||
// Store result in cache and continue | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (response && response.result && this.shouldCacheResponse(request, response)) { | ||
// cache the value | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
if (this.cachableJsonRpcMethods.includes(request.method)) { | ||
this.setCacheValue(key, response.result); | ||
} else { | ||
this.setCacheByBlockValue(key, response.result); | ||
} | ||
} | ||
} | ||
} | ||
return result; | ||
// Exec next handler | ||
callback(error, response); | ||
}, chainId || this.defaultChainId); | ||
}; | ||
@@ -491,5 +533,5 @@ }; | ||
}; | ||
this.shouldCacheResponse = (request, result) => { | ||
this.shouldCacheResponse = (request, response) => { | ||
// skip if we do not have response result | ||
if (!result) { | ||
if (!response || !response.result) { | ||
return false; | ||
@@ -499,3 +541,3 @@ } | ||
// skip caching eth_getCode where resposne value is '0x' or empty | ||
if (request.method === 'eth_getCode' && result.length <= 2) { | ||
if (request.method === 'eth_getCode' && response.result.length <= 2) { | ||
return false; | ||
@@ -532,29 +574,52 @@ } | ||
constructor(options) { | ||
var _this = this; | ||
this.options = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
switch (request.method) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
if (_this.options.chainId) { | ||
return `${_this.options.chainId}`; | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${this.options.chainId}` | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_chainId': | ||
if (_this.options.chainId) { | ||
return ethers.ethers.toQuantity(_this.options.chainId); | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.ethers.utils.hexlify(this.options.chainId) | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_accounts': | ||
if (_this.options.accountAddress) { | ||
return [ethers.ethers.getAddress(_this.options.accountAddress)]; | ||
if (this.options.accountAddress) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: [ethers.ethers.utils.getAddress(this.options.accountAddress)] | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'sequence_getWalletContext': | ||
if (_this.options.walletContext) { | ||
return _this.options.walletContext; | ||
if (this.options.walletContext) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: this.options.walletContext | ||
}); | ||
return; | ||
} | ||
break; | ||
} | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -567,12 +632,13 @@ }; | ||
const exceptionProviderMiddleware = next => { | ||
return async request => { | ||
try { | ||
return await next(request); | ||
} catch (error) { | ||
if (typeof error === 'string') { | ||
throw new Error(error); | ||
} else { | ||
throw new Error(error.message); | ||
return (request, callback, chainId) => { | ||
next(request, (error, response) => { | ||
if (!error && response && response.error) { | ||
if (typeof response.error === 'string') { | ||
throw new Error(response.error); | ||
} else { | ||
throw new Error(response.error.message); | ||
} | ||
} | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -583,12 +649,13 @@ }; | ||
const loggingProviderMiddleware = next => { | ||
return async request => { | ||
const chainIdLabel = request.chainId ? ` chainId:${request.chainId}` : ''; | ||
return (request, callback, chainId) => { | ||
const chainIdLabel = chainId ? ` chainId:${chainId}` : ''; | ||
utils.logger.info(`[provider request]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params); | ||
try { | ||
const result = await next(request); | ||
utils.logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `result:`, result); | ||
return result; | ||
} catch (error) { | ||
utils.logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} | ||
next(request, (error, response) => { | ||
if (error) { | ||
utils.logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} else { | ||
utils.logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `response:`, response); | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -598,17 +665,27 @@ }; | ||
const networkProviderMiddleware = getChainId => next => { | ||
return async request => { | ||
return (request, callback, chainId) => { | ||
const networkChainId = getChainId(request); | ||
switch (request.method) { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
{ | ||
return `${networkChainId}`; | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${networkChainId}` | ||
}); | ||
return; | ||
case 'eth_chainId': | ||
{ | ||
return ethers.ethers.toQuantity(networkChainId); | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.ethers.utils.hexlify(networkChainId) | ||
}); | ||
return; | ||
} | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -626,11 +703,12 @@ }; | ||
this.provider = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Forward signing requests to the signing provider | ||
if (SignerJsonRpcMethods.includes(request.method)) { | ||
return this.provider.request(request); | ||
this.provider.sendAsync(request, callback, chainId); | ||
return; | ||
} | ||
// Continue to next handler | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -647,7 +725,14 @@ }; | ||
this.rpcUrl = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback) => { | ||
// When provider is configured, send non-private methods to our local public provider | ||
if (this.provider && !this.privateJsonRpcMethods.includes(request.method)) { | ||
return this.provider.send(request.method, request.params || []); | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => callback(e)); | ||
return; | ||
} | ||
@@ -657,3 +742,3 @@ | ||
utils.logger.debug('[public-provider] sending request to signer window', request.method); | ||
return next(request); | ||
next(request, callback); | ||
}; | ||
@@ -676,3 +761,3 @@ }; | ||
// which supports better caching. | ||
this.provider = new ethers.ethers.JsonRpcProvider(rpcUrl); | ||
this.provider = new ethers.providers.JsonRpcProvider(rpcUrl); | ||
} | ||
@@ -684,48 +769,47 @@ } | ||
constructor() { | ||
var _this = this; | ||
this.singleflightJsonRpcMethods = ['eth_chainId', 'net_version', 'eth_call', 'eth_getCode', 'eth_blockNumber', 'eth_getBalance', 'eth_getStorageAt', 'eth_getTransactionCount', 'eth_getBlockTransactionCountByHash', 'eth_getBlockTransactionCountByNumber', 'eth_getUncleCountByBlockHash', 'eth_getUncleCountByBlockNumber', 'eth_getBlockByHash', 'eth_getBlockByNumber', 'eth_getTransactionByHash', 'eth_getTransactionByBlockHashAndIndex', 'eth_getTransactionByBlockNumberAndIndex', 'eth_getTransactionReceipt', 'eth_getUncleByBlockHashAndIndex', 'eth_getUncleByBlockNumberAndIndex', 'eth_getLogs']; | ||
this.inflight = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// continue to next handler if method isn't part of methods list | ||
if (!_this.singleflightJsonRpcMethods.includes(request.method)) { | ||
return next(request); | ||
if (!this.singleflightJsonRpcMethods.includes(request.method)) { | ||
next(request, callback, chainId); | ||
return; | ||
} | ||
const key = _this.requestKey(request.method, request.params || [], request.chainId); | ||
if (!_this.inflight[key]) { | ||
const key = this.requestKey(request.method, request.params || [], chainId); | ||
if (!this.inflight[key]) { | ||
// first request -- init the empty list | ||
_this.inflight[key] = []; | ||
this.inflight[key] = []; | ||
} else { | ||
// already in-flight, add the callback to the list and return | ||
return new Promise((resolve, reject) => { | ||
_this.inflight[key].push({ | ||
id: request.id, | ||
callback: (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(response); | ||
} | ||
} | ||
}); | ||
this.inflight[key].push({ | ||
id: request.id, | ||
callback | ||
}); | ||
return; | ||
} | ||
// Continue down the handler chain | ||
try { | ||
// Exec the handler, and on success resolve all other promises | ||
const response = await next(request); | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(undefined, response)); | ||
return response; | ||
} catch (error) { | ||
// If the request fails, reject all queued promises. | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(error, undefined)); | ||
throw error; | ||
} finally { | ||
delete _this.inflight[key]; | ||
} | ||
next(request, (error, response, chainId) => { | ||
// callback the original request | ||
callback(error, response); | ||
// callback all other requests of the same kind in queue, with the | ||
// same response result as from the first response. | ||
for (let i = 0; i < this.inflight[key].length; i++) { | ||
const sub = this.inflight[key][i]; | ||
if (error) { | ||
sub.callback(error, response); | ||
} else if (response) { | ||
sub.callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: sub.id, | ||
result: response.result | ||
}); | ||
} | ||
} | ||
// clear request key | ||
delete this.inflight[key]; | ||
}, chainId); | ||
}; | ||
@@ -749,84 +833,24 @@ }; | ||
function _classPrivateFieldBase(receiver, privateKey) { | ||
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { | ||
throw new TypeError("attempted to use private field on non-instance"); | ||
} | ||
return receiver; | ||
} | ||
var id = 0; | ||
function _classPrivateFieldKey(name) { | ||
return "__private_" + id++ + "_" + name; | ||
} | ||
var _chainId = /*#__PURE__*/_classPrivateFieldKey("chainId"); | ||
var _nextId = /*#__PURE__*/_classPrivateFieldKey("nextId"); | ||
var _sender = /*#__PURE__*/_classPrivateFieldKey("sender"); | ||
// JsonRpcProvider with a middleware stack. By default it will use a simple caching middleware. | ||
class JsonRpcProvider extends ethers.ethers.JsonRpcProvider { | ||
constructor(url, options, jsonRpcApiProviderOptions) { | ||
var _this; | ||
super(url, options == null ? void 0 : options.chainId, jsonRpcApiProviderOptions); | ||
_this = this; | ||
this.url = url; | ||
Object.defineProperty(this, _chainId, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _nextId, { | ||
writable: true, | ||
value: 1 | ||
}); | ||
Object.defineProperty(this, _sender, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.fetch = async function (request) { | ||
if (_this.url === undefined) { | ||
throw new Error('missing provider URL'); | ||
} | ||
const { | ||
method, | ||
params | ||
} = request; | ||
const jsonRpcRequest = { | ||
method, | ||
params, | ||
id: _classPrivateFieldBase(_this, _nextId)[_nextId]++, | ||
class JsonRpcProvider extends ethers.ethers.providers.JsonRpcProvider { | ||
constructor(url, options) { | ||
super(url, options == null ? void 0 : options.chainId); | ||
this._chainId = void 0; | ||
this._sender = void 0; | ||
this.send = (method, params) => { | ||
return this._sender.send(method, params); | ||
}; | ||
this.fetch = (method, params) => { | ||
const request = { | ||
method: method, | ||
params: params, | ||
id: this._nextId++, | ||
jsonrpc: '2.0' | ||
}; | ||
// const result = ethers.fetchJson(this.connection, JSON.stringify(request), getResult).then( | ||
// result => { | ||
// return result | ||
// }, | ||
// error => { | ||
// throw error | ||
// } | ||
// ) | ||
const fetchRequest = typeof _this.url === 'string' ? new ethers.ethers.FetchRequest(_this.url) : _this.url; | ||
fetchRequest.body = JSON.stringify(jsonRpcRequest); | ||
// TODOXXX: what about headers, etc..? | ||
// we probably need these in the options of the construtor, etc.. | ||
try { | ||
const res = await fetchRequest.send(); | ||
if (res.body) { | ||
try { | ||
const result = JSON.parse(ethers.ethers.toUtf8String(res.body)); | ||
// TODO: Process result | ||
return getResult(result); | ||
} catch (err) { | ||
throw new Error('invalid JSON response'); | ||
} | ||
} | ||
return null; | ||
} catch (err) { | ||
// TODO - error handling | ||
throw err; | ||
} | ||
const result = ethers.ethers.utils.fetchJson(this.connection, JSON.stringify(request), getResult).then(result => { | ||
return result; | ||
}, error => { | ||
throw error; | ||
}); | ||
return result; | ||
}; | ||
@@ -836,3 +860,3 @@ const chainId = options == null ? void 0 : options.chainId; | ||
const blockCache = options == null ? void 0 : options.blockCache; | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = chainId; | ||
this._chainId = chainId; | ||
@@ -850,17 +874,7 @@ // NOTE: it will either use the middleware stack passed to the constructor | ||
blockCache: blockCache | ||
})], new JsonRpcHandler(this.fetch, chainId)); | ||
_classPrivateFieldBase(this, _sender)[_sender] = router; | ||
})], new JsonRpcSender(this.fetch, chainId)); | ||
this._sender = new JsonRpcSender(router, chainId); | ||
} | ||
async request(request) { | ||
return _classPrivateFieldBase(this, _sender)[_sender].request(request); | ||
} | ||
async send(method, params, chainId) { | ||
return this.request({ | ||
method, | ||
params: params, | ||
chainId | ||
}); | ||
} | ||
async getNetwork() { | ||
const chainId = _classPrivateFieldBase(this, _chainId)[_chainId]; | ||
const chainId = this._chainId; | ||
if (chainId) { | ||
@@ -870,10 +884,10 @@ const network = constants_dist_0xsequenceNetworkConstants.networks[chainId]; | ||
const ensAddress = network == null ? void 0 : network.ensAddress; | ||
return ethers.ethers.Network.from({ | ||
name, | ||
chainId, | ||
ensAddress | ||
}); | ||
return { | ||
name: name, | ||
chainId: chainId, | ||
ensAddress: ensAddress | ||
}; | ||
} else { | ||
const chainIdHex = await this.send('eth_chainId', []); | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = Number(chainIdHex); | ||
this._chainId = ethers.ethers.BigNumber.from(chainIdHex).toNumber(); | ||
return this.getNetwork(); | ||
@@ -900,5 +914,7 @@ } | ||
exports.EagerProvider = EagerProvider; | ||
exports.JsonRpcHandler = JsonRpcHandler; | ||
exports.JsonRpcExternalProvider = JsonRpcExternalProvider; | ||
exports.JsonRpcProvider = JsonRpcProvider; | ||
exports.JsonRpcRouter = JsonRpcRouter; | ||
exports.JsonRpcSender = JsonRpcSender; | ||
exports.JsonRpcVersion = JsonRpcVersion; | ||
exports.PublicProvider = PublicProvider; | ||
@@ -919,4 +935,4 @@ exports.SigningProvider = SigningProvider; | ||
exports.indexerURL = indexerURL; | ||
exports.isJsonRpcHandler = isJsonRpcHandler; | ||
exports.isJsonRpcProvider = isJsonRpcProvider; | ||
exports.isJsonRpcSender = isJsonRpcSender; | ||
exports.isNetworkConfig = isNetworkConfig; | ||
@@ -923,0 +939,0 @@ exports.isValidNetworkConfig = isValidNetworkConfig; |
import { networks, ChainId } from '../constants/dist/0xsequence-network-constants.esm.js'; | ||
export { ChainId, NetworkType, networks } from '../constants/dist/0xsequence-network-constants.esm.js'; | ||
import { ethers, providers } from 'ethers'; | ||
import { isBigNumberish, logger } from '@0xsequence/utils'; | ||
import { ethers } from 'ethers'; | ||
@@ -31,3 +31,3 @@ function _extends() { | ||
} | ||
return Number(chainId); | ||
return ethers.BigNumber.from(chainId).toNumber(); | ||
}; | ||
@@ -139,3 +139,3 @@ const maybeChainId = chainId => { | ||
if (chainId.startsWith('0x')) { | ||
const id = Number(chainId); | ||
const id = ethers.BigNumber.from(chainId).toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -149,4 +149,4 @@ } else { | ||
return networks.find(n => n.chainId === chainId.chainId); | ||
} else if (typeof chainId === 'bigint') { | ||
const id = Number(chainId); | ||
} else if (ethers.BigNumber.isBigNumber(chainId)) { | ||
const id = chainId.toNumber(); | ||
return networks.find(n => n.chainId === id); | ||
@@ -220,9 +220,9 @@ } else { | ||
function toChainIdNumber(chainIdLike) { | ||
if (typeof chainIdLike === 'bigint') { | ||
if (ethers.BigNumber.isBigNumber(chainIdLike)) { | ||
return chainIdLike; | ||
} | ||
if (isBigNumberish(chainIdLike)) { | ||
return BigInt(chainIdLike); | ||
return ethers.BigNumber.from(chainIdLike); | ||
} | ||
return BigInt(chainIdLike.chainId); | ||
return ethers.BigNumber.from(chainIdLike.chainId); | ||
} | ||
@@ -274,2 +274,6 @@ const createNetworkConfig = (chainId, options) => { | ||
const JsonRpcVersion = '2.0'; | ||
// EIP-1193 function signature | ||
class JsonRpcRouter { | ||
@@ -285,6 +289,10 @@ constructor(middlewares, sender) { | ||
setMiddleware(middlewares) { | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender); | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender.sendAsync); | ||
} | ||
request(request) { | ||
return this.handler.request(request); | ||
sendAsync(request, callback, chainId) { | ||
try { | ||
this.handler(request, callback, chainId); | ||
} catch (err) { | ||
callback(err, undefined); | ||
} | ||
} | ||
@@ -295,4 +303,4 @@ } | ||
const toMiddleware = v => { | ||
if (v.requestHandler) { | ||
return v.requestHandler; | ||
if (v.sendAsyncMiddleware) { | ||
return v.sendAsyncMiddleware; | ||
} else { | ||
@@ -303,49 +311,80 @@ return v; | ||
let chain; | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler.request); | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler); | ||
for (let i = middlewares.length - 2; i >= 0; i--) { | ||
chain = toMiddleware(middlewares[i])(chain); | ||
} | ||
return { | ||
request: chain | ||
}; | ||
return chain; | ||
}; | ||
// TODOXXX: review.. | ||
function isJsonRpcProvider(cand) { | ||
return cand !== undefined && cand.send !== undefined && cand.constructor.defaultUrl !== undefined && cand.detectNetwork !== undefined && cand.getSigner !== undefined && cand.perform !== undefined; | ||
} | ||
function isJsonRpcSender(cand) { | ||
return cand !== undefined && cand.send !== undefined; | ||
function isJsonRpcHandler(cand) { | ||
return cand !== undefined && cand.sendAsync !== undefined; | ||
} | ||
class JsonRpcHandler { | ||
let _nextId = 0; | ||
class JsonRpcSender { | ||
constructor(provider, defaultChainId) { | ||
this.provider = void 0; | ||
this.send = void 0; | ||
this.request = void 0; | ||
this.defaultChainId = void 0; | ||
this.request = request => { | ||
if (!request.chainId) { | ||
request.chainId = this.defaultChainId; | ||
} | ||
return this.provider(request); | ||
this.sendAsync = (request, callback, chainId) => { | ||
this.send(request.method, request.params, chainId || this.defaultChainId).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
if (isJsonRpcSender(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params, request.chainId); | ||
this.defaultChainId = defaultChainId; | ||
if (isJsonRpcProvider(provider)) { | ||
// we can ignore defaultChainId for JsonRpcProviders as they are already chain-bound | ||
this.send = provider.send.bind(provider); | ||
} else if (isJsonRpcHandler(provider)) { | ||
this.send = (method, params, chainId) => { | ||
return new Promise((resolve, reject) => { | ||
provider.sendAsync({ | ||
// TODO: really shouldn't have to set these here? | ||
jsonrpc: JsonRpcVersion, | ||
id: ++_nextId, | ||
method, | ||
params | ||
}, (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else if (response) { | ||
resolve(response.result); | ||
} else { | ||
resolve(undefined); | ||
} | ||
}, chainId || this.defaultChainId); | ||
}); | ||
}; | ||
} else if (isJsonRpcProvider(provider)) { | ||
this.provider = request => { | ||
return provider.send(request.method, request.params || []); | ||
}; | ||
} else { | ||
this.provider = provider; | ||
this.send = provider; | ||
} | ||
this.defaultChainId = defaultChainId; | ||
this.request = (request, chainId) => { | ||
return this.send(request.method, request.params, chainId); | ||
}; | ||
} | ||
send(method, params, chainId) { | ||
const request = { | ||
method, | ||
params, | ||
chainId | ||
} | ||
class JsonRpcExternalProvider { | ||
constructor(provider) { | ||
this.provider = provider; | ||
this.sendAsync = (request, callback) => { | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => { | ||
callback(e, undefined); | ||
}); | ||
}; | ||
return this.request(request); | ||
this.send = this.sendAsync; | ||
} | ||
@@ -356,3 +395,3 @@ } | ||
constructor(isAllowedFunc) { | ||
this.requestHandler = void 0; | ||
this.sendAsyncMiddleware = void 0; | ||
this.isAllowedFunc = void 0; | ||
@@ -364,11 +403,11 @@ if (isAllowedFunc) { | ||
} | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
setIsAllowedFunc(fn) { | ||
this.isAllowedFunc = fn; | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc); | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc); | ||
} | ||
} | ||
const allowProviderMiddleware = isAllowed => next => { | ||
return request => { | ||
return (request, callback, chainId) => { | ||
// ensure precondition is met or do not allow the request to continue | ||
@@ -380,3 +419,3 @@ if (!isAllowed(request)) { | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -387,3 +426,2 @@ }; | ||
constructor(options) { | ||
var _this = this; | ||
// cachableJsonRpcMethods which can be permanently cached for lifetime | ||
@@ -407,13 +445,15 @@ // of the provider. | ||
this.defaultChainId = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Respond early with cached result | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
const _result = _this.getCacheValue(key); | ||
if (_result && _result !== '') { | ||
return { | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
const result = this.getCacheValue(key); | ||
if (result && result !== '') { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: _result | ||
}; | ||
result: result | ||
}); | ||
return; | ||
} | ||
@@ -423,17 +463,19 @@ } | ||
// Continue down the handler chain | ||
const result = await next(request); | ||
// Store result in cache and continue | ||
if (_this.cachableJsonRpcMethods.includes(request.method) || _this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (result && _this.shouldCacheResponse(request, result)) { | ||
// cache the value | ||
const key = _this.cacheKey(request.method, request.params, request.chainId || _this.defaultChainId); | ||
if (_this.cachableJsonRpcMethods.includes(request.method)) { | ||
_this.setCacheValue(key, result); | ||
} else { | ||
_this.setCacheByBlockValue(key, result); | ||
next(request, (error, response, chainId) => { | ||
// Store result in cache and continue | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (response && response.result && this.shouldCacheResponse(request, response)) { | ||
// cache the value | ||
const key = this.cacheKey(request.method, request.params, chainId || this.defaultChainId); | ||
if (this.cachableJsonRpcMethods.includes(request.method)) { | ||
this.setCacheValue(key, response.result); | ||
} else { | ||
this.setCacheByBlockValue(key, response.result); | ||
} | ||
} | ||
} | ||
} | ||
return result; | ||
// Exec next handler | ||
callback(error, response); | ||
}, chainId || this.defaultChainId); | ||
}; | ||
@@ -487,5 +529,5 @@ }; | ||
}; | ||
this.shouldCacheResponse = (request, result) => { | ||
this.shouldCacheResponse = (request, response) => { | ||
// skip if we do not have response result | ||
if (!result) { | ||
if (!response || !response.result) { | ||
return false; | ||
@@ -495,3 +537,3 @@ } | ||
// skip caching eth_getCode where resposne value is '0x' or empty | ||
if (request.method === 'eth_getCode' && result.length <= 2) { | ||
if (request.method === 'eth_getCode' && response.result.length <= 2) { | ||
return false; | ||
@@ -528,29 +570,52 @@ } | ||
constructor(options) { | ||
var _this = this; | ||
this.options = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
switch (request.method) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
if (_this.options.chainId) { | ||
return `${_this.options.chainId}`; | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${this.options.chainId}` | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_chainId': | ||
if (_this.options.chainId) { | ||
return ethers.toQuantity(_this.options.chainId); | ||
if (this.options.chainId) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.utils.hexlify(this.options.chainId) | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'eth_accounts': | ||
if (_this.options.accountAddress) { | ||
return [ethers.getAddress(_this.options.accountAddress)]; | ||
if (this.options.accountAddress) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: [ethers.utils.getAddress(this.options.accountAddress)] | ||
}); | ||
return; | ||
} | ||
break; | ||
case 'sequence_getWalletContext': | ||
if (_this.options.walletContext) { | ||
return _this.options.walletContext; | ||
if (this.options.walletContext) { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: this.options.walletContext | ||
}); | ||
return; | ||
} | ||
break; | ||
} | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -563,12 +628,13 @@ }; | ||
const exceptionProviderMiddleware = next => { | ||
return async request => { | ||
try { | ||
return await next(request); | ||
} catch (error) { | ||
if (typeof error === 'string') { | ||
throw new Error(error); | ||
} else { | ||
throw new Error(error.message); | ||
return (request, callback, chainId) => { | ||
next(request, (error, response) => { | ||
if (!error && response && response.error) { | ||
if (typeof response.error === 'string') { | ||
throw new Error(response.error); | ||
} else { | ||
throw new Error(response.error.message); | ||
} | ||
} | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -579,12 +645,13 @@ }; | ||
const loggingProviderMiddleware = next => { | ||
return async request => { | ||
const chainIdLabel = request.chainId ? ` chainId:${request.chainId}` : ''; | ||
return (request, callback, chainId) => { | ||
const chainIdLabel = chainId ? ` chainId:${chainId}` : ''; | ||
logger.info(`[provider request]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params); | ||
try { | ||
const result = await next(request); | ||
logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `result:`, result); | ||
return result; | ||
} catch (error) { | ||
logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} | ||
next(request, (error, response) => { | ||
if (error) { | ||
logger.warn(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `error:`, error); | ||
} else { | ||
logger.info(`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params, `response:`, response); | ||
} | ||
callback(error, response); | ||
}, chainId); | ||
}; | ||
@@ -594,17 +661,27 @@ }; | ||
const networkProviderMiddleware = getChainId => next => { | ||
return async request => { | ||
return (request, callback, chainId) => { | ||
const networkChainId = getChainId(request); | ||
switch (request.method) { | ||
const { | ||
id, | ||
method | ||
} = request; | ||
switch (method) { | ||
case 'net_version': | ||
{ | ||
return `${networkChainId}`; | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: `${networkChainId}` | ||
}); | ||
return; | ||
case 'eth_chainId': | ||
{ | ||
return ethers.toQuantity(networkChainId); | ||
} | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: id, | ||
result: ethers.utils.hexlify(networkChainId) | ||
}); | ||
return; | ||
} | ||
// request is allowed. keep going.. | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -622,11 +699,12 @@ }; | ||
this.provider = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// Forward signing requests to the signing provider | ||
if (SignerJsonRpcMethods.includes(request.method)) { | ||
return this.provider.request(request); | ||
this.provider.sendAsync(request, callback, chainId); | ||
return; | ||
} | ||
// Continue to next handler | ||
return next(request); | ||
next(request, callback, chainId); | ||
}; | ||
@@ -643,7 +721,14 @@ }; | ||
this.rpcUrl = void 0; | ||
this.requestHandler = next => { | ||
return request => { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback) => { | ||
// When provider is configured, send non-private methods to our local public provider | ||
if (this.provider && !this.privateJsonRpcMethods.includes(request.method)) { | ||
return this.provider.send(request.method, request.params || []); | ||
this.provider.send(request.method, request.params).then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id, | ||
result: r | ||
}); | ||
}).catch(e => callback(e)); | ||
return; | ||
} | ||
@@ -653,3 +738,3 @@ | ||
logger.debug('[public-provider] sending request to signer window', request.method); | ||
return next(request); | ||
next(request, callback); | ||
}; | ||
@@ -672,3 +757,3 @@ }; | ||
// which supports better caching. | ||
this.provider = new ethers.JsonRpcProvider(rpcUrl); | ||
this.provider = new providers.JsonRpcProvider(rpcUrl); | ||
} | ||
@@ -680,48 +765,47 @@ } | ||
constructor() { | ||
var _this = this; | ||
this.singleflightJsonRpcMethods = ['eth_chainId', 'net_version', 'eth_call', 'eth_getCode', 'eth_blockNumber', 'eth_getBalance', 'eth_getStorageAt', 'eth_getTransactionCount', 'eth_getBlockTransactionCountByHash', 'eth_getBlockTransactionCountByNumber', 'eth_getUncleCountByBlockHash', 'eth_getUncleCountByBlockNumber', 'eth_getBlockByHash', 'eth_getBlockByNumber', 'eth_getTransactionByHash', 'eth_getTransactionByBlockHashAndIndex', 'eth_getTransactionByBlockNumberAndIndex', 'eth_getTransactionReceipt', 'eth_getUncleByBlockHashAndIndex', 'eth_getUncleByBlockNumberAndIndex', 'eth_getLogs']; | ||
this.inflight = void 0; | ||
this.requestHandler = next => { | ||
return async function (request) { | ||
this.sendAsyncMiddleware = next => { | ||
return (request, callback, chainId) => { | ||
// continue to next handler if method isn't part of methods list | ||
if (!_this.singleflightJsonRpcMethods.includes(request.method)) { | ||
return next(request); | ||
if (!this.singleflightJsonRpcMethods.includes(request.method)) { | ||
next(request, callback, chainId); | ||
return; | ||
} | ||
const key = _this.requestKey(request.method, request.params || [], request.chainId); | ||
if (!_this.inflight[key]) { | ||
const key = this.requestKey(request.method, request.params || [], chainId); | ||
if (!this.inflight[key]) { | ||
// first request -- init the empty list | ||
_this.inflight[key] = []; | ||
this.inflight[key] = []; | ||
} else { | ||
// already in-flight, add the callback to the list and return | ||
return new Promise((resolve, reject) => { | ||
_this.inflight[key].push({ | ||
id: request.id, | ||
callback: (error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(response); | ||
} | ||
} | ||
}); | ||
this.inflight[key].push({ | ||
id: request.id, | ||
callback | ||
}); | ||
return; | ||
} | ||
// Continue down the handler chain | ||
try { | ||
// Exec the handler, and on success resolve all other promises | ||
const response = await next(request); | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(undefined, response)); | ||
return response; | ||
} catch (error) { | ||
// If the request fails, reject all queued promises. | ||
_this.inflight[key].forEach(({ | ||
callback | ||
}) => callback(error, undefined)); | ||
throw error; | ||
} finally { | ||
delete _this.inflight[key]; | ||
} | ||
next(request, (error, response, chainId) => { | ||
// callback the original request | ||
callback(error, response); | ||
// callback all other requests of the same kind in queue, with the | ||
// same response result as from the first response. | ||
for (let i = 0; i < this.inflight[key].length; i++) { | ||
const sub = this.inflight[key][i]; | ||
if (error) { | ||
sub.callback(error, response); | ||
} else if (response) { | ||
sub.callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: sub.id, | ||
result: response.result | ||
}); | ||
} | ||
} | ||
// clear request key | ||
delete this.inflight[key]; | ||
}, chainId); | ||
}; | ||
@@ -745,84 +829,24 @@ }; | ||
function _classPrivateFieldBase(receiver, privateKey) { | ||
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { | ||
throw new TypeError("attempted to use private field on non-instance"); | ||
} | ||
return receiver; | ||
} | ||
var id = 0; | ||
function _classPrivateFieldKey(name) { | ||
return "__private_" + id++ + "_" + name; | ||
} | ||
var _chainId = /*#__PURE__*/_classPrivateFieldKey("chainId"); | ||
var _nextId = /*#__PURE__*/_classPrivateFieldKey("nextId"); | ||
var _sender = /*#__PURE__*/_classPrivateFieldKey("sender"); | ||
// JsonRpcProvider with a middleware stack. By default it will use a simple caching middleware. | ||
class JsonRpcProvider extends ethers.JsonRpcProvider { | ||
constructor(url, options, jsonRpcApiProviderOptions) { | ||
var _this; | ||
super(url, options == null ? void 0 : options.chainId, jsonRpcApiProviderOptions); | ||
_this = this; | ||
this.url = url; | ||
Object.defineProperty(this, _chainId, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _nextId, { | ||
writable: true, | ||
value: 1 | ||
}); | ||
Object.defineProperty(this, _sender, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.fetch = async function (request) { | ||
if (_this.url === undefined) { | ||
throw new Error('missing provider URL'); | ||
} | ||
const { | ||
method, | ||
params | ||
} = request; | ||
const jsonRpcRequest = { | ||
method, | ||
params, | ||
id: _classPrivateFieldBase(_this, _nextId)[_nextId]++, | ||
class JsonRpcProvider extends ethers.providers.JsonRpcProvider { | ||
constructor(url, options) { | ||
super(url, options == null ? void 0 : options.chainId); | ||
this._chainId = void 0; | ||
this._sender = void 0; | ||
this.send = (method, params) => { | ||
return this._sender.send(method, params); | ||
}; | ||
this.fetch = (method, params) => { | ||
const request = { | ||
method: method, | ||
params: params, | ||
id: this._nextId++, | ||
jsonrpc: '2.0' | ||
}; | ||
// const result = ethers.fetchJson(this.connection, JSON.stringify(request), getResult).then( | ||
// result => { | ||
// return result | ||
// }, | ||
// error => { | ||
// throw error | ||
// } | ||
// ) | ||
const fetchRequest = typeof _this.url === 'string' ? new ethers.FetchRequest(_this.url) : _this.url; | ||
fetchRequest.body = JSON.stringify(jsonRpcRequest); | ||
// TODOXXX: what about headers, etc..? | ||
// we probably need these in the options of the construtor, etc.. | ||
try { | ||
const res = await fetchRequest.send(); | ||
if (res.body) { | ||
try { | ||
const result = JSON.parse(ethers.toUtf8String(res.body)); | ||
// TODO: Process result | ||
return getResult(result); | ||
} catch (err) { | ||
throw new Error('invalid JSON response'); | ||
} | ||
} | ||
return null; | ||
} catch (err) { | ||
// TODO - error handling | ||
throw err; | ||
} | ||
const result = ethers.utils.fetchJson(this.connection, JSON.stringify(request), getResult).then(result => { | ||
return result; | ||
}, error => { | ||
throw error; | ||
}); | ||
return result; | ||
}; | ||
@@ -832,3 +856,3 @@ const chainId = options == null ? void 0 : options.chainId; | ||
const blockCache = options == null ? void 0 : options.blockCache; | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = chainId; | ||
this._chainId = chainId; | ||
@@ -846,17 +870,7 @@ // NOTE: it will either use the middleware stack passed to the constructor | ||
blockCache: blockCache | ||
})], new JsonRpcHandler(this.fetch, chainId)); | ||
_classPrivateFieldBase(this, _sender)[_sender] = router; | ||
})], new JsonRpcSender(this.fetch, chainId)); | ||
this._sender = new JsonRpcSender(router, chainId); | ||
} | ||
async request(request) { | ||
return _classPrivateFieldBase(this, _sender)[_sender].request(request); | ||
} | ||
async send(method, params, chainId) { | ||
return this.request({ | ||
method, | ||
params: params, | ||
chainId | ||
}); | ||
} | ||
async getNetwork() { | ||
const chainId = _classPrivateFieldBase(this, _chainId)[_chainId]; | ||
const chainId = this._chainId; | ||
if (chainId) { | ||
@@ -866,10 +880,10 @@ const network = networks[chainId]; | ||
const ensAddress = network == null ? void 0 : network.ensAddress; | ||
return ethers.Network.from({ | ||
name, | ||
chainId, | ||
ensAddress | ||
}); | ||
return { | ||
name: name, | ||
chainId: chainId, | ||
ensAddress: ensAddress | ||
}; | ||
} else { | ||
const chainIdHex = await this.send('eth_chainId', []); | ||
_classPrivateFieldBase(this, _chainId)[_chainId] = Number(chainIdHex); | ||
this._chainId = ethers.BigNumber.from(chainIdHex).toNumber(); | ||
return this.getNetwork(); | ||
@@ -890,2 +904,2 @@ } | ||
export { AllowProvider, CachedProvider, EagerProvider, JsonRpcHandler, JsonRpcProvider, JsonRpcRouter, PublicProvider, SigningProvider, SingleflightMiddleware, allNetworks, allowProviderMiddleware, checkNetworkConfig, createJsonRpcMiddlewareStack, ensureUniqueNetworks, ensureValidNetworks, exceptionProviderMiddleware, findNetworkConfig, findSupportedNetwork, getChainId, hardhatNetworks, indexerURL, isJsonRpcProvider, isJsonRpcSender, isNetworkConfig, isValidNetworkConfig, loggingProviderMiddleware, maybeChainId, networkProviderMiddleware, networksIndex, nodesURL, relayerURL, sortNetworks, stringTemplate, toChainIdNumber, updateNetworkConfig, validateAndSortNetworks }; | ||
export { AllowProvider, CachedProvider, EagerProvider, JsonRpcExternalProvider, JsonRpcProvider, JsonRpcRouter, JsonRpcSender, JsonRpcVersion, PublicProvider, SigningProvider, SingleflightMiddleware, allNetworks, allowProviderMiddleware, checkNetworkConfig, createJsonRpcMiddlewareStack, ensureUniqueNetworks, ensureValidNetworks, exceptionProviderMiddleware, findNetworkConfig, findSupportedNetwork, getChainId, hardhatNetworks, indexerURL, isJsonRpcHandler, isJsonRpcProvider, isNetworkConfig, isValidNetworkConfig, loggingProviderMiddleware, maybeChainId, networkProviderMiddleware, networksIndex, nodesURL, relayerURL, sortNetworks, stringTemplate, toChainIdNumber, updateNetworkConfig, validateAndSortNetworks }; |
@@ -1,2 +0,2 @@ | ||
import { ethers } from 'ethers'; | ||
import { BigNumberish, ethers, providers } from 'ethers'; | ||
import { Indexer } from '@0xsequence/indexer'; | ||
@@ -7,3 +7,3 @@ import { Relayer, RpcRelayerOptions } from '@0xsequence/relayer'; | ||
rpcUrl: string; | ||
provider?: ethers.Provider; | ||
provider?: providers.Provider; | ||
indexerUrl?: string; | ||
@@ -19,4 +19,4 @@ indexer?: Indexer; | ||
export declare function findSupportedNetwork(chainIdOrName: string | ChainIdLike): NetworkConfig | undefined; | ||
export type ChainIdLike = NetworkConfig | ethers.BigNumberish; | ||
export declare function toChainIdNumber(chainIdLike: ChainIdLike): bigint; | ||
export type ChainIdLike = NetworkConfig | BigNumberish; | ||
export declare function toChainIdNumber(chainIdLike: ChainIdLike): ethers.BigNumber; | ||
export declare const hardhatNetworks: { | ||
@@ -23,0 +23,0 @@ rpcUrl: string; |
import { ethers } from 'ethers'; | ||
import { JsonRpcMiddleware, JsonRpcMiddlewareHandler, EIP1193Provider, JsonRpcSender } from "./json-rpc/index.js"; | ||
import { JsonRpcMiddleware, JsonRpcMiddlewareHandler } from "./json-rpc/index.js"; | ||
export interface JsonRpcProviderOptions { | ||
@@ -8,14 +8,9 @@ chainId?: number; | ||
} | ||
export declare class JsonRpcProvider extends ethers.JsonRpcProvider implements EIP1193Provider, JsonRpcSender { | ||
#private; | ||
url: string | ethers.FetchRequest | undefined; | ||
constructor(url: string | ethers.FetchRequest | undefined, options?: JsonRpcProviderOptions, jsonRpcApiProviderOptions?: ethers.JsonRpcApiProviderOptions); | ||
request(request: { | ||
method: string; | ||
params?: any[]; | ||
chainId?: number; | ||
}): Promise<any>; | ||
send(method: string, params?: any[] | Record<string, any>, chainId?: number): Promise<any>; | ||
getNetwork(): Promise<ethers.Network>; | ||
export declare class JsonRpcProvider extends ethers.providers.JsonRpcProvider { | ||
private _chainId?; | ||
private _sender; | ||
constructor(url: ethers.utils.ConnectionInfo | string, options?: JsonRpcProviderOptions); | ||
getNetwork(): Promise<ethers.providers.Network>; | ||
send: (method: string, params: Array<any>) => Promise<any>; | ||
private fetch; | ||
} |
export * from "./types.js"; | ||
export * from "./router.js"; | ||
export * from "./handler.js"; | ||
export * from "./sender.js"; | ||
export * from "./middleware/index.js"; | ||
export * from "./utils.js"; |
import { JsonRpcRequest, JsonRpcMiddleware, JsonRpcMiddlewareHandler } from "../types.js"; | ||
export declare class AllowProvider implements JsonRpcMiddlewareHandler { | ||
requestHandler: JsonRpcMiddleware; | ||
sendAsyncMiddleware: JsonRpcMiddleware; | ||
private isAllowedFunc; | ||
@@ -5,0 +5,0 @@ constructor(isAllowedFunc?: (request: JsonRpcRequest) => boolean); |
@@ -1,2 +0,2 @@ | ||
import { EIP1193ProviderFunc, JsonRpcRequest, JsonRpcMiddlewareHandler } from "../types.js"; | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from "../types.js"; | ||
export interface CachedProviderOptions { | ||
@@ -15,3 +15,3 @@ defaultChainId?: number; | ||
constructor(options?: CachedProviderOptions); | ||
requestHandler: (next: EIP1193ProviderFunc) => (request: JsonRpcRequest) => Promise<any>; | ||
sendAsyncMiddleware: (next: JsonRpcHandlerFunc) => (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
cacheKey: (method: string, params: any[], chainId?: number) => string; | ||
@@ -27,5 +27,5 @@ getCache: () => { | ||
setCacheByBlockValue: (key: string, value: any) => void; | ||
shouldCacheResponse: (request: JsonRpcRequest, result?: any) => boolean; | ||
shouldCacheResponse: (request: JsonRpcRequest, response?: JsonRpcResponse) => boolean; | ||
onUpdate(callback: (key?: string, value?: any) => void): void; | ||
clearCache: () => void; | ||
} |
import { commons } from '@0xsequence/core'; | ||
import { EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from "../types.js"; | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from "../types.js"; | ||
export type EagerProviderOptions = { | ||
@@ -11,3 +11,3 @@ accountAddress?: string; | ||
constructor(options: EagerProviderOptions); | ||
requestHandler: (next: EIP1193ProviderFunc) => (request: JsonRpcRequest) => Promise<any>; | ||
sendAsyncMiddleware: (next: JsonRpcHandlerFunc) => (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from "../types.js"; | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from "../types.js"; | ||
export declare class PublicProvider implements JsonRpcMiddlewareHandler { | ||
@@ -7,5 +7,5 @@ private privateJsonRpcMethods; | ||
constructor(rpcUrl?: string); | ||
requestHandler: (next: EIP1193ProviderFunc) => (request: JsonRpcRequest) => Promise<any>; | ||
sendAsyncMiddleware: (next: JsonRpcHandlerFunc) => (request: JsonRpcRequest, callback: JsonRpcResponseCallback) => void; | ||
getRpcUrl(): string | undefined; | ||
setRpcUrl(rpcUrl: string): void; | ||
} |
@@ -1,7 +0,7 @@ | ||
import { EIP1193Provider, EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from "../types.js"; | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler, JsonRpcHandler } from "../types.js"; | ||
export declare const SignerJsonRpcMethods: string[]; | ||
export declare class SigningProvider implements JsonRpcMiddlewareHandler { | ||
private provider; | ||
constructor(provider: EIP1193Provider); | ||
requestHandler: (next: EIP1193ProviderFunc) => (request: JsonRpcRequest) => Promise<any>; | ||
constructor(provider: JsonRpcHandler); | ||
sendAsyncMiddleware: (next: JsonRpcHandlerFunc) => (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { EIP1193ProviderFunc, JsonRpcResponseCallback, JsonRpcMiddlewareHandler, JsonRpcRequest } from "../types.js"; | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from "../types.js"; | ||
export declare class SingleflightMiddleware implements JsonRpcMiddlewareHandler { | ||
@@ -11,4 +11,4 @@ private singleflightJsonRpcMethods; | ||
constructor(); | ||
requestHandler: (next: EIP1193ProviderFunc) => (request: JsonRpcRequest) => Promise<any>; | ||
sendAsyncMiddleware: (next: JsonRpcHandlerFunc) => (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
requestKey: (method: string, params: any[], chainId?: number) => string; | ||
} |
@@ -1,14 +0,9 @@ | ||
import { EIP1193Provider, JsonRpcMiddleware, JsonRpcMiddlewareHandler } from "./types.js"; | ||
export declare class JsonRpcRouter implements EIP1193Provider { | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcHandler, JsonRpcMiddleware, JsonRpcMiddlewareHandler } from "./types.js"; | ||
export declare class JsonRpcRouter implements JsonRpcHandler { | ||
private sender; | ||
private handler; | ||
constructor(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, sender: EIP1193Provider); | ||
constructor(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, sender: JsonRpcHandler); | ||
setMiddleware(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>): void; | ||
request(request: { | ||
id?: number; | ||
method: string; | ||
params?: any[]; | ||
chainId?: number; | ||
}): Promise<any>; | ||
sendAsync(request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number): void; | ||
} | ||
export declare const createJsonRpcMiddlewareStack: (middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, handler: EIP1193Provider) => EIP1193Provider; | ||
export declare const createJsonRpcMiddlewareStack: (middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, handler: JsonRpcHandlerFunc) => JsonRpcHandlerFunc; |
@@ -1,40 +0,33 @@ | ||
export type JsonRpcRequest = { | ||
jsonrpc?: '2.0'; | ||
export declare const JsonRpcVersion = "2.0"; | ||
export interface JsonRpcRequest { | ||
jsonrpc?: string; | ||
id?: number; | ||
method: string; | ||
params?: any[]; | ||
chainId?: number; | ||
}; | ||
export type JsonRpcResponse = { | ||
jsonrpc?: string; | ||
} | ||
export interface JsonRpcResponse { | ||
jsonrpc: string; | ||
id: number; | ||
result: any; | ||
error?: JsonRpcErrorPayload; | ||
}; | ||
export type JsonRpcErrorPayload = { | ||
code: number; | ||
message?: string; | ||
data?: any; | ||
}; | ||
export interface EIP1193Provider<R = any> { | ||
request(request: { | ||
method: string; | ||
params?: any[]; | ||
chainId?: number; | ||
}): Promise<R>; | ||
error?: ProviderRpcError; | ||
} | ||
export type EIP1193ProviderFunc<R = any> = (request: { | ||
export type JsonRpcResponseCallback = (error?: ProviderRpcError, response?: JsonRpcResponse) => void; | ||
export type JsonRpcHandlerFunc = (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
export interface JsonRpcHandler { | ||
sendAsync: JsonRpcHandlerFunc; | ||
} | ||
export type JsonRpcFetchFunc = (method: string, params?: any[], chainId?: number) => Promise<any>; | ||
export type JsonRpcRequestFunc = (request: { | ||
method: string; | ||
params?: any[]; | ||
chainId?: number; | ||
}) => Promise<R>; | ||
export interface JsonRpcSender<R = any> { | ||
send(method: string, params?: any[], chainId?: number): Promise<R>; | ||
} | ||
export type JsonRpcSendFunc<R = any> = (method: string, params?: any[], chainId?: number) => Promise<R>; | ||
export type JsonRpcResponseCallback = (error: JsonRpcErrorPayload | undefined, response?: JsonRpcResponse) => void; | ||
export type JsonRpcSendAsyncFunc = (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void; | ||
export type JsonRpcMiddleware = (next: EIP1193ProviderFunc) => EIP1193ProviderFunc; | ||
}, chainId?: number) => Promise<any>; | ||
export type JsonRpcMiddleware = (next: JsonRpcHandlerFunc) => JsonRpcHandlerFunc; | ||
export interface JsonRpcMiddlewareHandler { | ||
requestHandler: JsonRpcMiddleware; | ||
sendAsyncMiddleware: JsonRpcMiddleware; | ||
} | ||
export interface ProviderRpcError extends Error { | ||
code?: number; | ||
data?: { | ||
[key: string]: any; | ||
}; | ||
} |
@@ -1,4 +0,4 @@ | ||
import { ethers } from 'ethers'; | ||
import { JsonRpcSender } from "./types.js"; | ||
export declare function isJsonRpcProvider(cand: any): cand is ethers.JsonRpcProvider; | ||
export declare function isJsonRpcSender(cand: any): cand is JsonRpcSender; | ||
import { providers } from 'ethers'; | ||
import { JsonRpcHandler } from "./types.js"; | ||
export declare function isJsonRpcProvider(cand: any): cand is providers.JsonRpcProvider; | ||
export declare function isJsonRpcHandler(cand: any): cand is JsonRpcHandler; |
{ | ||
"name": "@0xsequence/network", | ||
"version": "0.0.0-20240812142652", | ||
"version": "0.0.0-20240814043648", | ||
"description": "network sub-package for Sequence", | ||
@@ -12,12 +12,12 @@ "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/network", | ||
"dependencies": { | ||
"@0xsequence/core": "0.0.0-20240812142652", | ||
"@0xsequence/indexer": "0.0.0-20240812142652", | ||
"@0xsequence/relayer": "0.0.0-20240812142652", | ||
"@0xsequence/utils": "0.0.0-20240812142652" | ||
"@0xsequence/core": "0.0.0-20240814043648", | ||
"@0xsequence/indexer": "0.0.0-20240814043648", | ||
"@0xsequence/relayer": "0.0.0-20240814043648", | ||
"@0xsequence/utils": "0.0.0-20240814043648" | ||
}, | ||
"peerDependencies": { | ||
"ethers": ">=6" | ||
"ethers": ">=5.5 < 6" | ||
}, | ||
"devDependencies": { | ||
"ethers": "^6.13.0" | ||
"ethers": "^5.7.2" | ||
}, | ||
@@ -24,0 +24,0 @@ "files": [ |
@@ -1,2 +0,2 @@ | ||
import { ethers } from 'ethers' | ||
import { BigNumberish, ethers, providers } from 'ethers' | ||
import { Indexer } from '@0xsequence/indexer' | ||
@@ -10,3 +10,3 @@ import { Relayer, RpcRelayerOptions } from '@0xsequence/relayer' | ||
rpcUrl: string | ||
provider?: ethers.Provider | ||
provider?: providers.Provider | ||
indexerUrl?: string | ||
@@ -34,6 +34,6 @@ indexer?: Indexer | ||
export type ChainIdLike = NetworkConfig | ethers.BigNumberish | ||
export type ChainIdLike = NetworkConfig | BigNumberish | ||
export function toChainIdNumber(chainIdLike: ChainIdLike): bigint { | ||
if (typeof chainIdLike === 'bigint') { | ||
export function toChainIdNumber(chainIdLike: ChainIdLike): ethers.BigNumber { | ||
if (ethers.BigNumber.isBigNumber(chainIdLike)) { | ||
return chainIdLike | ||
@@ -43,6 +43,6 @@ } | ||
if (isBigNumberish(chainIdLike)) { | ||
return BigInt(chainIdLike) | ||
return ethers.BigNumber.from(chainIdLike) | ||
} | ||
return BigInt(chainIdLike.chainId) | ||
return ethers.BigNumber.from(chainIdLike.chainId) | ||
} | ||
@@ -49,0 +49,0 @@ |
import { ethers } from 'ethers' | ||
import { | ||
JsonRpcRouter, | ||
JsonRpcSender, | ||
loggingProviderMiddleware, | ||
EagerProvider, | ||
@@ -8,7 +10,3 @@ SingleflightMiddleware, | ||
JsonRpcMiddleware, | ||
JsonRpcMiddlewareHandler, | ||
JsonRpcHandler, | ||
EIP1193Provider, | ||
JsonRpcSender, | ||
JsonRpcRequest | ||
JsonRpcMiddlewareHandler | ||
} from './json-rpc' | ||
@@ -29,13 +27,8 @@ import { ChainId, networks } from './constants' | ||
// JsonRpcProvider with a middleware stack. By default it will use a simple caching middleware. | ||
export class JsonRpcProvider extends ethers.JsonRpcProvider implements EIP1193Provider, JsonRpcSender { | ||
#chainId?: number | ||
#nextId: number = 1 | ||
#sender: EIP1193Provider | ||
export class JsonRpcProvider extends ethers.providers.JsonRpcProvider { | ||
private _chainId?: number | ||
private _sender: JsonRpcSender | ||
constructor( | ||
public url: string | ethers.FetchRequest | undefined, | ||
options?: JsonRpcProviderOptions, | ||
jsonRpcApiProviderOptions?: ethers.JsonRpcApiProviderOptions | ||
) { | ||
super(url, options?.chainId, jsonRpcApiProviderOptions) | ||
constructor(url: ethers.utils.ConnectionInfo | string, options?: JsonRpcProviderOptions) { | ||
super(url, options?.chainId) | ||
@@ -46,3 +39,3 @@ const chainId = options?.chainId | ||
this.#chainId = chainId | ||
this._chainId = chainId | ||
@@ -60,18 +53,10 @@ // NOTE: it will either use the middleware stack passed to the constructor | ||
], | ||
new JsonRpcHandler(this.fetch, chainId) | ||
new JsonRpcSender(this.fetch, chainId) | ||
) | ||
this.#sender = router | ||
this._sender = new JsonRpcSender(router, chainId) | ||
} | ||
async request(request: { method: string; params?: any[]; chainId?: number }): Promise<any> { | ||
return this.#sender.request(request) | ||
} | ||
async send(method: string, params?: any[] | Record<string, any>, chainId?: number): Promise<any> { | ||
return this.request({ method, params: params as any, chainId }) | ||
} | ||
async getNetwork(): Promise<ethers.Network> { | ||
const chainId = this.#chainId | ||
async getNetwork(): Promise<ethers.providers.Network> { | ||
const chainId = this._chainId | ||
if (chainId) { | ||
@@ -81,10 +66,10 @@ const network = networks[chainId as ChainId] | ||
const ensAddress = network?.ensAddress | ||
return ethers.Network.from({ | ||
name, | ||
chainId, | ||
ensAddress | ||
}) | ||
return { | ||
name: name, | ||
chainId: chainId, | ||
ensAddress: ensAddress | ||
} | ||
} else { | ||
const chainIdHex = await this.send('eth_chainId', []) | ||
this.#chainId = Number(chainIdHex) | ||
this._chainId = ethers.BigNumber.from(chainIdHex).toNumber() | ||
return this.getNetwork() | ||
@@ -94,51 +79,24 @@ } | ||
private fetch = async (request: { method: string; params?: any[]; chainId?: number }): Promise<any> => { | ||
if (this.url === undefined) { | ||
throw new Error('missing provider URL') | ||
} | ||
send = (method: string, params: Array<any>): Promise<any> => { | ||
return this._sender.send(method, params) | ||
} | ||
const { method, params } = request | ||
const jsonRpcRequest: JsonRpcRequest = { | ||
method, | ||
params, | ||
id: this.#nextId++, | ||
private fetch = (method: string, params: Array<any>): Promise<any> => { | ||
const request = { | ||
method: method, | ||
params: params, | ||
id: this._nextId++, | ||
jsonrpc: '2.0' | ||
} | ||
// const result = ethers.fetchJson(this.connection, JSON.stringify(request), getResult).then( | ||
// result => { | ||
// return result | ||
// }, | ||
// error => { | ||
// throw error | ||
// } | ||
// ) | ||
const fetchRequest = typeof this.url === 'string' ? new ethers.FetchRequest(this.url) : this.url | ||
fetchRequest.body = JSON.stringify(jsonRpcRequest) | ||
// TODOXXX: what about headers, etc..? | ||
// we probably need these in the options of the construtor, etc.. | ||
try { | ||
const res = await fetchRequest.send() | ||
if (res.body) { | ||
try { | ||
const result = JSON.parse(ethers.toUtf8String(res.body)) | ||
// TODO: Process result | ||
return getResult(result) | ||
} catch (err) { | ||
throw new Error('invalid JSON response') | ||
} | ||
const result = ethers.utils.fetchJson(this.connection, JSON.stringify(request), getResult).then( | ||
result => { | ||
return result | ||
}, | ||
error => { | ||
throw error | ||
} | ||
) | ||
return null | ||
} catch (err) { | ||
// TODO - error handling | ||
throw err | ||
} | ||
return result | ||
} | ||
@@ -145,0 +103,0 @@ } |
export * from './types' | ||
export * from './router' | ||
export * from './handler' | ||
export * from './sender' | ||
export * from './middleware' | ||
export * from './utils' |
@@ -1,5 +0,11 @@ | ||
import { JsonRpcRequest, EIP1193ProviderFunc, JsonRpcMiddleware, JsonRpcMiddlewareHandler } from '../types' | ||
import { | ||
JsonRpcHandlerFunc, | ||
JsonRpcRequest, | ||
JsonRpcResponseCallback, | ||
JsonRpcMiddleware, | ||
JsonRpcMiddlewareHandler | ||
} from '../types' | ||
export class AllowProvider implements JsonRpcMiddlewareHandler { | ||
requestHandler: JsonRpcMiddleware | ||
sendAsyncMiddleware: JsonRpcMiddleware | ||
@@ -15,3 +21,3 @@ private isAllowedFunc: (request: JsonRpcRequest) => boolean | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc) | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc) | ||
} | ||
@@ -21,3 +27,3 @@ | ||
this.isAllowedFunc = fn | ||
this.requestHandler = allowProviderMiddleware(this.isAllowedFunc) | ||
this.sendAsyncMiddleware = allowProviderMiddleware(this.isAllowedFunc) | ||
} | ||
@@ -28,4 +34,4 @@ } | ||
(isAllowed: (request: JsonRpcRequest) => boolean): JsonRpcMiddleware => | ||
(next: EIP1193ProviderFunc) => { | ||
return (request: JsonRpcRequest): Promise<any> => { | ||
(next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
// ensure precondition is met or do not allow the request to continue | ||
@@ -37,4 +43,4 @@ if (!isAllowed(request)) { | ||
// request is allowed. keep going.. | ||
return next(request) | ||
next(request, callback, chainId) | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { EIP1193ProviderFunc, JsonRpcRequest, JsonRpcMiddlewareHandler } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from '../types' | ||
@@ -55,13 +55,15 @@ export interface CachedProviderOptions { | ||
requestHandler = (next: EIP1193ProviderFunc) => { | ||
return async (request: JsonRpcRequest): Promise<any> => { | ||
sendAsyncMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
// Respond early with cached result | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
const key = this.cacheKey(request.method, request.params! as any[], request.chainId || this.defaultChainId) | ||
const key = this.cacheKey(request.method, request.params!, chainId || this.defaultChainId) | ||
const result = this.getCacheValue(key) | ||
if (result && result !== '') { | ||
return { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id!, | ||
result | ||
} | ||
result: result | ||
}) | ||
return | ||
} | ||
@@ -71,19 +73,27 @@ } | ||
// Continue down the handler chain | ||
const result = await next(request) | ||
next( | ||
request, | ||
(error: any, response?: JsonRpcResponse, chainId?: number) => { | ||
// Store result in cache and continue | ||
if ( | ||
this.cachableJsonRpcMethods.includes(request.method) || | ||
this.cachableJsonRpcMethodsByBlock.includes(request.method) | ||
) { | ||
if (response && response.result && this.shouldCacheResponse(request, response)) { | ||
// cache the value | ||
const key = this.cacheKey(request.method, request.params!, chainId || this.defaultChainId) | ||
// Store result in cache and continue | ||
if (this.cachableJsonRpcMethods.includes(request.method) || this.cachableJsonRpcMethodsByBlock.includes(request.method)) { | ||
if (result && this.shouldCacheResponse(request, result)) { | ||
// cache the value | ||
const key = this.cacheKey(request.method, request.params! as any[], request.chainId || this.defaultChainId) | ||
if (this.cachableJsonRpcMethods.includes(request.method)) { | ||
this.setCacheValue(key, result) | ||
} else { | ||
this.setCacheByBlockValue(key, result) | ||
if (this.cachableJsonRpcMethods.includes(request.method)) { | ||
this.setCacheValue(key, response.result) | ||
} else { | ||
this.setCacheByBlockValue(key, response.result) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return result | ||
// Exec next handler | ||
callback(error, response) | ||
}, | ||
chainId || this.defaultChainId | ||
) | ||
} | ||
@@ -144,5 +154,5 @@ } | ||
shouldCacheResponse = (request: JsonRpcRequest, result?: any): boolean => { | ||
shouldCacheResponse = (request: JsonRpcRequest, response?: JsonRpcResponse): boolean => { | ||
// skip if we do not have response result | ||
if (!result) { | ||
if (!response || !response.result) { | ||
return false | ||
@@ -152,3 +162,3 @@ } | ||
// skip caching eth_getCode where resposne value is '0x' or empty | ||
if (request.method === 'eth_getCode' && result.length <= 2) { | ||
if (request.method === 'eth_getCode' && response.result.length <= 2) { | ||
return false | ||
@@ -155,0 +165,0 @@ } |
import { commons } from '@0xsequence/core' | ||
import { ethers } from 'ethers' | ||
import { EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcResponse, JsonRpcMiddlewareHandler } from '../types' | ||
@@ -23,8 +23,11 @@ // EagerProvider will eagerly respond to a provider request from pre-initialized data values. | ||
requestHandler = (next: EIP1193ProviderFunc) => { | ||
return async (request: JsonRpcRequest): Promise<any> => { | ||
switch (request.method) { | ||
sendAsyncMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
const { id, method } = request | ||
switch (method) { | ||
case 'net_version': | ||
if (this.options.chainId) { | ||
return `${this.options.chainId}` | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: `${this.options.chainId}` }) | ||
return | ||
} | ||
@@ -35,3 +38,4 @@ break | ||
if (this.options.chainId) { | ||
return ethers.toQuantity(this.options.chainId) | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: ethers.utils.hexlify(this.options.chainId) }) | ||
return | ||
} | ||
@@ -42,3 +46,4 @@ break | ||
if (this.options.accountAddress) { | ||
return [ethers.getAddress(this.options.accountAddress)] | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: [ethers.utils.getAddress(this.options.accountAddress)] }) | ||
return | ||
} | ||
@@ -49,3 +54,4 @@ break | ||
if (this.options.walletContext) { | ||
return this.options.walletContext | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: this.options.walletContext }) | ||
return | ||
} | ||
@@ -57,5 +63,5 @@ break | ||
return next(request) | ||
next(request, callback, chainId) | ||
} | ||
} | ||
} |
@@ -1,15 +0,21 @@ | ||
import { EIP1193ProviderFunc, JsonRpcMiddleware } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseCallback, JsonRpcMiddleware } from '../types' | ||
export const exceptionProviderMiddleware: JsonRpcMiddleware = (next: EIP1193ProviderFunc) => { | ||
return async (request: { method: string; params?: any[]; chainId?: number }): Promise<any> => { | ||
try { | ||
return await next(request) | ||
} catch (error) { | ||
if (typeof error === 'string') { | ||
throw new Error(error) | ||
} else { | ||
throw new Error(error.message) | ||
} | ||
} | ||
export const exceptionProviderMiddleware: JsonRpcMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
next( | ||
request, | ||
(error: any, response?: JsonRpcResponse) => { | ||
if (!error && response && response.error) { | ||
if (typeof response.error === 'string') { | ||
throw new Error(response.error) | ||
} else { | ||
throw new Error(response.error.message) | ||
} | ||
} | ||
callback(error, response) | ||
}, | ||
chainId | ||
) | ||
} | ||
} |
@@ -1,30 +0,33 @@ | ||
import { EIP1193ProviderFunc, JsonRpcMiddleware, JsonRpcRequest } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseCallback, JsonRpcMiddleware } from '../types' | ||
import { logger } from '@0xsequence/utils' | ||
// TODO: rename to loggerMiddleware | ||
export const loggingProviderMiddleware: JsonRpcMiddleware = (next: EIP1193ProviderFunc) => { | ||
return async (request: JsonRpcRequest): Promise<any> => { | ||
const chainIdLabel = request.chainId ? ` chainId:${request.chainId}` : '' | ||
export const loggingProviderMiddleware: JsonRpcMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
const chainIdLabel = chainId ? ` chainId:${chainId}` : '' | ||
logger.info(`[provider request]${chainIdLabel} id:${request.id} method:${request.method} params:`, request.params) | ||
try { | ||
const result = await next(request) | ||
logger.info( | ||
`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, | ||
request.params, | ||
`result:`, | ||
result | ||
) | ||
return result | ||
} catch (error) { | ||
logger.warn( | ||
`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, | ||
request.params, | ||
`error:`, | ||
error | ||
) | ||
} | ||
next( | ||
request, | ||
(error: any, response?: JsonRpcResponse) => { | ||
if (error) { | ||
logger.warn( | ||
`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, | ||
request.params, | ||
`error:`, | ||
error | ||
) | ||
} else { | ||
logger.info( | ||
`[provider response]${chainIdLabel} id:${request.id} method:${request.method} params:`, | ||
request.params, | ||
`response:`, | ||
response | ||
) | ||
} | ||
callback(error, response) | ||
}, | ||
chainId | ||
) | ||
} | ||
} |
import { ethers } from 'ethers' | ||
import { EIP1193ProviderFunc, JsonRpcRequest, JsonRpcMiddleware } from '../types' | ||
import { | ||
JsonRpcHandlerFunc, | ||
JsonRpcRequest, | ||
JsonRpcResponseCallback, | ||
JsonRpcMiddleware, | ||
JsonRpcMiddlewareHandler | ||
} from '../types' | ||
export const networkProviderMiddleware = | ||
(getChainId: (request: JsonRpcRequest) => number): JsonRpcMiddleware => | ||
(next: EIP1193ProviderFunc) => { | ||
return async (request: JsonRpcRequest): Promise<any> => { | ||
(next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
const networkChainId = getChainId(request) | ||
switch (request.method) { | ||
case 'net_version': { | ||
return `${networkChainId}` | ||
} | ||
const { id, method } = request | ||
case 'eth_chainId': { | ||
return ethers.toQuantity(networkChainId) | ||
} | ||
switch (method) { | ||
case 'net_version': | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: `${networkChainId}` }) | ||
return | ||
case 'eth_chainId': | ||
callback(undefined, { jsonrpc: '2.0', id: id!, result: ethers.utils.hexlify(networkChainId) }) | ||
return | ||
default: | ||
} | ||
// request is allowed. keep going.. | ||
return next(request) | ||
next(request, callback, chainId) | ||
} | ||
} |
@@ -1,3 +0,3 @@ | ||
import { ethers } from 'ethers' | ||
import { EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from '../types' | ||
import { providers } from 'ethers' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from '../types' | ||
import { SignerJsonRpcMethods } from './signing-provider' | ||
@@ -9,3 +9,3 @@ import { logger } from '@0xsequence/utils' | ||
private provider?: ethers.JsonRpcProvider | ||
private provider?: providers.JsonRpcProvider | ||
private rpcUrl?: string | ||
@@ -19,7 +19,17 @@ | ||
requestHandler = (next: EIP1193ProviderFunc) => { | ||
return (request: JsonRpcRequest): Promise<any> => { | ||
sendAsyncMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback) => { | ||
// When provider is configured, send non-private methods to our local public provider | ||
if (this.provider && !this.privateJsonRpcMethods.includes(request.method)) { | ||
return this.provider.send(request.method, request.params || []) | ||
this.provider | ||
.send(request.method, request.params!) | ||
.then(r => { | ||
callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: request.id!, | ||
result: r | ||
}) | ||
}) | ||
.catch(e => callback(e)) | ||
return | ||
} | ||
@@ -29,3 +39,3 @@ | ||
logger.debug('[public-provider] sending request to signer window', request.method) | ||
return next(request) | ||
next(request, callback) | ||
} | ||
@@ -46,5 +56,5 @@ } | ||
// which supports better caching. | ||
this.provider = new ethers.JsonRpcProvider(rpcUrl) | ||
this.provider = new providers.JsonRpcProvider(rpcUrl) | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { EIP1193Provider, EIP1193ProviderFunc, JsonRpcMiddlewareHandler, JsonRpcRequest } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponseCallback, JsonRpcMiddlewareHandler, JsonRpcHandler } from '../types' | ||
@@ -33,19 +33,20 @@ export const SignerJsonRpcMethods = [ | ||
export class SigningProvider implements JsonRpcMiddlewareHandler { | ||
private provider: EIP1193Provider | ||
private provider: JsonRpcHandler | ||
constructor(provider: EIP1193Provider) { | ||
constructor(provider: JsonRpcHandler) { | ||
this.provider = provider | ||
} | ||
requestHandler = (next: EIP1193ProviderFunc) => { | ||
return (request: JsonRpcRequest): Promise<any> => { | ||
sendAsyncMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
// Forward signing requests to the signing provider | ||
if (SignerJsonRpcMethods.includes(request.method)) { | ||
return this.provider.request(request) | ||
this.provider.sendAsync(request, callback, chainId) | ||
return | ||
} | ||
// Continue to next handler | ||
return next(request) | ||
next(request, callback, chainId) | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { EIP1193ProviderFunc, JsonRpcResponseCallback, JsonRpcMiddlewareHandler, JsonRpcRequest } from '../types' | ||
import { JsonRpcHandlerFunc, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseCallback, JsonRpcMiddlewareHandler } from '../types' | ||
@@ -34,10 +34,11 @@ export class SingleflightMiddleware implements JsonRpcMiddlewareHandler { | ||
requestHandler = (next: EIP1193ProviderFunc) => { | ||
return async (request: JsonRpcRequest): Promise<any> => { | ||
sendAsyncMiddleware = (next: JsonRpcHandlerFunc) => { | ||
return (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => { | ||
// continue to next handler if method isn't part of methods list | ||
if (!this.singleflightJsonRpcMethods.includes(request.method)) { | ||
return next(request) | ||
next(request, callback, chainId) | ||
return | ||
} | ||
const key = this.requestKey(request.method, request.params || [], request.chainId) | ||
const key = this.requestKey(request.method, request.params || [], chainId) | ||
@@ -49,29 +50,33 @@ if (!this.inflight[key]) { | ||
// already in-flight, add the callback to the list and return | ||
return new Promise<any>((resolve, reject) => { | ||
this.inflight[key].push({ | ||
id: request.id!, | ||
callback: (error: any, response: any) => { | ||
if (error) { | ||
reject(error) | ||
} else { | ||
resolve(response) | ||
} | ||
} | ||
}) | ||
}) | ||
this.inflight[key].push({ id: request.id!, callback }) | ||
return | ||
} | ||
// Continue down the handler chain | ||
try { | ||
// Exec the handler, and on success resolve all other promises | ||
const response = await next(request) | ||
this.inflight[key].forEach(({ callback }) => callback(undefined, response)) | ||
return response | ||
} catch (error) { | ||
// If the request fails, reject all queued promises. | ||
this.inflight[key].forEach(({ callback }) => callback(error, undefined)) | ||
throw error | ||
} finally { | ||
delete this.inflight[key] | ||
} | ||
next( | ||
request, | ||
(error: any, response?: JsonRpcResponse, chainId?: number) => { | ||
// callback the original request | ||
callback(error, response) | ||
// callback all other requests of the same kind in queue, with the | ||
// same response result as from the first response. | ||
for (let i = 0; i < this.inflight[key].length; i++) { | ||
const sub = this.inflight[key][i] | ||
if (error) { | ||
sub.callback(error, response) | ||
} else if (response) { | ||
sub.callback(undefined, { | ||
jsonrpc: '2.0', | ||
id: sub.id, | ||
result: response!.result | ||
}) | ||
} | ||
} | ||
// clear request key | ||
delete this.inflight[key] | ||
}, | ||
chainId | ||
) | ||
} | ||
@@ -78,0 +83,0 @@ } |
@@ -1,8 +0,15 @@ | ||
import { EIP1193Provider, EIP1193ProviderFunc, JsonRpcMiddleware, JsonRpcMiddlewareHandler } from './types' | ||
import { | ||
JsonRpcHandlerFunc, | ||
JsonRpcRequest, | ||
JsonRpcResponseCallback, | ||
JsonRpcHandler, | ||
JsonRpcMiddleware, | ||
JsonRpcMiddlewareHandler | ||
} from './types' | ||
export class JsonRpcRouter implements EIP1193Provider { | ||
private sender: EIP1193Provider | ||
private handler: EIP1193Provider | ||
export class JsonRpcRouter implements JsonRpcHandler { | ||
private sender: JsonRpcHandler | ||
private handler: JsonRpcHandlerFunc | ||
constructor(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, sender: EIP1193Provider) { | ||
constructor(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, sender: JsonRpcHandler) { | ||
this.sender = sender | ||
@@ -15,7 +22,11 @@ if (middlewares) { | ||
setMiddleware(middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>) { | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender) | ||
this.handler = createJsonRpcMiddlewareStack(middlewares, this.sender.sendAsync) | ||
} | ||
request(request: { id?: number; method: string; params?: any[]; chainId?: number }): Promise<any> { | ||
return this.handler.request(request) | ||
sendAsync(request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) { | ||
try { | ||
this.handler(request, callback, chainId) | ||
} catch (err) { | ||
callback(err, undefined) | ||
} | ||
} | ||
@@ -26,9 +37,9 @@ } | ||
middlewares: Array<JsonRpcMiddleware | JsonRpcMiddlewareHandler>, | ||
handler: EIP1193Provider | ||
): EIP1193Provider => { | ||
handler: JsonRpcHandlerFunc | ||
): JsonRpcHandlerFunc => { | ||
if (middlewares.length === 0) return handler | ||
const toMiddleware = (v: any): JsonRpcMiddleware => { | ||
if (v.requestHandler) { | ||
return (v as JsonRpcMiddlewareHandler).requestHandler | ||
if (v.sendAsyncMiddleware) { | ||
return (v as JsonRpcMiddlewareHandler).sendAsyncMiddleware | ||
} else { | ||
@@ -39,8 +50,8 @@ return v | ||
let chain: EIP1193ProviderFunc | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler.request) | ||
let chain: JsonRpcHandlerFunc | ||
chain = toMiddleware(middlewares[middlewares.length - 1])(handler) | ||
for (let i = middlewares.length - 2; i >= 0; i--) { | ||
chain = toMiddleware(middlewares[i])(chain) | ||
} | ||
return { request: chain } | ||
return chain | ||
} |
@@ -1,45 +0,39 @@ | ||
export type JsonRpcRequest = { | ||
jsonrpc?: '2.0' | ||
export const JsonRpcVersion = '2.0' | ||
export interface JsonRpcRequest { | ||
jsonrpc?: string | ||
id?: number | ||
method: string | ||
params?: any[] | ||
// ... | ||
chainId?: number | ||
} | ||
export type JsonRpcResponse = { | ||
jsonrpc?: string | ||
export interface JsonRpcResponse { | ||
jsonrpc: string | ||
id: number | ||
result: any | ||
error?: JsonRpcErrorPayload | ||
error?: ProviderRpcError | ||
} | ||
export type JsonRpcErrorPayload = { | ||
code: number | ||
message?: string | ||
data?: any | ||
} | ||
export type JsonRpcResponseCallback = (error?: ProviderRpcError, response?: JsonRpcResponse) => void | ||
// EIP1193Provider with reponse of R (default any), but in most cases R will be of type JsonRpcResponse. | ||
export interface EIP1193Provider<R = any> { | ||
request(request: { method: string; params?: any[]; chainId?: number }): Promise<R> | ||
} | ||
export type JsonRpcHandlerFunc = (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void | ||
export type EIP1193ProviderFunc<R = any> = (request: { method: string; params?: any[]; chainId?: number }) => Promise<R> | ||
export interface JsonRpcSender<R = any> { | ||
send(method: string, params?: any[], chainId?: number): Promise<R> | ||
export interface JsonRpcHandler { | ||
sendAsync: JsonRpcHandlerFunc | ||
} | ||
export type JsonRpcSendFunc<R = any> = (method: string, params?: any[], chainId?: number) => Promise<R> | ||
export type JsonRpcFetchFunc = (method: string, params?: any[], chainId?: number) => Promise<any> | ||
export type JsonRpcResponseCallback = (error: JsonRpcErrorPayload | undefined, response?: JsonRpcResponse) => void | ||
// EIP-1193 function signature | ||
export type JsonRpcRequestFunc = (request: { method: string; params?: any[] }, chainId?: number) => Promise<any> | ||
export type JsonRpcSendAsyncFunc = (request: JsonRpcRequest, callback: JsonRpcResponseCallback, chainId?: number) => void | ||
export type JsonRpcMiddleware = (next: JsonRpcHandlerFunc) => JsonRpcHandlerFunc | ||
export type JsonRpcMiddleware = (next: EIP1193ProviderFunc) => EIP1193ProviderFunc | ||
export interface JsonRpcMiddlewareHandler { | ||
requestHandler: JsonRpcMiddleware | ||
sendAsyncMiddleware: JsonRpcMiddleware | ||
} | ||
export interface ProviderRpcError extends Error { | ||
code?: number | ||
data?: { [key: string]: any } | ||
} |
@@ -1,6 +0,5 @@ | ||
import { ethers } from 'ethers' | ||
import { JsonRpcSender } from './types' | ||
import { providers } from 'ethers' | ||
import { JsonRpcHandler } from './types' | ||
// TODOXXX: review.. | ||
export function isJsonRpcProvider(cand: any): cand is ethers.JsonRpcProvider { | ||
export function isJsonRpcProvider(cand: any): cand is providers.JsonRpcProvider { | ||
return ( | ||
@@ -16,4 +15,4 @@ cand !== undefined && | ||
export function isJsonRpcSender(cand: any): cand is JsonRpcSender { | ||
return cand !== undefined && cand.send !== undefined | ||
export function isJsonRpcHandler(cand: any): cand is JsonRpcHandler { | ||
return cand !== undefined && cand.sendAsync !== undefined | ||
} |
@@ -1,2 +0,2 @@ | ||
import { ethers } from 'ethers' | ||
import { ethers, BigNumberish } from 'ethers' | ||
import { ChainIdLike } from '.' | ||
@@ -16,3 +16,3 @@ import { NetworkConfig } from './config' | ||
} | ||
return Number(chainId as ethers.BigNumberish) | ||
return ethers.BigNumber.from(chainId as BigNumberish).toNumber() | ||
} | ||
@@ -142,3 +142,3 @@ | ||
if (chainId.startsWith('0x')) { | ||
const id = Number(chainId) | ||
const id = ethers.BigNumber.from(chainId).toNumber() | ||
return networks.find(n => n.chainId === id) | ||
@@ -152,4 +152,4 @@ } else { | ||
return networks.find(n => n.chainId === (<NetworkConfig>chainId).chainId) | ||
} else if (typeof chainId === 'bigint') { | ||
const id = Number(chainId) | ||
} else if (ethers.BigNumber.isBigNumber(chainId)) { | ||
const id = chainId.toNumber() | ||
return networks.find(n => n.chainId === id) | ||
@@ -156,0 +156,0 @@ } else { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
248074
6928
+ Added@0xsequence/abi@0.0.0-20240814043648(transitive)
+ Added@0xsequence/core@0.0.0-20240814043648(transitive)
+ Added@0xsequence/indexer@0.0.0-20240814043648(transitive)
+ Added@0xsequence/relayer@0.0.0-20240814043648(transitive)
+ Added@0xsequence/utils@0.0.0-20240814043648(transitive)
+ Added@ethersproject/abi@5.7.0(transitive)
+ Added@ethersproject/abstract-provider@5.7.0(transitive)
+ Added@ethersproject/abstract-signer@5.7.0(transitive)
+ Added@ethersproject/address@5.7.0(transitive)
+ Added@ethersproject/base64@5.7.0(transitive)
+ Added@ethersproject/basex@5.7.0(transitive)
+ Added@ethersproject/bignumber@5.7.0(transitive)
+ Added@ethersproject/bytes@5.7.0(transitive)
+ Added@ethersproject/constants@5.7.0(transitive)
+ Added@ethersproject/contracts@5.7.0(transitive)
+ Added@ethersproject/hash@5.7.0(transitive)
+ Added@ethersproject/hdnode@5.7.0(transitive)
+ Added@ethersproject/json-wallets@5.7.0(transitive)
+ Added@ethersproject/keccak256@5.7.0(transitive)
+ Added@ethersproject/logger@5.7.0(transitive)
+ Added@ethersproject/networks@5.7.1(transitive)
+ Added@ethersproject/pbkdf2@5.7.0(transitive)
+ Added@ethersproject/properties@5.7.0(transitive)
+ Added@ethersproject/providers@5.7.2(transitive)
+ Added@ethersproject/random@5.7.0(transitive)
+ Added@ethersproject/rlp@5.7.0(transitive)
+ Added@ethersproject/sha2@5.7.0(transitive)
+ Added@ethersproject/signing-key@5.7.0(transitive)
+ Added@ethersproject/solidity@5.7.0(transitive)
+ Added@ethersproject/strings@5.7.0(transitive)
+ Added@ethersproject/transactions@5.7.0(transitive)
+ Added@ethersproject/units@5.7.0(transitive)
+ Added@ethersproject/wallet@5.7.0(transitive)
+ Added@ethersproject/web@5.7.1(transitive)
+ Added@ethersproject/wordlists@5.7.0(transitive)
+ Addedaes-js@3.0.0(transitive)
+ Addedbech32@1.1.4(transitive)
+ Addedbn.js@4.12.15.2.1(transitive)
+ Addedbrorand@1.1.0(transitive)
+ Addedelliptic@6.5.4(transitive)
+ Addedethers@5.7.2(transitive)
+ Addedhash.js@1.1.7(transitive)
+ Addedhmac-drbg@1.0.1(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedjs-sha3@0.8.0(transitive)
+ Addedminimalistic-assert@1.0.1(transitive)
+ Addedminimalistic-crypto-utils@1.0.1(transitive)
+ Addedscrypt-js@3.0.1(transitive)
+ Addedws@7.4.6(transitive)
- Removed@0xsequence/abi@0.0.0-20240812142652(transitive)
- Removed@0xsequence/core@0.0.0-20240812142652(transitive)
- Removed@0xsequence/indexer@0.0.0-20240812142652(transitive)
- Removed@0xsequence/relayer@0.0.0-20240812142652(transitive)
- Removed@0xsequence/utils@0.0.0-20240812142652(transitive)
- Removed@adraffy/ens-normalize@1.10.1(transitive)
- Removed@noble/curves@1.2.0(transitive)
- Removed@noble/hashes@1.3.2(transitive)
- Removed@types/node@22.7.5(transitive)
- Removedaes-js@4.0.0-beta.5(transitive)
- Removedethers@6.13.4(transitive)
- Removedtslib@2.7.0(transitive)
- Removedundici-types@6.19.8(transitive)
- Removedws@8.17.1(transitive)