base-provider.js 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. import { ForkEvent, Provider } from "@ethersproject/abstract-provider";
  12. import { Base58 } from "@ethersproject/basex";
  13. import { BigNumber } from "@ethersproject/bignumber";
  14. import { arrayify, concat, hexConcat, hexDataLength, hexDataSlice, hexlify, hexValue, hexZeroPad, isHexString } from "@ethersproject/bytes";
  15. import { HashZero } from "@ethersproject/constants";
  16. import { dnsEncode, namehash } from "@ethersproject/hash";
  17. import { getNetwork } from "@ethersproject/networks";
  18. import { defineReadOnly, getStatic, resolveProperties } from "@ethersproject/properties";
  19. import { sha256 } from "@ethersproject/sha2";
  20. import { toUtf8Bytes, toUtf8String } from "@ethersproject/strings";
  21. import { fetchJson, poll } from "@ethersproject/web";
  22. import bech32 from "bech32";
  23. import { Logger } from "@ethersproject/logger";
  24. import { version } from "./_version";
  25. const logger = new Logger(version);
  26. import { Formatter } from "./formatter";
  27. const MAX_CCIP_REDIRECTS = 10;
  28. //////////////////////////////
  29. // Event Serializeing
  30. function checkTopic(topic) {
  31. if (topic == null) {
  32. return "null";
  33. }
  34. if (hexDataLength(topic) !== 32) {
  35. logger.throwArgumentError("invalid topic", "topic", topic);
  36. }
  37. return topic.toLowerCase();
  38. }
  39. function serializeTopics(topics) {
  40. // Remove trailing null AND-topics; they are redundant
  41. topics = topics.slice();
  42. while (topics.length > 0 && topics[topics.length - 1] == null) {
  43. topics.pop();
  44. }
  45. return topics.map((topic) => {
  46. if (Array.isArray(topic)) {
  47. // Only track unique OR-topics
  48. const unique = {};
  49. topic.forEach((topic) => {
  50. unique[checkTopic(topic)] = true;
  51. });
  52. // The order of OR-topics does not matter
  53. const sorted = Object.keys(unique);
  54. sorted.sort();
  55. return sorted.join("|");
  56. }
  57. else {
  58. return checkTopic(topic);
  59. }
  60. }).join("&");
  61. }
  62. function deserializeTopics(data) {
  63. if (data === "") {
  64. return [];
  65. }
  66. return data.split(/&/g).map((topic) => {
  67. if (topic === "") {
  68. return [];
  69. }
  70. const comps = topic.split("|").map((topic) => {
  71. return ((topic === "null") ? null : topic);
  72. });
  73. return ((comps.length === 1) ? comps[0] : comps);
  74. });
  75. }
  76. function getEventTag(eventName) {
  77. if (typeof (eventName) === "string") {
  78. eventName = eventName.toLowerCase();
  79. if (hexDataLength(eventName) === 32) {
  80. return "tx:" + eventName;
  81. }
  82. if (eventName.indexOf(":") === -1) {
  83. return eventName;
  84. }
  85. }
  86. else if (Array.isArray(eventName)) {
  87. return "filter:*:" + serializeTopics(eventName);
  88. }
  89. else if (ForkEvent.isForkEvent(eventName)) {
  90. logger.warn("not implemented");
  91. throw new Error("not implemented");
  92. }
  93. else if (eventName && typeof (eventName) === "object") {
  94. return "filter:" + (eventName.address || "*") + ":" + serializeTopics(eventName.topics || []);
  95. }
  96. throw new Error("invalid event - " + eventName);
  97. }
  98. //////////////////////////////
  99. // Helper Object
  100. function getTime() {
  101. return (new Date()).getTime();
  102. }
  103. function stall(duration) {
  104. return new Promise((resolve) => {
  105. setTimeout(resolve, duration);
  106. });
  107. }
  108. //////////////////////////////
  109. // Provider Object
  110. /**
  111. * EventType
  112. * - "block"
  113. * - "poll"
  114. * - "didPoll"
  115. * - "pending"
  116. * - "error"
  117. * - "network"
  118. * - filter
  119. * - topics array
  120. * - transaction hash
  121. */
  122. const PollableEvents = ["block", "network", "pending", "poll"];
  123. export class Event {
  124. constructor(tag, listener, once) {
  125. defineReadOnly(this, "tag", tag);
  126. defineReadOnly(this, "listener", listener);
  127. defineReadOnly(this, "once", once);
  128. this._lastBlockNumber = -2;
  129. this._inflight = false;
  130. }
  131. get event() {
  132. switch (this.type) {
  133. case "tx":
  134. return this.hash;
  135. case "filter":
  136. return this.filter;
  137. }
  138. return this.tag;
  139. }
  140. get type() {
  141. return this.tag.split(":")[0];
  142. }
  143. get hash() {
  144. const comps = this.tag.split(":");
  145. if (comps[0] !== "tx") {
  146. return null;
  147. }
  148. return comps[1];
  149. }
  150. get filter() {
  151. const comps = this.tag.split(":");
  152. if (comps[0] !== "filter") {
  153. return null;
  154. }
  155. const address = comps[1];
  156. const topics = deserializeTopics(comps[2]);
  157. const filter = {};
  158. if (topics.length > 0) {
  159. filter.topics = topics;
  160. }
  161. if (address && address !== "*") {
  162. filter.address = address;
  163. }
  164. return filter;
  165. }
  166. pollable() {
  167. return (this.tag.indexOf(":") >= 0 || PollableEvents.indexOf(this.tag) >= 0);
  168. }
  169. }
  170. ;
  171. // https://github.com/satoshilabs/slips/blob/master/slip-0044.md
  172. const coinInfos = {
  173. "0": { symbol: "btc", p2pkh: 0x00, p2sh: 0x05, prefix: "bc" },
  174. "2": { symbol: "ltc", p2pkh: 0x30, p2sh: 0x32, prefix: "ltc" },
  175. "3": { symbol: "doge", p2pkh: 0x1e, p2sh: 0x16 },
  176. "60": { symbol: "eth", ilk: "eth" },
  177. "61": { symbol: "etc", ilk: "eth" },
  178. "700": { symbol: "xdai", ilk: "eth" },
  179. };
  180. function bytes32ify(value) {
  181. return hexZeroPad(BigNumber.from(value).toHexString(), 32);
  182. }
  183. // Compute the Base58Check encoded data (checksum is first 4 bytes of sha256d)
  184. function base58Encode(data) {
  185. return Base58.encode(concat([data, hexDataSlice(sha256(sha256(data)), 0, 4)]));
  186. }
  187. const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
  188. const matchers = [
  189. new RegExp("^(https):/\/(.*)$", "i"),
  190. new RegExp("^(data):(.*)$", "i"),
  191. matcherIpfs,
  192. new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
  193. ];
  194. function _parseString(result, start) {
  195. try {
  196. return toUtf8String(_parseBytes(result, start));
  197. }
  198. catch (error) { }
  199. return null;
  200. }
  201. function _parseBytes(result, start) {
  202. if (result === "0x") {
  203. return null;
  204. }
  205. const offset = BigNumber.from(hexDataSlice(result, start, start + 32)).toNumber();
  206. const length = BigNumber.from(hexDataSlice(result, offset, offset + 32)).toNumber();
  207. return hexDataSlice(result, offset + 32, offset + 32 + length);
  208. }
  209. // Trim off the ipfs:// prefix and return the default gateway URL
  210. function getIpfsLink(link) {
  211. if (link.match(/^ipfs:\/\/ipfs\//i)) {
  212. link = link.substring(12);
  213. }
  214. else if (link.match(/^ipfs:\/\//i)) {
  215. link = link.substring(7);
  216. }
  217. else {
  218. logger.throwArgumentError("unsupported IPFS format", "link", link);
  219. }
  220. return `https:/\/gateway.ipfs.io/ipfs/${link}`;
  221. }
  222. function numPad(value) {
  223. const result = arrayify(value);
  224. if (result.length > 32) {
  225. throw new Error("internal; should not happen");
  226. }
  227. const padded = new Uint8Array(32);
  228. padded.set(result, 32 - result.length);
  229. return padded;
  230. }
  231. function bytesPad(value) {
  232. if ((value.length % 32) === 0) {
  233. return value;
  234. }
  235. const result = new Uint8Array(Math.ceil(value.length / 32) * 32);
  236. result.set(value);
  237. return result;
  238. }
  239. // ABI Encodes a series of (bytes, bytes, ...)
  240. function encodeBytes(datas) {
  241. const result = [];
  242. let byteCount = 0;
  243. // Add place-holders for pointers as we add items
  244. for (let i = 0; i < datas.length; i++) {
  245. result.push(null);
  246. byteCount += 32;
  247. }
  248. for (let i = 0; i < datas.length; i++) {
  249. const data = arrayify(datas[i]);
  250. // Update the bytes offset
  251. result[i] = numPad(byteCount);
  252. // The length and padded value of data
  253. result.push(numPad(data.length));
  254. result.push(bytesPad(data));
  255. byteCount += 32 + Math.ceil(data.length / 32) * 32;
  256. }
  257. return hexConcat(result);
  258. }
  259. export class Resolver {
  260. // The resolvedAddress is only for creating a ReverseLookup resolver
  261. constructor(provider, address, name, resolvedAddress) {
  262. defineReadOnly(this, "provider", provider);
  263. defineReadOnly(this, "name", name);
  264. defineReadOnly(this, "address", provider.formatter.address(address));
  265. defineReadOnly(this, "_resolvedAddress", resolvedAddress);
  266. }
  267. supportsWildcard() {
  268. if (!this._supportsEip2544) {
  269. // supportsInterface(bytes4 = selector("resolve(bytes,bytes)"))
  270. this._supportsEip2544 = this.provider.call({
  271. to: this.address,
  272. data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000"
  273. }).then((result) => {
  274. return BigNumber.from(result).eq(1);
  275. }).catch((error) => {
  276. if (error.code === Logger.errors.CALL_EXCEPTION) {
  277. return false;
  278. }
  279. // Rethrow the error: link is down, etc. Let future attempts retry.
  280. this._supportsEip2544 = null;
  281. throw error;
  282. });
  283. }
  284. return this._supportsEip2544;
  285. }
  286. _fetch(selector, parameters) {
  287. return __awaiter(this, void 0, void 0, function* () {
  288. // e.g. keccak256("addr(bytes32,uint256)")
  289. const tx = {
  290. to: this.address,
  291. ccipReadEnabled: true,
  292. data: hexConcat([selector, namehash(this.name), (parameters || "0x")])
  293. };
  294. // Wildcard support; use EIP-2544 to resolve the request
  295. let parseBytes = false;
  296. if (yield this.supportsWildcard()) {
  297. parseBytes = true;
  298. // selector("resolve(bytes,bytes)")
  299. tx.data = hexConcat(["0x9061b923", encodeBytes([dnsEncode(this.name), tx.data])]);
  300. }
  301. try {
  302. let result = yield this.provider.call(tx);
  303. if ((arrayify(result).length % 32) === 4) {
  304. logger.throwError("resolver threw error", Logger.errors.CALL_EXCEPTION, {
  305. transaction: tx, data: result
  306. });
  307. }
  308. if (parseBytes) {
  309. result = _parseBytes(result, 0);
  310. }
  311. return result;
  312. }
  313. catch (error) {
  314. if (error.code === Logger.errors.CALL_EXCEPTION) {
  315. return null;
  316. }
  317. throw error;
  318. }
  319. });
  320. }
  321. _fetchBytes(selector, parameters) {
  322. return __awaiter(this, void 0, void 0, function* () {
  323. const result = yield this._fetch(selector, parameters);
  324. if (result != null) {
  325. return _parseBytes(result, 0);
  326. }
  327. return null;
  328. });
  329. }
  330. _getAddress(coinType, hexBytes) {
  331. const coinInfo = coinInfos[String(coinType)];
  332. if (coinInfo == null) {
  333. logger.throwError(`unsupported coin type: ${coinType}`, Logger.errors.UNSUPPORTED_OPERATION, {
  334. operation: `getAddress(${coinType})`
  335. });
  336. }
  337. if (coinInfo.ilk === "eth") {
  338. return this.provider.formatter.address(hexBytes);
  339. }
  340. const bytes = arrayify(hexBytes);
  341. // P2PKH: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
  342. if (coinInfo.p2pkh != null) {
  343. const p2pkh = hexBytes.match(/^0x76a9([0-9a-f][0-9a-f])([0-9a-f]*)88ac$/);
  344. if (p2pkh) {
  345. const length = parseInt(p2pkh[1], 16);
  346. if (p2pkh[2].length === length * 2 && length >= 1 && length <= 75) {
  347. return base58Encode(concat([[coinInfo.p2pkh], ("0x" + p2pkh[2])]));
  348. }
  349. }
  350. }
  351. // P2SH: OP_HASH160 <scriptHash> OP_EQUAL
  352. if (coinInfo.p2sh != null) {
  353. const p2sh = hexBytes.match(/^0xa9([0-9a-f][0-9a-f])([0-9a-f]*)87$/);
  354. if (p2sh) {
  355. const length = parseInt(p2sh[1], 16);
  356. if (p2sh[2].length === length * 2 && length >= 1 && length <= 75) {
  357. return base58Encode(concat([[coinInfo.p2sh], ("0x" + p2sh[2])]));
  358. }
  359. }
  360. }
  361. // Bech32
  362. if (coinInfo.prefix != null) {
  363. const length = bytes[1];
  364. // https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
  365. let version = bytes[0];
  366. if (version === 0x00) {
  367. if (length !== 20 && length !== 32) {
  368. version = -1;
  369. }
  370. }
  371. else {
  372. version = -1;
  373. }
  374. if (version >= 0 && bytes.length === 2 + length && length >= 1 && length <= 75) {
  375. const words = bech32.toWords(bytes.slice(2));
  376. words.unshift(version);
  377. return bech32.encode(coinInfo.prefix, words);
  378. }
  379. }
  380. return null;
  381. }
  382. getAddress(coinType) {
  383. return __awaiter(this, void 0, void 0, function* () {
  384. if (coinType == null) {
  385. coinType = 60;
  386. }
  387. // If Ethereum, use the standard `addr(bytes32)`
  388. if (coinType === 60) {
  389. try {
  390. // keccak256("addr(bytes32)")
  391. const result = yield this._fetch("0x3b3b57de");
  392. // No address
  393. if (result === "0x" || result === HashZero) {
  394. return null;
  395. }
  396. return this.provider.formatter.callAddress(result);
  397. }
  398. catch (error) {
  399. if (error.code === Logger.errors.CALL_EXCEPTION) {
  400. return null;
  401. }
  402. throw error;
  403. }
  404. }
  405. // keccak256("addr(bytes32,uint256")
  406. const hexBytes = yield this._fetchBytes("0xf1cb7e06", bytes32ify(coinType));
  407. // No address
  408. if (hexBytes == null || hexBytes === "0x") {
  409. return null;
  410. }
  411. // Compute the address
  412. const address = this._getAddress(coinType, hexBytes);
  413. if (address == null) {
  414. logger.throwError(`invalid or unsupported coin data`, Logger.errors.UNSUPPORTED_OPERATION, {
  415. operation: `getAddress(${coinType})`,
  416. coinType: coinType,
  417. data: hexBytes
  418. });
  419. }
  420. return address;
  421. });
  422. }
  423. getAvatar() {
  424. return __awaiter(this, void 0, void 0, function* () {
  425. const linkage = [{ type: "name", content: this.name }];
  426. try {
  427. // test data for ricmoo.eth
  428. //const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
  429. const avatar = yield this.getText("avatar");
  430. if (avatar == null) {
  431. return null;
  432. }
  433. for (let i = 0; i < matchers.length; i++) {
  434. const match = avatar.match(matchers[i]);
  435. if (match == null) {
  436. continue;
  437. }
  438. const scheme = match[1].toLowerCase();
  439. switch (scheme) {
  440. case "https":
  441. linkage.push({ type: "url", content: avatar });
  442. return { linkage, url: avatar };
  443. case "data":
  444. linkage.push({ type: "data", content: avatar });
  445. return { linkage, url: avatar };
  446. case "ipfs":
  447. linkage.push({ type: "ipfs", content: avatar });
  448. return { linkage, url: getIpfsLink(avatar) };
  449. case "erc721":
  450. case "erc1155": {
  451. // Depending on the ERC type, use tokenURI(uint256) or url(uint256)
  452. const selector = (scheme === "erc721") ? "0xc87b56dd" : "0x0e89341c";
  453. linkage.push({ type: scheme, content: avatar });
  454. // The owner of this name
  455. const owner = (this._resolvedAddress || (yield this.getAddress()));
  456. const comps = (match[2] || "").split("/");
  457. if (comps.length !== 2) {
  458. return null;
  459. }
  460. const addr = yield this.provider.formatter.address(comps[0]);
  461. const tokenId = hexZeroPad(BigNumber.from(comps[1]).toHexString(), 32);
  462. // Check that this account owns the token
  463. if (scheme === "erc721") {
  464. // ownerOf(uint256 tokenId)
  465. const tokenOwner = this.provider.formatter.callAddress(yield this.provider.call({
  466. to: addr, data: hexConcat(["0x6352211e", tokenId])
  467. }));
  468. if (owner !== tokenOwner) {
  469. return null;
  470. }
  471. linkage.push({ type: "owner", content: tokenOwner });
  472. }
  473. else if (scheme === "erc1155") {
  474. // balanceOf(address owner, uint256 tokenId)
  475. const balance = BigNumber.from(yield this.provider.call({
  476. to: addr, data: hexConcat(["0x00fdd58e", hexZeroPad(owner, 32), tokenId])
  477. }));
  478. if (balance.isZero()) {
  479. return null;
  480. }
  481. linkage.push({ type: "balance", content: balance.toString() });
  482. }
  483. // Call the token contract for the metadata URL
  484. const tx = {
  485. to: this.provider.formatter.address(comps[0]),
  486. data: hexConcat([selector, tokenId])
  487. };
  488. let metadataUrl = _parseString(yield this.provider.call(tx), 0);
  489. if (metadataUrl == null) {
  490. return null;
  491. }
  492. linkage.push({ type: "metadata-url-base", content: metadataUrl });
  493. // ERC-1155 allows a generic {id} in the URL
  494. if (scheme === "erc1155") {
  495. metadataUrl = metadataUrl.replace("{id}", tokenId.substring(2));
  496. linkage.push({ type: "metadata-url-expanded", content: metadataUrl });
  497. }
  498. // Transform IPFS metadata links
  499. if (metadataUrl.match(/^ipfs:/i)) {
  500. metadataUrl = getIpfsLink(metadataUrl);
  501. }
  502. linkage.push({ type: "metadata-url", content: metadataUrl });
  503. // Get the token metadata
  504. const metadata = yield fetchJson(metadataUrl);
  505. if (!metadata) {
  506. return null;
  507. }
  508. linkage.push({ type: "metadata", content: JSON.stringify(metadata) });
  509. // Pull the image URL out
  510. let imageUrl = metadata.image;
  511. if (typeof (imageUrl) !== "string") {
  512. return null;
  513. }
  514. if (imageUrl.match(/^(https:\/\/|data:)/i)) {
  515. // Allow
  516. }
  517. else {
  518. // Transform IPFS link to gateway
  519. const ipfs = imageUrl.match(matcherIpfs);
  520. if (ipfs == null) {
  521. return null;
  522. }
  523. linkage.push({ type: "url-ipfs", content: imageUrl });
  524. imageUrl = getIpfsLink(imageUrl);
  525. }
  526. linkage.push({ type: "url", content: imageUrl });
  527. return { linkage, url: imageUrl };
  528. }
  529. }
  530. }
  531. }
  532. catch (error) { }
  533. return null;
  534. });
  535. }
  536. getContentHash() {
  537. return __awaiter(this, void 0, void 0, function* () {
  538. // keccak256("contenthash()")
  539. const hexBytes = yield this._fetchBytes("0xbc1c58d1");
  540. // No contenthash
  541. if (hexBytes == null || hexBytes === "0x") {
  542. return null;
  543. }
  544. // IPFS (CID: 1, Type: DAG-PB)
  545. const ipfs = hexBytes.match(/^0xe3010170(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/);
  546. if (ipfs) {
  547. const length = parseInt(ipfs[3], 16);
  548. if (ipfs[4].length === length * 2) {
  549. return "ipfs:/\/" + Base58.encode("0x" + ipfs[1]);
  550. }
  551. }
  552. // Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
  553. const swarm = hexBytes.match(/^0xe40101fa011b20([0-9a-f]*)$/);
  554. if (swarm) {
  555. if (swarm[1].length === (32 * 2)) {
  556. return "bzz:/\/" + swarm[1];
  557. }
  558. }
  559. return logger.throwError(`invalid or unsupported content hash data`, Logger.errors.UNSUPPORTED_OPERATION, {
  560. operation: "getContentHash()",
  561. data: hexBytes
  562. });
  563. });
  564. }
  565. getText(key) {
  566. return __awaiter(this, void 0, void 0, function* () {
  567. // The key encoded as parameter to fetchBytes
  568. let keyBytes = toUtf8Bytes(key);
  569. // The nodehash consumes the first slot, so the string pointer targets
  570. // offset 64, with the length at offset 64 and data starting at offset 96
  571. keyBytes = concat([bytes32ify(64), bytes32ify(keyBytes.length), keyBytes]);
  572. // Pad to word-size (32 bytes)
  573. if ((keyBytes.length % 32) !== 0) {
  574. keyBytes = concat([keyBytes, hexZeroPad("0x", 32 - (key.length % 32))]);
  575. }
  576. const hexBytes = yield this._fetchBytes("0x59d1d43c", hexlify(keyBytes));
  577. if (hexBytes == null || hexBytes === "0x") {
  578. return null;
  579. }
  580. return toUtf8String(hexBytes);
  581. });
  582. }
  583. }
  584. let defaultFormatter = null;
  585. let nextPollId = 1;
  586. export class BaseProvider extends Provider {
  587. /**
  588. * ready
  589. *
  590. * A Promise<Network> that resolves only once the provider is ready.
  591. *
  592. * Sub-classes that call the super with a network without a chainId
  593. * MUST set this. Standard named networks have a known chainId.
  594. *
  595. */
  596. constructor(network) {
  597. logger.checkNew(new.target, Provider);
  598. super();
  599. // Events being listened to
  600. this._events = [];
  601. this._emitted = { block: -2 };
  602. this.disableCcipRead = false;
  603. this.formatter = new.target.getFormatter();
  604. // If network is any, this Provider allows the underlying
  605. // network to change dynamically, and we auto-detect the
  606. // current network
  607. defineReadOnly(this, "anyNetwork", (network === "any"));
  608. if (this.anyNetwork) {
  609. network = this.detectNetwork();
  610. }
  611. if (network instanceof Promise) {
  612. this._networkPromise = network;
  613. // Squash any "unhandled promise" errors; that do not need to be handled
  614. network.catch((error) => { });
  615. // Trigger initial network setting (async)
  616. this._ready().catch((error) => { });
  617. }
  618. else {
  619. const knownNetwork = getStatic(new.target, "getNetwork")(network);
  620. if (knownNetwork) {
  621. defineReadOnly(this, "_network", knownNetwork);
  622. this.emit("network", knownNetwork, null);
  623. }
  624. else {
  625. logger.throwArgumentError("invalid network", "network", network);
  626. }
  627. }
  628. this._maxInternalBlockNumber = -1024;
  629. this._lastBlockNumber = -2;
  630. this._maxFilterBlockRange = 10;
  631. this._pollingInterval = 4000;
  632. this._fastQueryDate = 0;
  633. }
  634. _ready() {
  635. return __awaiter(this, void 0, void 0, function* () {
  636. if (this._network == null) {
  637. let network = null;
  638. if (this._networkPromise) {
  639. try {
  640. network = yield this._networkPromise;
  641. }
  642. catch (error) { }
  643. }
  644. // Try the Provider's network detection (this MUST throw if it cannot)
  645. if (network == null) {
  646. network = yield this.detectNetwork();
  647. }
  648. // This should never happen; every Provider sub-class should have
  649. // suggested a network by here (or have thrown).
  650. if (!network) {
  651. logger.throwError("no network detected", Logger.errors.UNKNOWN_ERROR, {});
  652. }
  653. // Possible this call stacked so do not call defineReadOnly again
  654. if (this._network == null) {
  655. if (this.anyNetwork) {
  656. this._network = network;
  657. }
  658. else {
  659. defineReadOnly(this, "_network", network);
  660. }
  661. this.emit("network", network, null);
  662. }
  663. }
  664. return this._network;
  665. });
  666. }
  667. // This will always return the most recently established network.
  668. // For "any", this can change (a "network" event is emitted before
  669. // any change is reflected); otherwise this cannot change
  670. get ready() {
  671. return poll(() => {
  672. return this._ready().then((network) => {
  673. return network;
  674. }, (error) => {
  675. // If the network isn't running yet, we will wait
  676. if (error.code === Logger.errors.NETWORK_ERROR && error.event === "noNetwork") {
  677. return undefined;
  678. }
  679. throw error;
  680. });
  681. });
  682. }
  683. // @TODO: Remove this and just create a singleton formatter
  684. static getFormatter() {
  685. if (defaultFormatter == null) {
  686. defaultFormatter = new Formatter();
  687. }
  688. return defaultFormatter;
  689. }
  690. // @TODO: Remove this and just use getNetwork
  691. static getNetwork(network) {
  692. return getNetwork((network == null) ? "homestead" : network);
  693. }
  694. ccipReadFetch(tx, calldata, urls) {
  695. return __awaiter(this, void 0, void 0, function* () {
  696. if (this.disableCcipRead || urls.length === 0) {
  697. return null;
  698. }
  699. const sender = (tx.from || "0x0000000000000000000000000000000000000000").toLowerCase();
  700. const data = calldata.toLowerCase();
  701. const errorMessages = [];
  702. for (let i = 0; i < urls.length; i++) {
  703. const url = urls[i];
  704. // URL expansion
  705. const href = url.replace("{sender}", sender).replace("{data}", data);
  706. // If no {data} is present, use POST; otherwise GET
  707. const json = (url.indexOf("{data}") >= 0) ? null : JSON.stringify({ data, sender });
  708. const result = yield fetchJson({ url: href, errorPassThrough: true }, json, (value, response) => {
  709. value.status = response.statusCode;
  710. return value;
  711. });
  712. if (result.data) {
  713. return result.data;
  714. }
  715. const errorMessage = (result.message || "unknown error");
  716. // 4xx indicates the result is not present; stop
  717. if (result.status >= 400 && result.status < 500) {
  718. return logger.throwError(`response not found during CCIP fetch: ${errorMessage}`, Logger.errors.SERVER_ERROR, { url, errorMessage });
  719. }
  720. // 5xx indicates server issue; try the next url
  721. errorMessages.push(errorMessage);
  722. }
  723. return logger.throwError(`error encountered during CCIP fetch: ${errorMessages.map((m) => JSON.stringify(m)).join(", ")}`, Logger.errors.SERVER_ERROR, {
  724. urls, errorMessages
  725. });
  726. });
  727. }
  728. // Fetches the blockNumber, but will reuse any result that is less
  729. // than maxAge old or has been requested since the last request
  730. _getInternalBlockNumber(maxAge) {
  731. return __awaiter(this, void 0, void 0, function* () {
  732. yield this._ready();
  733. // Allowing stale data up to maxAge old
  734. if (maxAge > 0) {
  735. // While there are pending internal block requests...
  736. while (this._internalBlockNumber) {
  737. // ..."remember" which fetch we started with
  738. const internalBlockNumber = this._internalBlockNumber;
  739. try {
  740. // Check the result is not too stale
  741. const result = yield internalBlockNumber;
  742. if ((getTime() - result.respTime) <= maxAge) {
  743. return result.blockNumber;
  744. }
  745. // Too old; fetch a new value
  746. break;
  747. }
  748. catch (error) {
  749. // The fetch rejected; if we are the first to get the
  750. // rejection, drop through so we replace it with a new
  751. // fetch; all others blocked will then get that fetch
  752. // which won't match the one they "remembered" and loop
  753. if (this._internalBlockNumber === internalBlockNumber) {
  754. break;
  755. }
  756. }
  757. }
  758. }
  759. const reqTime = getTime();
  760. const checkInternalBlockNumber = resolveProperties({
  761. blockNumber: this.perform("getBlockNumber", {}),
  762. networkError: this.getNetwork().then((network) => (null), (error) => (error))
  763. }).then(({ blockNumber, networkError }) => {
  764. if (networkError) {
  765. // Unremember this bad internal block number
  766. if (this._internalBlockNumber === checkInternalBlockNumber) {
  767. this._internalBlockNumber = null;
  768. }
  769. throw networkError;
  770. }
  771. const respTime = getTime();
  772. blockNumber = BigNumber.from(blockNumber).toNumber();
  773. if (blockNumber < this._maxInternalBlockNumber) {
  774. blockNumber = this._maxInternalBlockNumber;
  775. }
  776. this._maxInternalBlockNumber = blockNumber;
  777. this._setFastBlockNumber(blockNumber); // @TODO: Still need this?
  778. return { blockNumber, reqTime, respTime };
  779. });
  780. this._internalBlockNumber = checkInternalBlockNumber;
  781. // Swallow unhandled exceptions; if needed they are handled else where
  782. checkInternalBlockNumber.catch((error) => {
  783. // Don't null the dead (rejected) fetch, if it has already been updated
  784. if (this._internalBlockNumber === checkInternalBlockNumber) {
  785. this._internalBlockNumber = null;
  786. }
  787. });
  788. return (yield checkInternalBlockNumber).blockNumber;
  789. });
  790. }
  791. poll() {
  792. return __awaiter(this, void 0, void 0, function* () {
  793. const pollId = nextPollId++;
  794. // Track all running promises, so we can trigger a post-poll once they are complete
  795. const runners = [];
  796. let blockNumber = null;
  797. try {
  798. blockNumber = yield this._getInternalBlockNumber(100 + this.pollingInterval / 2);
  799. }
  800. catch (error) {
  801. this.emit("error", error);
  802. return;
  803. }
  804. this._setFastBlockNumber(blockNumber);
  805. // Emit a poll event after we have the latest (fast) block number
  806. this.emit("poll", pollId, blockNumber);
  807. // If the block has not changed, meh.
  808. if (blockNumber === this._lastBlockNumber) {
  809. this.emit("didPoll", pollId);
  810. return;
  811. }
  812. // First polling cycle, trigger a "block" events
  813. if (this._emitted.block === -2) {
  814. this._emitted.block = blockNumber - 1;
  815. }
  816. if (Math.abs((this._emitted.block) - blockNumber) > 1000) {
  817. logger.warn(`network block skew detected; skipping block events (emitted=${this._emitted.block} blockNumber${blockNumber})`);
  818. this.emit("error", logger.makeError("network block skew detected", Logger.errors.NETWORK_ERROR, {
  819. blockNumber: blockNumber,
  820. event: "blockSkew",
  821. previousBlockNumber: this._emitted.block
  822. }));
  823. this.emit("block", blockNumber);
  824. }
  825. else {
  826. // Notify all listener for each block that has passed
  827. for (let i = this._emitted.block + 1; i <= blockNumber; i++) {
  828. this.emit("block", i);
  829. }
  830. }
  831. // The emitted block was updated, check for obsolete events
  832. if (this._emitted.block !== blockNumber) {
  833. this._emitted.block = blockNumber;
  834. Object.keys(this._emitted).forEach((key) => {
  835. // The block event does not expire
  836. if (key === "block") {
  837. return;
  838. }
  839. // The block we were at when we emitted this event
  840. const eventBlockNumber = this._emitted[key];
  841. // We cannot garbage collect pending transactions or blocks here
  842. // They should be garbage collected by the Provider when setting
  843. // "pending" events
  844. if (eventBlockNumber === "pending") {
  845. return;
  846. }
  847. // Evict any transaction hashes or block hashes over 12 blocks
  848. // old, since they should not return null anyways
  849. if (blockNumber - eventBlockNumber > 12) {
  850. delete this._emitted[key];
  851. }
  852. });
  853. }
  854. // First polling cycle
  855. if (this._lastBlockNumber === -2) {
  856. this._lastBlockNumber = blockNumber - 1;
  857. }
  858. // Find all transaction hashes we are waiting on
  859. this._events.forEach((event) => {
  860. switch (event.type) {
  861. case "tx": {
  862. const hash = event.hash;
  863. let runner = this.getTransactionReceipt(hash).then((receipt) => {
  864. if (!receipt || receipt.blockNumber == null) {
  865. return null;
  866. }
  867. this._emitted["t:" + hash] = receipt.blockNumber;
  868. this.emit(hash, receipt);
  869. return null;
  870. }).catch((error) => { this.emit("error", error); });
  871. runners.push(runner);
  872. break;
  873. }
  874. case "filter": {
  875. // We only allow a single getLogs to be in-flight at a time
  876. if (!event._inflight) {
  877. event._inflight = true;
  878. // Filter from the last known event; due to load-balancing
  879. // and some nodes returning updated block numbers before
  880. // indexing events, a logs result with 0 entries cannot be
  881. // trusted and we must retry a range which includes it again
  882. const filter = event.filter;
  883. filter.fromBlock = event._lastBlockNumber + 1;
  884. filter.toBlock = blockNumber;
  885. // Prevent fitler ranges from growing too wild
  886. if (filter.toBlock - this._maxFilterBlockRange > filter.fromBlock) {
  887. filter.fromBlock = filter.toBlock - this._maxFilterBlockRange;
  888. }
  889. const runner = this.getLogs(filter).then((logs) => {
  890. // Allow the next getLogs
  891. event._inflight = false;
  892. if (logs.length === 0) {
  893. return;
  894. }
  895. logs.forEach((log) => {
  896. // Only when we get an event for a given block number
  897. // can we trust the events are indexed
  898. if (log.blockNumber > event._lastBlockNumber) {
  899. event._lastBlockNumber = log.blockNumber;
  900. }
  901. // Make sure we stall requests to fetch blocks and txs
  902. this._emitted["b:" + log.blockHash] = log.blockNumber;
  903. this._emitted["t:" + log.transactionHash] = log.blockNumber;
  904. this.emit(filter, log);
  905. });
  906. }).catch((error) => {
  907. this.emit("error", error);
  908. // Allow another getLogs (the range was not updated)
  909. event._inflight = false;
  910. });
  911. runners.push(runner);
  912. }
  913. break;
  914. }
  915. }
  916. });
  917. this._lastBlockNumber = blockNumber;
  918. // Once all events for this loop have been processed, emit "didPoll"
  919. Promise.all(runners).then(() => {
  920. this.emit("didPoll", pollId);
  921. }).catch((error) => { this.emit("error", error); });
  922. return;
  923. });
  924. }
  925. // Deprecated; do not use this
  926. resetEventsBlock(blockNumber) {
  927. this._lastBlockNumber = blockNumber - 1;
  928. if (this.polling) {
  929. this.poll();
  930. }
  931. }
  932. get network() {
  933. return this._network;
  934. }
  935. // This method should query the network if the underlying network
  936. // can change, such as when connected to a JSON-RPC backend
  937. detectNetwork() {
  938. return __awaiter(this, void 0, void 0, function* () {
  939. return logger.throwError("provider does not support network detection", Logger.errors.UNSUPPORTED_OPERATION, {
  940. operation: "provider.detectNetwork"
  941. });
  942. });
  943. }
  944. getNetwork() {
  945. return __awaiter(this, void 0, void 0, function* () {
  946. const network = yield this._ready();
  947. // Make sure we are still connected to the same network; this is
  948. // only an external call for backends which can have the underlying
  949. // network change spontaneously
  950. const currentNetwork = yield this.detectNetwork();
  951. if (network.chainId !== currentNetwork.chainId) {
  952. // We are allowing network changes, things can get complex fast;
  953. // make sure you know what you are doing if you use "any"
  954. if (this.anyNetwork) {
  955. this._network = currentNetwork;
  956. // Reset all internal block number guards and caches
  957. this._lastBlockNumber = -2;
  958. this._fastBlockNumber = null;
  959. this._fastBlockNumberPromise = null;
  960. this._fastQueryDate = 0;
  961. this._emitted.block = -2;
  962. this._maxInternalBlockNumber = -1024;
  963. this._internalBlockNumber = null;
  964. // The "network" event MUST happen before this method resolves
  965. // so any events have a chance to unregister, so we stall an
  966. // additional event loop before returning from /this/ call
  967. this.emit("network", currentNetwork, network);
  968. yield stall(0);
  969. return this._network;
  970. }
  971. const error = logger.makeError("underlying network changed", Logger.errors.NETWORK_ERROR, {
  972. event: "changed",
  973. network: network,
  974. detectedNetwork: currentNetwork
  975. });
  976. this.emit("error", error);
  977. throw error;
  978. }
  979. return network;
  980. });
  981. }
  982. get blockNumber() {
  983. this._getInternalBlockNumber(100 + this.pollingInterval / 2).then((blockNumber) => {
  984. this._setFastBlockNumber(blockNumber);
  985. }, (error) => { });
  986. return (this._fastBlockNumber != null) ? this._fastBlockNumber : -1;
  987. }
  988. get polling() {
  989. return (this._poller != null);
  990. }
  991. set polling(value) {
  992. if (value && !this._poller) {
  993. this._poller = setInterval(() => { this.poll(); }, this.pollingInterval);
  994. if (!this._bootstrapPoll) {
  995. this._bootstrapPoll = setTimeout(() => {
  996. this.poll();
  997. // We block additional polls until the polling interval
  998. // is done, to prevent overwhelming the poll function
  999. this._bootstrapPoll = setTimeout(() => {
  1000. // If polling was disabled, something may require a poke
  1001. // since starting the bootstrap poll and it was disabled
  1002. if (!this._poller) {
  1003. this.poll();
  1004. }
  1005. // Clear out the bootstrap so we can do another
  1006. this._bootstrapPoll = null;
  1007. }, this.pollingInterval);
  1008. }, 0);
  1009. }
  1010. }
  1011. else if (!value && this._poller) {
  1012. clearInterval(this._poller);
  1013. this._poller = null;
  1014. }
  1015. }
  1016. get pollingInterval() {
  1017. return this._pollingInterval;
  1018. }
  1019. set pollingInterval(value) {
  1020. if (typeof (value) !== "number" || value <= 0 || parseInt(String(value)) != value) {
  1021. throw new Error("invalid polling interval");
  1022. }
  1023. this._pollingInterval = value;
  1024. if (this._poller) {
  1025. clearInterval(this._poller);
  1026. this._poller = setInterval(() => { this.poll(); }, this._pollingInterval);
  1027. }
  1028. }
  1029. _getFastBlockNumber() {
  1030. const now = getTime();
  1031. // Stale block number, request a newer value
  1032. if ((now - this._fastQueryDate) > 2 * this._pollingInterval) {
  1033. this._fastQueryDate = now;
  1034. this._fastBlockNumberPromise = this.getBlockNumber().then((blockNumber) => {
  1035. if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
  1036. this._fastBlockNumber = blockNumber;
  1037. }
  1038. return this._fastBlockNumber;
  1039. });
  1040. }
  1041. return this._fastBlockNumberPromise;
  1042. }
  1043. _setFastBlockNumber(blockNumber) {
  1044. // Older block, maybe a stale request
  1045. if (this._fastBlockNumber != null && blockNumber < this._fastBlockNumber) {
  1046. return;
  1047. }
  1048. // Update the time we updated the blocknumber
  1049. this._fastQueryDate = getTime();
  1050. // Newer block number, use it
  1051. if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
  1052. this._fastBlockNumber = blockNumber;
  1053. this._fastBlockNumberPromise = Promise.resolve(blockNumber);
  1054. }
  1055. }
  1056. waitForTransaction(transactionHash, confirmations, timeout) {
  1057. return __awaiter(this, void 0, void 0, function* () {
  1058. return this._waitForTransaction(transactionHash, (confirmations == null) ? 1 : confirmations, timeout || 0, null);
  1059. });
  1060. }
  1061. _waitForTransaction(transactionHash, confirmations, timeout, replaceable) {
  1062. return __awaiter(this, void 0, void 0, function* () {
  1063. const receipt = yield this.getTransactionReceipt(transactionHash);
  1064. // Receipt is already good
  1065. if ((receipt ? receipt.confirmations : 0) >= confirmations) {
  1066. return receipt;
  1067. }
  1068. // Poll until the receipt is good...
  1069. return new Promise((resolve, reject) => {
  1070. const cancelFuncs = [];
  1071. let done = false;
  1072. const alreadyDone = function () {
  1073. if (done) {
  1074. return true;
  1075. }
  1076. done = true;
  1077. cancelFuncs.forEach((func) => { func(); });
  1078. return false;
  1079. };
  1080. const minedHandler = (receipt) => {
  1081. if (receipt.confirmations < confirmations) {
  1082. return;
  1083. }
  1084. if (alreadyDone()) {
  1085. return;
  1086. }
  1087. resolve(receipt);
  1088. };
  1089. this.on(transactionHash, minedHandler);
  1090. cancelFuncs.push(() => { this.removeListener(transactionHash, minedHandler); });
  1091. if (replaceable) {
  1092. let lastBlockNumber = replaceable.startBlock;
  1093. let scannedBlock = null;
  1094. const replaceHandler = (blockNumber) => __awaiter(this, void 0, void 0, function* () {
  1095. if (done) {
  1096. return;
  1097. }
  1098. // Wait 1 second; this is only used in the case of a fault, so
  1099. // we will trade off a little bit of latency for more consistent
  1100. // results and fewer JSON-RPC calls
  1101. yield stall(1000);
  1102. this.getTransactionCount(replaceable.from).then((nonce) => __awaiter(this, void 0, void 0, function* () {
  1103. if (done) {
  1104. return;
  1105. }
  1106. if (nonce <= replaceable.nonce) {
  1107. lastBlockNumber = blockNumber;
  1108. }
  1109. else {
  1110. // First check if the transaction was mined
  1111. {
  1112. const mined = yield this.getTransaction(transactionHash);
  1113. if (mined && mined.blockNumber != null) {
  1114. return;
  1115. }
  1116. }
  1117. // First time scanning. We start a little earlier for some
  1118. // wiggle room here to handle the eventually consistent nature
  1119. // of blockchain (e.g. the getTransactionCount was for a
  1120. // different block)
  1121. if (scannedBlock == null) {
  1122. scannedBlock = lastBlockNumber - 3;
  1123. if (scannedBlock < replaceable.startBlock) {
  1124. scannedBlock = replaceable.startBlock;
  1125. }
  1126. }
  1127. while (scannedBlock <= blockNumber) {
  1128. if (done) {
  1129. return;
  1130. }
  1131. const block = yield this.getBlockWithTransactions(scannedBlock);
  1132. for (let ti = 0; ti < block.transactions.length; ti++) {
  1133. const tx = block.transactions[ti];
  1134. // Successfully mined!
  1135. if (tx.hash === transactionHash) {
  1136. return;
  1137. }
  1138. // Matches our transaction from and nonce; its a replacement
  1139. if (tx.from === replaceable.from && tx.nonce === replaceable.nonce) {
  1140. if (done) {
  1141. return;
  1142. }
  1143. // Get the receipt of the replacement
  1144. const receipt = yield this.waitForTransaction(tx.hash, confirmations);
  1145. // Already resolved or rejected (prolly a timeout)
  1146. if (alreadyDone()) {
  1147. return;
  1148. }
  1149. // The reason we were replaced
  1150. let reason = "replaced";
  1151. if (tx.data === replaceable.data && tx.to === replaceable.to && tx.value.eq(replaceable.value)) {
  1152. reason = "repriced";
  1153. }
  1154. else if (tx.data === "0x" && tx.from === tx.to && tx.value.isZero()) {
  1155. reason = "cancelled";
  1156. }
  1157. // Explain why we were replaced
  1158. reject(logger.makeError("transaction was replaced", Logger.errors.TRANSACTION_REPLACED, {
  1159. cancelled: (reason === "replaced" || reason === "cancelled"),
  1160. reason,
  1161. replacement: this._wrapTransaction(tx),
  1162. hash: transactionHash,
  1163. receipt
  1164. }));
  1165. return;
  1166. }
  1167. }
  1168. scannedBlock++;
  1169. }
  1170. }
  1171. if (done) {
  1172. return;
  1173. }
  1174. this.once("block", replaceHandler);
  1175. }), (error) => {
  1176. if (done) {
  1177. return;
  1178. }
  1179. this.once("block", replaceHandler);
  1180. });
  1181. });
  1182. if (done) {
  1183. return;
  1184. }
  1185. this.once("block", replaceHandler);
  1186. cancelFuncs.push(() => {
  1187. this.removeListener("block", replaceHandler);
  1188. });
  1189. }
  1190. if (typeof (timeout) === "number" && timeout > 0) {
  1191. const timer = setTimeout(() => {
  1192. if (alreadyDone()) {
  1193. return;
  1194. }
  1195. reject(logger.makeError("timeout exceeded", Logger.errors.TIMEOUT, { timeout: timeout }));
  1196. }, timeout);
  1197. if (timer.unref) {
  1198. timer.unref();
  1199. }
  1200. cancelFuncs.push(() => { clearTimeout(timer); });
  1201. }
  1202. });
  1203. });
  1204. }
  1205. getBlockNumber() {
  1206. return __awaiter(this, void 0, void 0, function* () {
  1207. return this._getInternalBlockNumber(0);
  1208. });
  1209. }
  1210. getGasPrice() {
  1211. return __awaiter(this, void 0, void 0, function* () {
  1212. yield this.getNetwork();
  1213. const result = yield this.perform("getGasPrice", {});
  1214. try {
  1215. return BigNumber.from(result);
  1216. }
  1217. catch (error) {
  1218. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1219. method: "getGasPrice",
  1220. result, error
  1221. });
  1222. }
  1223. });
  1224. }
  1225. getBalance(addressOrName, blockTag) {
  1226. return __awaiter(this, void 0, void 0, function* () {
  1227. yield this.getNetwork();
  1228. const params = yield resolveProperties({
  1229. address: this._getAddress(addressOrName),
  1230. blockTag: this._getBlockTag(blockTag)
  1231. });
  1232. const result = yield this.perform("getBalance", params);
  1233. try {
  1234. return BigNumber.from(result);
  1235. }
  1236. catch (error) {
  1237. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1238. method: "getBalance",
  1239. params, result, error
  1240. });
  1241. }
  1242. });
  1243. }
  1244. getTransactionCount(addressOrName, blockTag) {
  1245. return __awaiter(this, void 0, void 0, function* () {
  1246. yield this.getNetwork();
  1247. const params = yield resolveProperties({
  1248. address: this._getAddress(addressOrName),
  1249. blockTag: this._getBlockTag(blockTag)
  1250. });
  1251. const result = yield this.perform("getTransactionCount", params);
  1252. try {
  1253. return BigNumber.from(result).toNumber();
  1254. }
  1255. catch (error) {
  1256. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1257. method: "getTransactionCount",
  1258. params, result, error
  1259. });
  1260. }
  1261. });
  1262. }
  1263. getCode(addressOrName, blockTag) {
  1264. return __awaiter(this, void 0, void 0, function* () {
  1265. yield this.getNetwork();
  1266. const params = yield resolveProperties({
  1267. address: this._getAddress(addressOrName),
  1268. blockTag: this._getBlockTag(blockTag)
  1269. });
  1270. const result = yield this.perform("getCode", params);
  1271. try {
  1272. return hexlify(result);
  1273. }
  1274. catch (error) {
  1275. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1276. method: "getCode",
  1277. params, result, error
  1278. });
  1279. }
  1280. });
  1281. }
  1282. getStorageAt(addressOrName, position, blockTag) {
  1283. return __awaiter(this, void 0, void 0, function* () {
  1284. yield this.getNetwork();
  1285. const params = yield resolveProperties({
  1286. address: this._getAddress(addressOrName),
  1287. blockTag: this._getBlockTag(blockTag),
  1288. position: Promise.resolve(position).then((p) => hexValue(p))
  1289. });
  1290. const result = yield this.perform("getStorageAt", params);
  1291. try {
  1292. return hexlify(result);
  1293. }
  1294. catch (error) {
  1295. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1296. method: "getStorageAt",
  1297. params, result, error
  1298. });
  1299. }
  1300. });
  1301. }
  1302. // This should be called by any subclass wrapping a TransactionResponse
  1303. _wrapTransaction(tx, hash, startBlock) {
  1304. if (hash != null && hexDataLength(hash) !== 32) {
  1305. throw new Error("invalid response - sendTransaction");
  1306. }
  1307. const result = tx;
  1308. // Check the hash we expect is the same as the hash the server reported
  1309. if (hash != null && tx.hash !== hash) {
  1310. logger.throwError("Transaction hash mismatch from Provider.sendTransaction.", Logger.errors.UNKNOWN_ERROR, { expectedHash: tx.hash, returnedHash: hash });
  1311. }
  1312. result.wait = (confirms, timeout) => __awaiter(this, void 0, void 0, function* () {
  1313. if (confirms == null) {
  1314. confirms = 1;
  1315. }
  1316. if (timeout == null) {
  1317. timeout = 0;
  1318. }
  1319. // Get the details to detect replacement
  1320. let replacement = undefined;
  1321. if (confirms !== 0 && startBlock != null) {
  1322. replacement = {
  1323. data: tx.data,
  1324. from: tx.from,
  1325. nonce: tx.nonce,
  1326. to: tx.to,
  1327. value: tx.value,
  1328. startBlock
  1329. };
  1330. }
  1331. const receipt = yield this._waitForTransaction(tx.hash, confirms, timeout, replacement);
  1332. if (receipt == null && confirms === 0) {
  1333. return null;
  1334. }
  1335. // No longer pending, allow the polling loop to garbage collect this
  1336. this._emitted["t:" + tx.hash] = receipt.blockNumber;
  1337. if (receipt.status === 0) {
  1338. logger.throwError("transaction failed", Logger.errors.CALL_EXCEPTION, {
  1339. transactionHash: tx.hash,
  1340. transaction: tx,
  1341. receipt: receipt
  1342. });
  1343. }
  1344. return receipt;
  1345. });
  1346. return result;
  1347. }
  1348. sendTransaction(signedTransaction) {
  1349. return __awaiter(this, void 0, void 0, function* () {
  1350. yield this.getNetwork();
  1351. const hexTx = yield Promise.resolve(signedTransaction).then(t => hexlify(t));
  1352. const tx = this.formatter.transaction(signedTransaction);
  1353. if (tx.confirmations == null) {
  1354. tx.confirmations = 0;
  1355. }
  1356. const blockNumber = yield this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
  1357. try {
  1358. const hash = yield this.perform("sendTransaction", { signedTransaction: hexTx });
  1359. return this._wrapTransaction(tx, hash, blockNumber);
  1360. }
  1361. catch (error) {
  1362. error.transaction = tx;
  1363. error.transactionHash = tx.hash;
  1364. throw error;
  1365. }
  1366. });
  1367. }
  1368. _getTransactionRequest(transaction) {
  1369. return __awaiter(this, void 0, void 0, function* () {
  1370. const values = yield transaction;
  1371. const tx = {};
  1372. ["from", "to"].forEach((key) => {
  1373. if (values[key] == null) {
  1374. return;
  1375. }
  1376. tx[key] = Promise.resolve(values[key]).then((v) => (v ? this._getAddress(v) : null));
  1377. });
  1378. ["gasLimit", "gasPrice", "maxFeePerGas", "maxPriorityFeePerGas", "value"].forEach((key) => {
  1379. if (values[key] == null) {
  1380. return;
  1381. }
  1382. tx[key] = Promise.resolve(values[key]).then((v) => (v ? BigNumber.from(v) : null));
  1383. });
  1384. ["type"].forEach((key) => {
  1385. if (values[key] == null) {
  1386. return;
  1387. }
  1388. tx[key] = Promise.resolve(values[key]).then((v) => ((v != null) ? v : null));
  1389. });
  1390. if (values.accessList) {
  1391. tx.accessList = this.formatter.accessList(values.accessList);
  1392. }
  1393. ["data"].forEach((key) => {
  1394. if (values[key] == null) {
  1395. return;
  1396. }
  1397. tx[key] = Promise.resolve(values[key]).then((v) => (v ? hexlify(v) : null));
  1398. });
  1399. return this.formatter.transactionRequest(yield resolveProperties(tx));
  1400. });
  1401. }
  1402. _getFilter(filter) {
  1403. return __awaiter(this, void 0, void 0, function* () {
  1404. filter = yield filter;
  1405. const result = {};
  1406. if (filter.address != null) {
  1407. result.address = this._getAddress(filter.address);
  1408. }
  1409. ["blockHash", "topics"].forEach((key) => {
  1410. if (filter[key] == null) {
  1411. return;
  1412. }
  1413. result[key] = filter[key];
  1414. });
  1415. ["fromBlock", "toBlock"].forEach((key) => {
  1416. if (filter[key] == null) {
  1417. return;
  1418. }
  1419. result[key] = this._getBlockTag(filter[key]);
  1420. });
  1421. return this.formatter.filter(yield resolveProperties(result));
  1422. });
  1423. }
  1424. _call(transaction, blockTag, attempt) {
  1425. return __awaiter(this, void 0, void 0, function* () {
  1426. if (attempt >= MAX_CCIP_REDIRECTS) {
  1427. logger.throwError("CCIP read exceeded maximum redirections", Logger.errors.SERVER_ERROR, {
  1428. redirects: attempt, transaction
  1429. });
  1430. }
  1431. const txSender = transaction.to;
  1432. const result = yield this.perform("call", { transaction, blockTag });
  1433. // CCIP Read request via OffchainLookup(address,string[],bytes,bytes4,bytes)
  1434. if (attempt >= 0 && blockTag === "latest" && txSender != null && result.substring(0, 10) === "0x556f1830" && (hexDataLength(result) % 32 === 4)) {
  1435. try {
  1436. const data = hexDataSlice(result, 4);
  1437. // Check the sender of the OffchainLookup matches the transaction
  1438. const sender = hexDataSlice(data, 0, 32);
  1439. if (!BigNumber.from(sender).eq(txSender)) {
  1440. logger.throwError("CCIP Read sender did not match", Logger.errors.CALL_EXCEPTION, {
  1441. name: "OffchainLookup",
  1442. signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
  1443. transaction, data: result
  1444. });
  1445. }
  1446. // Read the URLs from the response
  1447. const urls = [];
  1448. const urlsOffset = BigNumber.from(hexDataSlice(data, 32, 64)).toNumber();
  1449. const urlsLength = BigNumber.from(hexDataSlice(data, urlsOffset, urlsOffset + 32)).toNumber();
  1450. const urlsData = hexDataSlice(data, urlsOffset + 32);
  1451. for (let u = 0; u < urlsLength; u++) {
  1452. const url = _parseString(urlsData, u * 32);
  1453. if (url == null) {
  1454. logger.throwError("CCIP Read contained corrupt URL string", Logger.errors.CALL_EXCEPTION, {
  1455. name: "OffchainLookup",
  1456. signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
  1457. transaction, data: result
  1458. });
  1459. }
  1460. urls.push(url);
  1461. }
  1462. // Get the CCIP calldata to forward
  1463. const calldata = _parseBytes(data, 64);
  1464. // Get the callbackSelector (bytes4)
  1465. if (!BigNumber.from(hexDataSlice(data, 100, 128)).isZero()) {
  1466. logger.throwError("CCIP Read callback selector included junk", Logger.errors.CALL_EXCEPTION, {
  1467. name: "OffchainLookup",
  1468. signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
  1469. transaction, data: result
  1470. });
  1471. }
  1472. const callbackSelector = hexDataSlice(data, 96, 100);
  1473. // Get the extra data to send back to the contract as context
  1474. const extraData = _parseBytes(data, 128);
  1475. const ccipResult = yield this.ccipReadFetch(transaction, calldata, urls);
  1476. if (ccipResult == null) {
  1477. logger.throwError("CCIP Read disabled or provided no URLs", Logger.errors.CALL_EXCEPTION, {
  1478. name: "OffchainLookup",
  1479. signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
  1480. transaction, data: result
  1481. });
  1482. }
  1483. const tx = {
  1484. to: txSender,
  1485. data: hexConcat([callbackSelector, encodeBytes([ccipResult, extraData])])
  1486. };
  1487. return this._call(tx, blockTag, attempt + 1);
  1488. }
  1489. catch (error) {
  1490. if (error.code === Logger.errors.SERVER_ERROR) {
  1491. throw error;
  1492. }
  1493. }
  1494. }
  1495. try {
  1496. return hexlify(result);
  1497. }
  1498. catch (error) {
  1499. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1500. method: "call",
  1501. params: { transaction, blockTag }, result, error
  1502. });
  1503. }
  1504. });
  1505. }
  1506. call(transaction, blockTag) {
  1507. return __awaiter(this, void 0, void 0, function* () {
  1508. yield this.getNetwork();
  1509. const resolved = yield resolveProperties({
  1510. transaction: this._getTransactionRequest(transaction),
  1511. blockTag: this._getBlockTag(blockTag),
  1512. ccipReadEnabled: Promise.resolve(transaction.ccipReadEnabled)
  1513. });
  1514. return this._call(resolved.transaction, resolved.blockTag, resolved.ccipReadEnabled ? 0 : -1);
  1515. });
  1516. }
  1517. estimateGas(transaction) {
  1518. return __awaiter(this, void 0, void 0, function* () {
  1519. yield this.getNetwork();
  1520. const params = yield resolveProperties({
  1521. transaction: this._getTransactionRequest(transaction)
  1522. });
  1523. const result = yield this.perform("estimateGas", params);
  1524. try {
  1525. return BigNumber.from(result);
  1526. }
  1527. catch (error) {
  1528. return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
  1529. method: "estimateGas",
  1530. params, result, error
  1531. });
  1532. }
  1533. });
  1534. }
  1535. _getAddress(addressOrName) {
  1536. return __awaiter(this, void 0, void 0, function* () {
  1537. addressOrName = yield addressOrName;
  1538. if (typeof (addressOrName) !== "string") {
  1539. logger.throwArgumentError("invalid address or ENS name", "name", addressOrName);
  1540. }
  1541. const address = yield this.resolveName(addressOrName);
  1542. if (address == null) {
  1543. logger.throwError("ENS name not configured", Logger.errors.UNSUPPORTED_OPERATION, {
  1544. operation: `resolveName(${JSON.stringify(addressOrName)})`
  1545. });
  1546. }
  1547. return address;
  1548. });
  1549. }
  1550. _getBlock(blockHashOrBlockTag, includeTransactions) {
  1551. return __awaiter(this, void 0, void 0, function* () {
  1552. yield this.getNetwork();
  1553. blockHashOrBlockTag = yield blockHashOrBlockTag;
  1554. // If blockTag is a number (not "latest", etc), this is the block number
  1555. let blockNumber = -128;
  1556. const params = {
  1557. includeTransactions: !!includeTransactions
  1558. };
  1559. if (isHexString(blockHashOrBlockTag, 32)) {
  1560. params.blockHash = blockHashOrBlockTag;
  1561. }
  1562. else {
  1563. try {
  1564. params.blockTag = yield this._getBlockTag(blockHashOrBlockTag);
  1565. if (isHexString(params.blockTag)) {
  1566. blockNumber = parseInt(params.blockTag.substring(2), 16);
  1567. }
  1568. }
  1569. catch (error) {
  1570. logger.throwArgumentError("invalid block hash or block tag", "blockHashOrBlockTag", blockHashOrBlockTag);
  1571. }
  1572. }
  1573. return poll(() => __awaiter(this, void 0, void 0, function* () {
  1574. const block = yield this.perform("getBlock", params);
  1575. // Block was not found
  1576. if (block == null) {
  1577. // For blockhashes, if we didn't say it existed, that blockhash may
  1578. // not exist. If we did see it though, perhaps from a log, we know
  1579. // it exists, and this node is just not caught up yet.
  1580. if (params.blockHash != null) {
  1581. if (this._emitted["b:" + params.blockHash] == null) {
  1582. return null;
  1583. }
  1584. }
  1585. // For block tags, if we are asking for a future block, we return null
  1586. if (params.blockTag != null) {
  1587. if (blockNumber > this._emitted.block) {
  1588. return null;
  1589. }
  1590. }
  1591. // Retry on the next block
  1592. return undefined;
  1593. }
  1594. // Add transactions
  1595. if (includeTransactions) {
  1596. let blockNumber = null;
  1597. for (let i = 0; i < block.transactions.length; i++) {
  1598. const tx = block.transactions[i];
  1599. if (tx.blockNumber == null) {
  1600. tx.confirmations = 0;
  1601. }
  1602. else if (tx.confirmations == null) {
  1603. if (blockNumber == null) {
  1604. blockNumber = yield this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
  1605. }
  1606. // Add the confirmations using the fast block number (pessimistic)
  1607. let confirmations = (blockNumber - tx.blockNumber) + 1;
  1608. if (confirmations <= 0) {
  1609. confirmations = 1;
  1610. }
  1611. tx.confirmations = confirmations;
  1612. }
  1613. }
  1614. const blockWithTxs = this.formatter.blockWithTransactions(block);
  1615. blockWithTxs.transactions = blockWithTxs.transactions.map((tx) => this._wrapTransaction(tx));
  1616. return blockWithTxs;
  1617. }
  1618. return this.formatter.block(block);
  1619. }), { oncePoll: this });
  1620. });
  1621. }
  1622. getBlock(blockHashOrBlockTag) {
  1623. return (this._getBlock(blockHashOrBlockTag, false));
  1624. }
  1625. getBlockWithTransactions(blockHashOrBlockTag) {
  1626. return (this._getBlock(blockHashOrBlockTag, true));
  1627. }
  1628. getTransaction(transactionHash) {
  1629. return __awaiter(this, void 0, void 0, function* () {
  1630. yield this.getNetwork();
  1631. transactionHash = yield transactionHash;
  1632. const params = { transactionHash: this.formatter.hash(transactionHash, true) };
  1633. return poll(() => __awaiter(this, void 0, void 0, function* () {
  1634. const result = yield this.perform("getTransaction", params);
  1635. if (result == null) {
  1636. if (this._emitted["t:" + transactionHash] == null) {
  1637. return null;
  1638. }
  1639. return undefined;
  1640. }
  1641. const tx = this.formatter.transactionResponse(result);
  1642. if (tx.blockNumber == null) {
  1643. tx.confirmations = 0;
  1644. }
  1645. else if (tx.confirmations == null) {
  1646. const blockNumber = yield this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
  1647. // Add the confirmations using the fast block number (pessimistic)
  1648. let confirmations = (blockNumber - tx.blockNumber) + 1;
  1649. if (confirmations <= 0) {
  1650. confirmations = 1;
  1651. }
  1652. tx.confirmations = confirmations;
  1653. }
  1654. return this._wrapTransaction(tx);
  1655. }), { oncePoll: this });
  1656. });
  1657. }
  1658. getTransactionReceipt(transactionHash) {
  1659. return __awaiter(this, void 0, void 0, function* () {
  1660. yield this.getNetwork();
  1661. transactionHash = yield transactionHash;
  1662. const params = { transactionHash: this.formatter.hash(transactionHash, true) };
  1663. return poll(() => __awaiter(this, void 0, void 0, function* () {
  1664. const result = yield this.perform("getTransactionReceipt", params);
  1665. if (result == null) {
  1666. if (this._emitted["t:" + transactionHash] == null) {
  1667. return null;
  1668. }
  1669. return undefined;
  1670. }
  1671. // "geth-etc" returns receipts before they are ready
  1672. if (result.blockHash == null) {
  1673. return undefined;
  1674. }
  1675. const receipt = this.formatter.receipt(result);
  1676. if (receipt.blockNumber == null) {
  1677. receipt.confirmations = 0;
  1678. }
  1679. else if (receipt.confirmations == null) {
  1680. const blockNumber = yield this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
  1681. // Add the confirmations using the fast block number (pessimistic)
  1682. let confirmations = (blockNumber - receipt.blockNumber) + 1;
  1683. if (confirmations <= 0) {
  1684. confirmations = 1;
  1685. }
  1686. receipt.confirmations = confirmations;
  1687. }
  1688. return receipt;
  1689. }), { oncePoll: this });
  1690. });
  1691. }
  1692. getLogs(filter) {
  1693. return __awaiter(this, void 0, void 0, function* () {
  1694. yield this.getNetwork();
  1695. const params = yield resolveProperties({ filter: this._getFilter(filter) });
  1696. const logs = yield this.perform("getLogs", params);
  1697. logs.forEach((log) => {
  1698. if (log.removed == null) {
  1699. log.removed = false;
  1700. }
  1701. });
  1702. return Formatter.arrayOf(this.formatter.filterLog.bind(this.formatter))(logs);
  1703. });
  1704. }
  1705. getEtherPrice() {
  1706. return __awaiter(this, void 0, void 0, function* () {
  1707. yield this.getNetwork();
  1708. return this.perform("getEtherPrice", {});
  1709. });
  1710. }
  1711. _getBlockTag(blockTag) {
  1712. return __awaiter(this, void 0, void 0, function* () {
  1713. blockTag = yield blockTag;
  1714. if (typeof (blockTag) === "number" && blockTag < 0) {
  1715. if (blockTag % 1) {
  1716. logger.throwArgumentError("invalid BlockTag", "blockTag", blockTag);
  1717. }
  1718. let blockNumber = yield this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
  1719. blockNumber += blockTag;
  1720. if (blockNumber < 0) {
  1721. blockNumber = 0;
  1722. }
  1723. return this.formatter.blockTag(blockNumber);
  1724. }
  1725. return this.formatter.blockTag(blockTag);
  1726. });
  1727. }
  1728. getResolver(name) {
  1729. return __awaiter(this, void 0, void 0, function* () {
  1730. let currentName = name;
  1731. while (true) {
  1732. if (currentName === "" || currentName === ".") {
  1733. return null;
  1734. }
  1735. // Optimization since the eth node cannot change and does
  1736. // not have a wildcar resolver
  1737. if (name !== "eth" && currentName === "eth") {
  1738. return null;
  1739. }
  1740. // Check the current node for a resolver
  1741. const addr = yield this._getResolver(currentName, "getResolver");
  1742. // Found a resolver!
  1743. if (addr != null) {
  1744. const resolver = new Resolver(this, addr, name);
  1745. // Legacy resolver found, using EIP-2544 so it isn't safe to use
  1746. if (currentName !== name && !(yield resolver.supportsWildcard())) {
  1747. return null;
  1748. }
  1749. return resolver;
  1750. }
  1751. // Get the parent node
  1752. currentName = currentName.split(".").slice(1).join(".");
  1753. }
  1754. });
  1755. }
  1756. _getResolver(name, operation) {
  1757. return __awaiter(this, void 0, void 0, function* () {
  1758. if (operation == null) {
  1759. operation = "ENS";
  1760. }
  1761. const network = yield this.getNetwork();
  1762. // No ENS...
  1763. if (!network.ensAddress) {
  1764. logger.throwError("network does not support ENS", Logger.errors.UNSUPPORTED_OPERATION, { operation, network: network.name });
  1765. }
  1766. try {
  1767. // keccak256("resolver(bytes32)")
  1768. const addrData = yield this.call({
  1769. to: network.ensAddress,
  1770. data: ("0x0178b8bf" + namehash(name).substring(2))
  1771. });
  1772. return this.formatter.callAddress(addrData);
  1773. }
  1774. catch (error) {
  1775. // ENS registry cannot throw errors on resolver(bytes32)
  1776. }
  1777. return null;
  1778. });
  1779. }
  1780. resolveName(name) {
  1781. return __awaiter(this, void 0, void 0, function* () {
  1782. name = yield name;
  1783. // If it is already an address, nothing to resolve
  1784. try {
  1785. return Promise.resolve(this.formatter.address(name));
  1786. }
  1787. catch (error) {
  1788. // If is is a hexstring, the address is bad (See #694)
  1789. if (isHexString(name)) {
  1790. throw error;
  1791. }
  1792. }
  1793. if (typeof (name) !== "string") {
  1794. logger.throwArgumentError("invalid ENS name", "name", name);
  1795. }
  1796. // Get the addr from the resovler
  1797. const resolver = yield this.getResolver(name);
  1798. if (!resolver) {
  1799. return null;
  1800. }
  1801. return yield resolver.getAddress();
  1802. });
  1803. }
  1804. lookupAddress(address) {
  1805. return __awaiter(this, void 0, void 0, function* () {
  1806. address = yield address;
  1807. address = this.formatter.address(address);
  1808. const node = address.substring(2).toLowerCase() + ".addr.reverse";
  1809. const resolverAddr = yield this._getResolver(node, "lookupAddress");
  1810. if (resolverAddr == null) {
  1811. return null;
  1812. }
  1813. // keccak("name(bytes32)")
  1814. const name = _parseString(yield this.call({
  1815. to: resolverAddr,
  1816. data: ("0x691f3431" + namehash(node).substring(2))
  1817. }), 0);
  1818. const addr = yield this.resolveName(name);
  1819. if (addr != address) {
  1820. return null;
  1821. }
  1822. return name;
  1823. });
  1824. }
  1825. getAvatar(nameOrAddress) {
  1826. return __awaiter(this, void 0, void 0, function* () {
  1827. let resolver = null;
  1828. if (isHexString(nameOrAddress)) {
  1829. // Address; reverse lookup
  1830. const address = this.formatter.address(nameOrAddress);
  1831. const node = address.substring(2).toLowerCase() + ".addr.reverse";
  1832. const resolverAddress = yield this._getResolver(node, "getAvatar");
  1833. if (!resolverAddress) {
  1834. return null;
  1835. }
  1836. // Try resolving the avatar against the addr.reverse resolver
  1837. resolver = new Resolver(this, resolverAddress, node);
  1838. try {
  1839. const avatar = yield resolver.getAvatar();
  1840. if (avatar) {
  1841. return avatar.url;
  1842. }
  1843. }
  1844. catch (error) {
  1845. if (error.code !== Logger.errors.CALL_EXCEPTION) {
  1846. throw error;
  1847. }
  1848. }
  1849. // Try getting the name and performing forward lookup; allowing wildcards
  1850. try {
  1851. // keccak("name(bytes32)")
  1852. const name = _parseString(yield this.call({
  1853. to: resolverAddress,
  1854. data: ("0x691f3431" + namehash(node).substring(2))
  1855. }), 0);
  1856. resolver = yield this.getResolver(name);
  1857. }
  1858. catch (error) {
  1859. if (error.code !== Logger.errors.CALL_EXCEPTION) {
  1860. throw error;
  1861. }
  1862. return null;
  1863. }
  1864. }
  1865. else {
  1866. // ENS name; forward lookup with wildcard
  1867. resolver = yield this.getResolver(nameOrAddress);
  1868. if (!resolver) {
  1869. return null;
  1870. }
  1871. }
  1872. const avatar = yield resolver.getAvatar();
  1873. if (avatar == null) {
  1874. return null;
  1875. }
  1876. return avatar.url;
  1877. });
  1878. }
  1879. perform(method, params) {
  1880. return logger.throwError(method + " not implemented", Logger.errors.NOT_IMPLEMENTED, { operation: method });
  1881. }
  1882. _startEvent(event) {
  1883. this.polling = (this._events.filter((e) => e.pollable()).length > 0);
  1884. }
  1885. _stopEvent(event) {
  1886. this.polling = (this._events.filter((e) => e.pollable()).length > 0);
  1887. }
  1888. _addEventListener(eventName, listener, once) {
  1889. const event = new Event(getEventTag(eventName), listener, once);
  1890. this._events.push(event);
  1891. this._startEvent(event);
  1892. return this;
  1893. }
  1894. on(eventName, listener) {
  1895. return this._addEventListener(eventName, listener, false);
  1896. }
  1897. once(eventName, listener) {
  1898. return this._addEventListener(eventName, listener, true);
  1899. }
  1900. emit(eventName, ...args) {
  1901. let result = false;
  1902. let stopped = [];
  1903. let eventTag = getEventTag(eventName);
  1904. this._events = this._events.filter((event) => {
  1905. if (event.tag !== eventTag) {
  1906. return true;
  1907. }
  1908. setTimeout(() => {
  1909. event.listener.apply(this, args);
  1910. }, 0);
  1911. result = true;
  1912. if (event.once) {
  1913. stopped.push(event);
  1914. return false;
  1915. }
  1916. return true;
  1917. });
  1918. stopped.forEach((event) => { this._stopEvent(event); });
  1919. return result;
  1920. }
  1921. listenerCount(eventName) {
  1922. if (!eventName) {
  1923. return this._events.length;
  1924. }
  1925. let eventTag = getEventTag(eventName);
  1926. return this._events.filter((event) => {
  1927. return (event.tag === eventTag);
  1928. }).length;
  1929. }
  1930. listeners(eventName) {
  1931. if (eventName == null) {
  1932. return this._events.map((event) => event.listener);
  1933. }
  1934. let eventTag = getEventTag(eventName);
  1935. return this._events
  1936. .filter((event) => (event.tag === eventTag))
  1937. .map((event) => event.listener);
  1938. }
  1939. off(eventName, listener) {
  1940. if (listener == null) {
  1941. return this.removeAllListeners(eventName);
  1942. }
  1943. const stopped = [];
  1944. let found = false;
  1945. let eventTag = getEventTag(eventName);
  1946. this._events = this._events.filter((event) => {
  1947. if (event.tag !== eventTag || event.listener != listener) {
  1948. return true;
  1949. }
  1950. if (found) {
  1951. return true;
  1952. }
  1953. found = true;
  1954. stopped.push(event);
  1955. return false;
  1956. });
  1957. stopped.forEach((event) => { this._stopEvent(event); });
  1958. return this;
  1959. }
  1960. removeAllListeners(eventName) {
  1961. let stopped = [];
  1962. if (eventName == null) {
  1963. stopped = this._events;
  1964. this._events = [];
  1965. }
  1966. else {
  1967. const eventTag = getEventTag(eventName);
  1968. this._events = this._events.filter((event) => {
  1969. if (event.tag !== eventTag) {
  1970. return true;
  1971. }
  1972. stopped.push(event);
  1973. return false;
  1974. });
  1975. }
  1976. stopped.forEach((event) => { this._stopEvent(event); });
  1977. return this;
  1978. }
  1979. }
  1980. //# sourceMappingURL=base-provider.js.map