web3-provider.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. "use strict";
  2. import { Networkish } from "@ethersproject/networks";
  3. import { deepCopy, defineReadOnly } from "@ethersproject/properties";
  4. import { Logger } from "@ethersproject/logger";
  5. import { version } from "./_version";
  6. const logger = new Logger(version);
  7. import { JsonRpcProvider } from "./json-rpc-provider";
  8. // Exported Types
  9. export type ExternalProvider = {
  10. isMetaMask?: boolean;
  11. isStatus?: boolean;
  12. host?: string;
  13. path?: string;
  14. sendAsync?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  15. send?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  16. request?: (request: { method: string, params?: Array<any> }) => Promise<any>
  17. }
  18. let _nextId = 1;
  19. export type JsonRpcFetchFunc = (method: string, params?: Array<any>) => Promise<any>;
  20. type Web3LegacySend = (request: any, callback: (error: Error, response: any) => void) => void;
  21. function buildWeb3LegacyFetcher(provider: ExternalProvider, sendFunc: Web3LegacySend) : JsonRpcFetchFunc {
  22. const fetcher = "Web3LegacyFetcher";
  23. return function(method: string, params: Array<any>): Promise<any> {
  24. const request = {
  25. method: method,
  26. params: params,
  27. id: (_nextId++),
  28. jsonrpc: "2.0"
  29. };
  30. return new Promise((resolve, reject) => {
  31. this.emit("debug", {
  32. action: "request",
  33. fetcher,
  34. request: deepCopy(request),
  35. provider: this
  36. });
  37. sendFunc(request, (error, response) => {
  38. if (error) {
  39. this.emit("debug", {
  40. action: "response",
  41. fetcher,
  42. error,
  43. request,
  44. provider: this
  45. });
  46. return reject(error);
  47. }
  48. this.emit("debug", {
  49. action: "response",
  50. fetcher,
  51. request,
  52. response,
  53. provider: this
  54. });
  55. if (response.error) {
  56. const error = new Error(response.error.message);
  57. (<any>error).code = response.error.code;
  58. (<any>error).data = response.error.data;
  59. return reject(error);
  60. }
  61. resolve(response.result);
  62. });
  63. });
  64. }
  65. }
  66. function buildEip1193Fetcher(provider: ExternalProvider): JsonRpcFetchFunc {
  67. return function(method: string, params: Array<any>): Promise<any> {
  68. if (params == null) { params = [ ]; }
  69. const request = { method, params };
  70. this.emit("debug", {
  71. action: "request",
  72. fetcher: "Eip1193Fetcher",
  73. request: deepCopy(request),
  74. provider: this
  75. });
  76. return provider.request(request).then((response) => {
  77. this.emit("debug", {
  78. action: "response",
  79. fetcher: "Eip1193Fetcher",
  80. request,
  81. response,
  82. provider: this
  83. });
  84. return response;
  85. }, (error) => {
  86. this.emit("debug", {
  87. action: "response",
  88. fetcher: "Eip1193Fetcher",
  89. request,
  90. error,
  91. provider: this
  92. });
  93. throw error;
  94. });
  95. }
  96. }
  97. export class Web3Provider extends JsonRpcProvider {
  98. readonly provider: ExternalProvider;
  99. readonly jsonRpcFetchFunc: JsonRpcFetchFunc;
  100. constructor(provider: ExternalProvider | JsonRpcFetchFunc, network?: Networkish) {
  101. logger.checkNew(new.target, Web3Provider);
  102. if (provider == null) {
  103. logger.throwArgumentError("missing provider", "provider", provider);
  104. }
  105. let path: string = null;
  106. let jsonRpcFetchFunc: JsonRpcFetchFunc = null;
  107. let subprovider: ExternalProvider = null;
  108. if (typeof(provider) === "function") {
  109. path = "unknown:";
  110. jsonRpcFetchFunc = provider;
  111. } else {
  112. path = provider.host || provider.path || "";
  113. if (!path && provider.isMetaMask) {
  114. path = "metamask";
  115. }
  116. subprovider = provider;
  117. if (provider.request) {
  118. if (path === "") { path = "eip-1193:"; }
  119. jsonRpcFetchFunc = buildEip1193Fetcher(provider);
  120. } else if (provider.sendAsync) {
  121. jsonRpcFetchFunc = buildWeb3LegacyFetcher(provider, provider.sendAsync.bind(provider));
  122. } else if (provider.send) {
  123. jsonRpcFetchFunc = buildWeb3LegacyFetcher(provider, provider.send.bind(provider));
  124. } else {
  125. logger.throwArgumentError("unsupported provider", "provider", provider);
  126. }
  127. if (!path) { path = "unknown:"; }
  128. }
  129. super(path, network);
  130. defineReadOnly(this, "jsonRpcFetchFunc", jsonRpcFetchFunc);
  131. defineReadOnly(this, "provider", subprovider);
  132. }
  133. send(method: string, params: Array<any>): Promise<any> {
  134. return this.jsonRpcFetchFunc(method, params);
  135. }
  136. }