aboutsummaryrefslogtreecommitdiffstats
path: root/packages/subproviders/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/subproviders/src')
-rw-r--r--packages/subproviders/src/globals.d.ts2
-rw-r--r--packages/subproviders/src/index.ts1
-rw-r--r--packages/subproviders/src/subproviders/rpc_subprovider.ts88
-rw-r--r--packages/subproviders/src/subproviders/subprovider.ts26
4 files changed, 104 insertions, 13 deletions
diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts
index 94e63a32d..6af4c7980 100644
--- a/packages/subproviders/src/globals.d.ts
+++ b/packages/subproviders/src/globals.d.ts
@@ -4,3 +4,5 @@ declare module '*.json' {
export default json;
/* tslint:enable */
}
+
+declare module 'json-rpc-error';
diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts
index 71d643f14..9a5597a06 100644
--- a/packages/subproviders/src/index.ts
+++ b/packages/subproviders/src/index.ts
@@ -10,6 +10,7 @@ export { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_sub
export { SignerSubprovider } from './subproviders/signer';
export { RedundantSubprovider } from './subproviders/redundant_subprovider';
export { LedgerSubprovider } from './subproviders/ledger';
+export { RPCSubprovider } from './subproviders/rpc_subprovider';
export { GanacheSubprovider } from './subproviders/ganache';
export { Subprovider } from './subproviders/subprovider';
export { NonceTrackerSubprovider } from './subproviders/nonce_tracker';
diff --git a/packages/subproviders/src/subproviders/rpc_subprovider.ts b/packages/subproviders/src/subproviders/rpc_subprovider.ts
new file mode 100644
index 000000000..87c522271
--- /dev/null
+++ b/packages/subproviders/src/subproviders/rpc_subprovider.ts
@@ -0,0 +1,88 @@
+import { assert } from '@0xproject/assert';
+import { StatusCodes } from '@0xproject/types';
+import { fetchAsync } from '@0xproject/utils';
+import { JSONRPCRequestPayload } from 'ethereum-types';
+import JsonRpcError = require('json-rpc-error');
+
+import { Callback, ErrorCallback } from '../types';
+
+import { Subprovider } from './subprovider';
+
+/**
+ * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface.
+ * It forwards on JSON RPC requests to the supplied `rpcUrl` endpoint
+ */
+export class RPCSubprovider extends Subprovider {
+ private _rpcUrl: string;
+ constructor(rpcUrl: string) {
+ super();
+ assert.isString('rpcUrl', rpcUrl);
+ this._rpcUrl = rpcUrl;
+ }
+ /**
+ * This method conforms to the web3-provider-engine interface.
+ * It is called internally by the ProviderEngine when it is this subproviders
+ * turn to handle a JSON RPC request.
+ * @param payload JSON RPC payload
+ * @param next Callback to call if this subprovider decides not to handle the request
+ * @param end Callback to call if subprovider handled the request and wants to pass back the request.
+ */
+ // tslint:disable-next-line:prefer-function-over-method async-suffix
+ public async handleRequest(payload: JSONRPCRequestPayload, next: Callback, end: ErrorCallback): Promise<void> {
+ const finalPayload = Subprovider.createFinalPayload(payload);
+ const headers = new Headers({
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ });
+ const timeoutMs = 1000;
+
+ let response;
+ try {
+ response = await fetchAsync(
+ this._rpcUrl,
+ {
+ method: 'POST',
+ headers,
+ body: JSON.stringify(finalPayload),
+ },
+ timeoutMs,
+ );
+ } catch (err) {
+ end(new JsonRpcError.InternalError(err));
+ return;
+ }
+
+ const text = await response.text();
+ if (!response.ok) {
+ const statusCode = response.status;
+ switch (statusCode) {
+ case StatusCodes.MethodNotAllowed:
+ end(new JsonRpcError.MethodNotFound());
+ return;
+ case StatusCodes.GatewayTimeout:
+ const errMsg =
+ 'Gateway timeout. The request took too long to process. This can happen when querying logs over too wide a block range.';
+ const err = new Error(errMsg);
+ end(new JsonRpcError.InternalError(err));
+ return;
+ default:
+ end(new JsonRpcError.InternalError(text));
+ return;
+ }
+ }
+
+ let data;
+ try {
+ data = JSON.parse(text);
+ } catch (err) {
+ end(new JsonRpcError.InternalError(err));
+ return;
+ }
+
+ if (data.error) {
+ end(data.error);
+ return;
+ }
+ end(null, data.result);
+ }
+}
diff --git a/packages/subproviders/src/subproviders/subprovider.ts b/packages/subproviders/src/subproviders/subprovider.ts
index ff8378c4e..6f4a8f99e 100644
--- a/packages/subproviders/src/subproviders/subprovider.ts
+++ b/packages/subproviders/src/subproviders/subprovider.ts
@@ -9,18 +9,7 @@ import { Callback, ErrorCallback, JSONRPCRequestPayloadWithMethod } from '../typ
export abstract class Subprovider {
// tslint:disable-next-line:underscore-private-and-protected
private engine!: Provider;
- // Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
- private static _getRandomId(): number {
- const extraDigits = 3;
- const baseTen = 10;
- // 13 time digits
- const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
- // 3 random digits
- const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits));
- // 16 digits
- return datePart + extraPart;
- }
- private static _createFinalPayload(
+ public static createFinalPayload(
payload: Partial<JSONRPCRequestPayloadWithMethod>,
): Partial<JSONRPCRequestPayloadWithMethod> {
const finalPayload = {
@@ -32,6 +21,17 @@ export abstract class Subprovider {
};
return finalPayload;
}
+ // Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js
+ private static _getRandomId(): number {
+ const extraDigits = 3;
+ const baseTen = 10;
+ // 13 time digits
+ const datePart = new Date().getTime() * Math.pow(baseTen, extraDigits);
+ // 3 random digits
+ const extraPart = Math.floor(Math.random() * Math.pow(baseTen, extraDigits));
+ // 16 digits
+ return datePart + extraPart;
+ }
// tslint:disable-next-line:async-suffix
public abstract async handleRequest(
payload: JSONRPCRequestPayload,
@@ -47,7 +47,7 @@ export abstract class Subprovider {
* @returns JSON RPC response payload
*/
public async emitPayloadAsync(payload: Partial<JSONRPCRequestPayloadWithMethod>): Promise<JSONRPCResponsePayload> {
- const finalPayload = Subprovider._createFinalPayload(payload);
+ const finalPayload = Subprovider.createFinalPayload(payload);
const response = await promisify<JSONRPCResponsePayload>(this.engine.sendAsync, this.engine)(finalPayload);
return response;
}