interface.js 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. "use strict";
  2. /**
  3. * The Interface class is a low-level class that accepts an
  4. * ABI and provides all the necessary functionality to encode
  5. * and decode paramaters to and results from methods, events
  6. * and errors.
  7. *
  8. * It also provides several convenience methods to automatically
  9. * search and find matching transactions and events to parse them.
  10. *
  11. * @_subsection api/abi:Interfaces [interfaces]
  12. */
  13. Object.defineProperty(exports, "__esModule", { value: true });
  14. exports.Interface = exports.Indexed = exports.ErrorDescription = exports.TransactionDescription = exports.LogDescription = exports.Result = exports.checkResultErrors = void 0;
  15. const ethers_1 = require("ethers");
  16. const ethers_2 = require("ethers");
  17. const ethers_3 = require("ethers");
  18. const ethers_4 = require("ethers");
  19. const ethers_5 = require("ethers");
  20. Object.defineProperty(exports, "checkResultErrors", { enumerable: true, get: function () { return ethers_5.checkResultErrors; } });
  21. Object.defineProperty(exports, "Result", { enumerable: true, get: function () { return ethers_5.Result; } });
  22. const fragments_js_1 = require("./fragments.js");
  23. const ethers_6 = require("ethers");
  24. /**
  25. * When using the [[Interface-parseLog]] to automatically match a Log to its event
  26. * for parsing, a **LogDescription** is returned.
  27. */
  28. class LogDescription {
  29. /**
  30. * The matching fragment for the ``topic0``.
  31. */
  32. fragment;
  33. /**
  34. * The name of the Event.
  35. */
  36. name;
  37. /**
  38. * The full Event signature.
  39. */
  40. signature;
  41. /**
  42. * The topic hash for the Event.
  43. */
  44. topic;
  45. /**
  46. * The arguments passed into the Event with ``emit``.
  47. */
  48. args;
  49. /**
  50. * @_ignore:
  51. */
  52. constructor(fragment, topic, args) {
  53. const name = fragment.name, signature = fragment.format();
  54. (0, ethers_3.defineProperties)(this, {
  55. fragment,
  56. name,
  57. signature,
  58. topic,
  59. args,
  60. });
  61. }
  62. }
  63. exports.LogDescription = LogDescription;
  64. /**
  65. * When using the [[Interface-parseTransaction]] to automatically match
  66. * a transaction data to its function for parsing,
  67. * a **TransactionDescription** is returned.
  68. */
  69. class TransactionDescription {
  70. /**
  71. * The matching fragment from the transaction ``data``.
  72. */
  73. fragment;
  74. /**
  75. * The name of the Function from the transaction ``data``.
  76. */
  77. name;
  78. /**
  79. * The arguments passed to the Function from the transaction ``data``.
  80. */
  81. args;
  82. /**
  83. * The full Function signature from the transaction ``data``.
  84. */
  85. signature;
  86. /**
  87. * The selector for the Function from the transaction ``data``.
  88. */
  89. selector;
  90. /**
  91. * The ``value`` (in wei) from the transaction.
  92. */
  93. value;
  94. /**
  95. * @_ignore:
  96. */
  97. constructor(fragment, selector, args, value) {
  98. const name = fragment.name, signature = fragment.format();
  99. (0, ethers_3.defineProperties)(this, {
  100. fragment,
  101. name,
  102. args,
  103. signature,
  104. selector,
  105. value,
  106. });
  107. }
  108. }
  109. exports.TransactionDescription = TransactionDescription;
  110. /**
  111. * When using the [[Interface-parseError]] to automatically match an
  112. * error for a call result for parsing, an **ErrorDescription** is returned.
  113. */
  114. class ErrorDescription {
  115. /**
  116. * The matching fragment.
  117. */
  118. fragment;
  119. /**
  120. * The name of the Error.
  121. */
  122. name;
  123. /**
  124. * The arguments passed to the Error with ``revert``.
  125. */
  126. args;
  127. /**
  128. * The full Error signature.
  129. */
  130. signature;
  131. /**
  132. * The selector for the Error.
  133. */
  134. selector;
  135. /**
  136. * @_ignore:
  137. */
  138. constructor(fragment, selector, args) {
  139. const name = fragment.name, signature = fragment.format();
  140. (0, ethers_3.defineProperties)(this, {
  141. fragment,
  142. name,
  143. args,
  144. signature,
  145. selector,
  146. });
  147. }
  148. }
  149. exports.ErrorDescription = ErrorDescription;
  150. /**
  151. * An **Indexed** is used as a value when a value that does not
  152. * fit within a topic (i.e. not a fixed-length, 32-byte type). It
  153. * is the ``keccak256`` of the value, and used for types such as
  154. * arrays, tuples, bytes and strings.
  155. */
  156. class Indexed {
  157. /**
  158. * The ``keccak256`` of the value logged.
  159. */
  160. hash;
  161. /**
  162. * @_ignore:
  163. */
  164. _isIndexed;
  165. /**
  166. * Returns ``true`` if %%value%% is an **Indexed**.
  167. *
  168. * This provides a Type Guard for property access.
  169. */
  170. static isIndexed(value) {
  171. return !!(value && value._isIndexed);
  172. }
  173. /**
  174. * @_ignore:
  175. */
  176. constructor(hash) {
  177. (0, ethers_3.defineProperties)(this, { hash, _isIndexed: true });
  178. }
  179. }
  180. exports.Indexed = Indexed;
  181. // https://docs.soliditylang.org/en/v0.8.13/control-structures.html?highlight=panic#panic-via-assert-and-error-via-require
  182. const PanicReasons = {
  183. '0': 'generic panic',
  184. '1': 'assert(false)',
  185. '17': 'arithmetic overflow',
  186. '18': 'division or modulo by zero',
  187. '33': 'enum overflow',
  188. '34': 'invalid encoded storage byte array accessed',
  189. '49': 'out-of-bounds array access; popping on an empty array',
  190. '50': 'out-of-bounds access of an array or bytesN',
  191. '65': 'out of memory',
  192. '81': 'uninitialized function',
  193. };
  194. const BuiltinErrors = {
  195. '0x08c379a0': {
  196. signature: 'Error(string)',
  197. name: 'Error',
  198. inputs: ['string'],
  199. reason: (message) => {
  200. return `reverted with reason string ${JSON.stringify(message)}`;
  201. },
  202. },
  203. '0x4e487b71': {
  204. signature: 'Panic(uint256)',
  205. name: 'Panic',
  206. inputs: ['uint256'],
  207. reason: (code) => {
  208. let reason = 'unknown panic code';
  209. if (code >= 0 && code <= 0xff && PanicReasons[code.toString()]) {
  210. reason = PanicReasons[code.toString()];
  211. }
  212. return `reverted with panic code 0x${code.toString(16)} (${reason})`;
  213. },
  214. },
  215. };
  216. /**
  217. * An Interface abstracts many of the low-level details for
  218. * encoding and decoding the data on the blockchain.
  219. *
  220. * An ABI provides information on how to encode data to send to
  221. * a Contract, how to decode the results and events and how to
  222. * interpret revert errors.
  223. *
  224. * The ABI can be specified by [any supported format](InterfaceAbi).
  225. */
  226. class Interface {
  227. /**
  228. * All the Contract ABI members (i.e. methods, events, errors, etc).
  229. */
  230. fragments;
  231. /**
  232. * The Contract constructor.
  233. */
  234. deploy;
  235. /**
  236. * The Fallback method, if any.
  237. */
  238. fallback;
  239. /**
  240. * If receiving ether is supported.
  241. */
  242. receive;
  243. #errors;
  244. #events;
  245. #functions;
  246. // #structs: Map<string, StructFragment>;
  247. #abiCoder;
  248. /**
  249. * Create a new Interface for the %%fragments%%.
  250. */
  251. constructor(fragments) {
  252. let abi = [];
  253. if (typeof fragments === 'string') {
  254. abi = JSON.parse(fragments);
  255. }
  256. else {
  257. abi = fragments;
  258. }
  259. this.#functions = new Map();
  260. this.#errors = new Map();
  261. this.#events = new Map();
  262. // this.#structs = new Map();
  263. const frags = [];
  264. for (const a of abi) {
  265. try {
  266. frags.push(fragments_js_1.Fragment.from(a));
  267. }
  268. catch (error) {
  269. console.log('EE', error);
  270. }
  271. }
  272. (0, ethers_3.defineProperties)(this, {
  273. fragments: Object.freeze(frags),
  274. });
  275. let fallback = null;
  276. let receive = false;
  277. this.#abiCoder = this.getAbiCoder();
  278. // Add all fragments by their signature
  279. this.fragments.forEach((fragment, index) => {
  280. let bucket;
  281. switch (fragment.type) {
  282. case 'constructor':
  283. if (this.deploy) {
  284. console.log('duplicate definition - constructor');
  285. return;
  286. }
  287. //checkNames(fragment, "input", fragment.inputs);
  288. (0, ethers_3.defineProperties)(this, {
  289. deploy: fragment,
  290. });
  291. return;
  292. case 'fallback':
  293. if (fragment.inputs.length === 0) {
  294. receive = true;
  295. }
  296. else {
  297. (0, ethers_3.assertArgument)(!fallback || fragment.payable !== fallback.payable, 'conflicting fallback fragments', `fragments[${index}]`, fragment);
  298. fallback = fragment;
  299. receive = fallback.payable;
  300. }
  301. return;
  302. case 'function':
  303. //checkNames(fragment, "input", fragment.inputs);
  304. //checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
  305. bucket = this.#functions;
  306. break;
  307. case 'event':
  308. //checkNames(fragment, "input", fragment.inputs);
  309. bucket = this.#events;
  310. break;
  311. case 'error':
  312. bucket = this.#errors;
  313. break;
  314. default:
  315. return;
  316. }
  317. // Two identical entries; ignore it
  318. const signature = fragment.format();
  319. if (bucket.has(signature)) {
  320. return;
  321. }
  322. bucket.set(signature, fragment);
  323. });
  324. // If we do not have a constructor add a default
  325. if (!this.deploy) {
  326. (0, ethers_3.defineProperties)(this, {
  327. deploy: fragments_js_1.ConstructorFragment.from('constructor()'),
  328. });
  329. }
  330. (0, ethers_3.defineProperties)(this, { fallback, receive });
  331. }
  332. /**
  333. * Returns the entire Human-Readable ABI, as an array of
  334. * signatures, optionally as %%minimal%% strings, which
  335. * removes parameter names and unneceesary spaces.
  336. */
  337. format(minimal) {
  338. const format = minimal ? 'minimal' : 'full';
  339. const abi = this.fragments.map((f) => f.format(format));
  340. return abi;
  341. }
  342. /**
  343. * Return the JSON-encoded ABI. This is the format Solidiy
  344. * returns.
  345. */
  346. formatJson() {
  347. const abi = this.fragments.map((f) => f.format('json'));
  348. // We need to re-bundle the JSON fragments a bit
  349. return JSON.stringify(abi.map((j) => JSON.parse(j)));
  350. }
  351. /**
  352. * The ABI coder that will be used to encode and decode binary
  353. * data.
  354. */
  355. getAbiCoder() {
  356. return ethers_4.AbiCoder.defaultAbiCoder();
  357. }
  358. // Find a function definition by any means necessary (unless it is ambiguous)
  359. #getFunction(key, values, forceUnique) {
  360. // Selector
  361. if ((0, ethers_3.isHexString)(key)) {
  362. const selector = key.toLowerCase();
  363. for (const fragment of this.#functions.values()) {
  364. if (selector === fragment.selector) {
  365. return fragment;
  366. }
  367. }
  368. return null;
  369. }
  370. // It is a bare name, look up the function (will return null if ambiguous)
  371. if (key.indexOf('(') === -1) {
  372. const matching = [];
  373. for (const [name, fragment] of this.#functions) {
  374. if (name.split('(' /* fix:) */)[0] === key) {
  375. matching.push(fragment);
  376. }
  377. }
  378. if (values) {
  379. const lastValue = values.length > 0 ? values[values.length - 1] : null;
  380. let valueLength = values.length;
  381. let allowOptions = true;
  382. if (ethers_6.Typed.isTyped(lastValue) && lastValue.type === 'overrides') {
  383. allowOptions = false;
  384. valueLength--;
  385. }
  386. // Remove all matches that don't have a compatible length. The args
  387. // may contain an overrides, so the match may have n or n - 1 parameters
  388. for (let i = matching.length - 1; i >= 0; i--) {
  389. const inputs = matching[i].inputs.length;
  390. if (inputs !== valueLength && (!allowOptions || inputs !== valueLength - 1)) {
  391. matching.splice(i, 1);
  392. }
  393. }
  394. // Remove all matches that don't match the Typed signature
  395. for (let i = matching.length - 1; i >= 0; i--) {
  396. const inputs = matching[i].inputs;
  397. for (let j = 0; j < values.length; j++) {
  398. // Not a typed value
  399. if (!ethers_6.Typed.isTyped(values[j])) {
  400. continue;
  401. }
  402. // We are past the inputs
  403. if (j >= inputs.length) {
  404. if (values[j].type === 'overrides') {
  405. continue;
  406. }
  407. matching.splice(i, 1);
  408. break;
  409. }
  410. // Make sure the value type matches the input type
  411. if (values[j].type !== inputs[j].baseType) {
  412. matching.splice(i, 1);
  413. break;
  414. }
  415. }
  416. }
  417. }
  418. // We found a single matching signature with an overrides, but the
  419. // last value is something that cannot possibly be an options
  420. if (matching.length === 1 && values && values.length !== matching[0].inputs.length) {
  421. const lastArg = values[values.length - 1];
  422. if (lastArg == null || Array.isArray(lastArg) || typeof lastArg !== 'object') {
  423. matching.splice(0, 1);
  424. }
  425. }
  426. if (matching.length === 0) {
  427. return null;
  428. }
  429. if (matching.length > 1 && forceUnique) {
  430. const matchStr = matching.map((m) => JSON.stringify(m.format())).join(', ');
  431. (0, ethers_3.assertArgument)(false, `ambiguous function description (i.e. matches ${matchStr})`, 'key', key);
  432. }
  433. return matching[0];
  434. }
  435. // Normalize the signature and lookup the function
  436. const result = this.#functions.get(fragments_js_1.FunctionFragment.from(key).format());
  437. if (result) {
  438. return result;
  439. }
  440. return null;
  441. }
  442. /**
  443. * Get the function name for %%key%%, which may be a function selector,
  444. * function name or function signature that belongs to the ABI.
  445. */
  446. getFunctionName(key) {
  447. const fragment = this.#getFunction(key, null, false);
  448. (0, ethers_3.assertArgument)(fragment, 'no matching function', 'key', key);
  449. return fragment.name;
  450. }
  451. /**
  452. * Returns true if %%key%% (a function selector, function name or
  453. * function signature) is present in the ABI.
  454. *
  455. * In the case of a function name, the name may be ambiguous, so
  456. * accessing the [[FunctionFragment]] may require refinement.
  457. */
  458. hasFunction(key) {
  459. return !!this.#getFunction(key, null, false);
  460. }
  461. /**
  462. * Get the [[FunctionFragment]] for %%key%%, which may be a function
  463. * selector, function name or function signature that belongs to the ABI.
  464. *
  465. * If %%values%% is provided, it will use the Typed API to handle
  466. * ambiguous cases where multiple functions match by name.
  467. *
  468. * If the %%key%% and %%values%% do not refine to a single function in
  469. * the ABI, this will throw.
  470. */
  471. getFunction(key, values) {
  472. return this.#getFunction(key, values || null, true);
  473. }
  474. /**
  475. * Iterate over all functions, calling %%callback%%, sorted by their name.
  476. */
  477. forEachFunction(callback) {
  478. const names = Array.from(this.#functions.keys());
  479. names.sort((a, b) => a.localeCompare(b));
  480. for (let i = 0; i < names.length; i++) {
  481. const name = names[i];
  482. callback(this.#functions.get(name), i);
  483. }
  484. }
  485. // Find an event definition by any means necessary (unless it is ambiguous)
  486. #getEvent(key, values, forceUnique) {
  487. // EventTopic
  488. if ((0, ethers_3.isHexString)(key)) {
  489. const eventTopic = key.toLowerCase();
  490. for (const fragment of this.#events.values()) {
  491. if (eventTopic === fragment.topicHash) {
  492. return fragment;
  493. }
  494. }
  495. return null;
  496. }
  497. // It is a bare name, look up the function (will return null if ambiguous)
  498. if (key.indexOf('(') === -1) {
  499. const matching = [];
  500. for (const [name, fragment] of this.#events) {
  501. if (name.split('(' /* fix:) */)[0] === key) {
  502. matching.push(fragment);
  503. }
  504. }
  505. if (values) {
  506. // Remove all matches that don't have a compatible length.
  507. for (let i = matching.length - 1; i >= 0; i--) {
  508. if (matching[i].inputs.length < values.length) {
  509. matching.splice(i, 1);
  510. }
  511. }
  512. // Remove all matches that don't match the Typed signature
  513. for (let i = matching.length - 1; i >= 0; i--) {
  514. const inputs = matching[i].inputs;
  515. for (let j = 0; j < values.length; j++) {
  516. // Not a typed value
  517. if (!ethers_6.Typed.isTyped(values[j])) {
  518. continue;
  519. }
  520. // Make sure the value type matches the input type
  521. if (values[j].type !== inputs[j].baseType) {
  522. matching.splice(i, 1);
  523. break;
  524. }
  525. }
  526. }
  527. }
  528. if (matching.length === 0) {
  529. return null;
  530. }
  531. if (matching.length > 1 && forceUnique) {
  532. const matchStr = matching.map((m) => JSON.stringify(m.format())).join(', ');
  533. (0, ethers_3.assertArgument)(false, `ambiguous event description (i.e. matches ${matchStr})`, 'key', key);
  534. }
  535. return matching[0];
  536. }
  537. // Normalize the signature and lookup the function
  538. const result = this.#events.get(fragments_js_1.EventFragment.from(key).format());
  539. if (result) {
  540. return result;
  541. }
  542. return null;
  543. }
  544. /**
  545. * Get the event name for %%key%%, which may be a topic hash,
  546. * event name or event signature that belongs to the ABI.
  547. */
  548. getEventName(key) {
  549. const fragment = this.#getEvent(key, null, false);
  550. (0, ethers_3.assertArgument)(fragment, 'no matching event', 'key', key);
  551. return fragment.name;
  552. }
  553. /**
  554. * Returns true if %%key%% (an event topic hash, event name or
  555. * event signature) is present in the ABI.
  556. *
  557. * In the case of an event name, the name may be ambiguous, so
  558. * accessing the [[EventFragment]] may require refinement.
  559. */
  560. hasEvent(key) {
  561. return !!this.#getEvent(key, null, false);
  562. }
  563. /**
  564. * Get the [[EventFragment]] for %%key%%, which may be a topic hash,
  565. * event name or event signature that belongs to the ABI.
  566. *
  567. * If %%values%% is provided, it will use the Typed API to handle
  568. * ambiguous cases where multiple events match by name.
  569. *
  570. * If the %%key%% and %%values%% do not refine to a single event in
  571. * the ABI, this will throw.
  572. */
  573. getEvent(key, values) {
  574. return this.#getEvent(key, values || null, true);
  575. }
  576. /**
  577. * Iterate over all events, calling %%callback%%, sorted by their name.
  578. */
  579. forEachEvent(callback) {
  580. const names = Array.from(this.#events.keys());
  581. names.sort((a, b) => a.localeCompare(b));
  582. for (let i = 0; i < names.length; i++) {
  583. const name = names[i];
  584. callback(this.#events.get(name), i);
  585. }
  586. }
  587. /**
  588. * Get the [[ErrorFragment]] for %%key%%, which may be an error
  589. * selector, error name or error signature that belongs to the ABI.
  590. *
  591. * If %%values%% is provided, it will use the Typed API to handle
  592. * ambiguous cases where multiple errors match by name.
  593. *
  594. * If the %%key%% and %%values%% do not refine to a single error in
  595. * the ABI, this will throw.
  596. */
  597. getError(key, values) {
  598. if ((0, ethers_3.isHexString)(key)) {
  599. const selector = key.toLowerCase();
  600. if (BuiltinErrors[selector]) {
  601. return fragments_js_1.ErrorFragment.from(BuiltinErrors[selector].signature);
  602. }
  603. for (const fragment of this.#errors.values()) {
  604. if (selector === fragment.selector) {
  605. return fragment;
  606. }
  607. }
  608. return null;
  609. }
  610. // It is a bare name, look up the function (will return null if ambiguous)
  611. if (key.indexOf('(') === -1) {
  612. const matching = [];
  613. for (const [name, fragment] of this.#errors) {
  614. if (name.split('(' /* fix:) */)[0] === key) {
  615. matching.push(fragment);
  616. }
  617. }
  618. if (matching.length === 0) {
  619. if (key === 'Error') {
  620. return fragments_js_1.ErrorFragment.from('error Error(string)');
  621. }
  622. if (key === 'Panic') {
  623. return fragments_js_1.ErrorFragment.from('error Panic(uint256)');
  624. }
  625. return null;
  626. }
  627. else if (matching.length > 1) {
  628. const matchStr = matching.map((m) => JSON.stringify(m.format())).join(', ');
  629. (0, ethers_3.assertArgument)(false, `ambiguous error description (i.e. ${matchStr})`, 'name', key);
  630. }
  631. return matching[0];
  632. }
  633. // Normalize the signature and lookup the function
  634. key = fragments_js_1.ErrorFragment.from(key).format();
  635. if (key === 'Error(string)') {
  636. return fragments_js_1.ErrorFragment.from('error Error(string)');
  637. }
  638. if (key === 'Panic(uint256)') {
  639. return fragments_js_1.ErrorFragment.from('error Panic(uint256)');
  640. }
  641. const result = this.#errors.get(key);
  642. if (result) {
  643. return result;
  644. }
  645. return null;
  646. }
  647. /**
  648. * Iterate over all errors, calling %%callback%%, sorted by their name.
  649. */
  650. forEachError(callback) {
  651. const names = Array.from(this.#errors.keys());
  652. names.sort((a, b) => a.localeCompare(b));
  653. for (let i = 0; i < names.length; i++) {
  654. const name = names[i];
  655. callback(this.#errors.get(name), i);
  656. }
  657. }
  658. // Get the 4-byte selector used by Solidity to identify a function
  659. /*
  660. getSelector(fragment: ErrorFragment | FunctionFragment): string {
  661. if (typeof(fragment) === "string") {
  662. const matches: Array<Fragment> = [ ];
  663. try { matches.push(this.getFunction(fragment)); } catch (error) { }
  664. try { matches.push(this.getError(<string>fragment)); } catch (_) { }
  665. if (matches.length === 0) {
  666. logger.throwArgumentError("unknown fragment", "key", fragment);
  667. } else if (matches.length > 1) {
  668. logger.throwArgumentError("ambiguous fragment matches function and error", "key", fragment);
  669. }
  670. fragment = matches[0];
  671. }
  672. return dataSlice(id(fragment.format()), 0, 4);
  673. }
  674. */
  675. // Get the 32-byte topic hash used by Solidity to identify an event
  676. /*
  677. getEventTopic(fragment: EventFragment): string {
  678. //if (typeof(fragment) === "string") { fragment = this.getEvent(eventFragment); }
  679. return id(fragment.format());
  680. }
  681. */
  682. _decodeParams(params, data) {
  683. return this.#abiCoder.decode(params, data);
  684. }
  685. _encodeParams(params, values) {
  686. return this.#abiCoder.encode(params, values);
  687. }
  688. /**
  689. * Encodes a ``tx.data`` object for deploying the Contract with
  690. * the %%values%% as the constructor arguments.
  691. */
  692. encodeDeploy(values) {
  693. return this._encodeParams(this.deploy.inputs, values || []);
  694. }
  695. /**
  696. * Decodes the result %%data%% (e.g. from an ``eth_call``) for the
  697. * specified error (see [[getError]] for valid values for
  698. * %%key%%).
  699. *
  700. * Most developers should prefer the [[parseCallResult]] method instead,
  701. * which will automatically detect a ``CALL_EXCEPTION`` and throw the
  702. * corresponding error.
  703. */
  704. decodeErrorResult(fragment, data) {
  705. if (typeof fragment === 'string') {
  706. const f = this.getError(fragment);
  707. (0, ethers_3.assertArgument)(f, 'unknown error', 'fragment', fragment);
  708. fragment = f;
  709. }
  710. (0, ethers_3.assertArgument)((0, ethers_3.dataSlice)(data, 0, 4) === fragment.selector, `data signature does not match error ${fragment.name}.`, 'data', data);
  711. return this._decodeParams(fragment.inputs, (0, ethers_3.dataSlice)(data, 4));
  712. }
  713. /**
  714. * Encodes the transaction revert data for a call result that
  715. * reverted from the the Contract with the sepcified %%error%%
  716. * (see [[getError]] for valid values for %%fragment%%) with the %%values%%.
  717. *
  718. * This is generally not used by most developers, unless trying to mock
  719. * a result from a Contract.
  720. */
  721. encodeErrorResult(fragment, values) {
  722. if (typeof fragment === 'string') {
  723. const f = this.getError(fragment);
  724. (0, ethers_3.assertArgument)(f, 'unknown error', 'fragment', fragment);
  725. fragment = f;
  726. }
  727. return (0, ethers_3.concat)([fragment.selector, this._encodeParams(fragment.inputs, values || [])]);
  728. }
  729. /**
  730. * Decodes the %%data%% from a transaction ``tx.data`` for
  731. * the function specified (see [[getFunction]] for valid values
  732. * for %%fragment%%).
  733. *
  734. * Most developers should prefer the [[parseTransaction]] method
  735. * instead, which will automatically detect the fragment.
  736. */
  737. decodeFunctionData(fragment, data) {
  738. if (typeof fragment === 'string') {
  739. const f = this.getFunction(fragment);
  740. (0, ethers_3.assertArgument)(f, 'unknown function', 'fragment', fragment);
  741. fragment = f;
  742. }
  743. (0, ethers_3.assertArgument)((0, ethers_3.dataSlice)(data, 0, 4) === fragment.selector, `data signature does not match function ${fragment.name}.`, 'data', data);
  744. return this._decodeParams(fragment.inputs, (0, ethers_3.dataSlice)(data, 4));
  745. }
  746. /**
  747. * Encodes the ``tx.data`` for a transaction that calls the function
  748. * specified (see [[getFunction]] for valid values for %%fragment%%) with
  749. * the %%values%%.
  750. */
  751. encodeFunctionData(fragment, values) {
  752. if (typeof fragment === 'string') {
  753. const f = this.getFunction(fragment);
  754. (0, ethers_3.assertArgument)(f, 'unknown function', 'fragment', fragment);
  755. fragment = f;
  756. }
  757. return (0, ethers_3.concat)([fragment.selector, this._encodeParams(fragment.inputs, values || [])]);
  758. }
  759. /**
  760. * Decodes the result %%data%% (e.g. from an ``eth_call``) for the
  761. * specified function (see [[getFunction]] for valid values for
  762. * %%key%%).
  763. *
  764. * Most developers should prefer the [[parseCallResult]] method instead,
  765. * which will automatically detect a ``CALL_EXCEPTION`` and throw the
  766. * corresponding error.
  767. */
  768. decodeFunctionResult(fragment, data) {
  769. if (typeof fragment === 'string') {
  770. const f = this.getFunction(fragment);
  771. (0, ethers_3.assertArgument)(f, 'unknown function', 'fragment', fragment);
  772. fragment = f;
  773. }
  774. let message = 'invalid length for result data';
  775. const bytes = (0, ethers_3.getBytesCopy)(data);
  776. if (bytes.length % 32 === 0) {
  777. try {
  778. return this.#abiCoder.decode(fragment.outputs, bytes);
  779. }
  780. catch (error) {
  781. message = 'could not decode result data';
  782. }
  783. }
  784. // Call returned data with no error, but the data is junk
  785. (0, ethers_3.assert)(false, message, 'BAD_DATA', {
  786. value: (0, ethers_3.hexlify)(bytes),
  787. info: { method: fragment.name, signature: fragment.format() },
  788. });
  789. }
  790. makeError(_data, tx) {
  791. const data = (0, ethers_3.getBytes)(_data, 'data');
  792. const error = ethers_4.AbiCoder.getBuiltinCallException('call', tx, data);
  793. // Not a built-in error; try finding a custom error
  794. const customPrefix = 'execution reverted (unknown custom error)';
  795. if (error.message.startsWith(customPrefix)) {
  796. const selector = (0, ethers_3.hexlify)(data.slice(0, 4));
  797. const ef = this.getError(selector);
  798. if (ef) {
  799. try {
  800. const args = this.#abiCoder.decode(ef.inputs, data.slice(4));
  801. error.revert = {
  802. name: ef.name,
  803. signature: ef.format(),
  804. args,
  805. };
  806. error.reason = error.revert.signature;
  807. error.message = `execution reverted: ${error.reason}`;
  808. }
  809. catch (e) {
  810. error.message = `execution reverted (coult not decode custom error)`;
  811. }
  812. }
  813. }
  814. // Add the invocation, if available
  815. const parsed = this.parseTransaction(tx);
  816. if (parsed) {
  817. error.invocation = {
  818. method: parsed.name,
  819. signature: parsed.signature,
  820. args: parsed.args,
  821. };
  822. }
  823. return error;
  824. }
  825. /**
  826. * Encodes the result data (e.g. from an ``eth_call``) for the
  827. * specified function (see [[getFunction]] for valid values
  828. * for %%fragment%%) with %%values%%.
  829. *
  830. * This is generally not used by most developers, unless trying to mock
  831. * a result from a Contract.
  832. */
  833. encodeFunctionResult(fragment, values) {
  834. if (typeof fragment === 'string') {
  835. const f = this.getFunction(fragment);
  836. (0, ethers_3.assertArgument)(f, 'unknown function', 'fragment', fragment);
  837. fragment = f;
  838. }
  839. return (0, ethers_3.hexlify)(this.#abiCoder.encode(fragment.outputs, values || []));
  840. }
  841. /*
  842. spelunk(inputs: Array<ParamType>, values: ReadonlyArray<any>, processfunc: (type: string, value: any) => Promise<any>): Promise<Array<any>> {
  843. const promises: Array<Promise<>> = [ ];
  844. const process = function(type: ParamType, value: any): any {
  845. if (type.baseType === "array") {
  846. return descend(type.child
  847. }
  848. if (type. === "address") {
  849. }
  850. };
  851. const descend = function (inputs: Array<ParamType>, values: ReadonlyArray<any>) {
  852. if (inputs.length !== values.length) { throw new Error("length mismatch"); }
  853. };
  854. const result: Array<any> = [ ];
  855. values.forEach((value, index) => {
  856. if (value == null) {
  857. topics.push(null);
  858. } else if (param.baseType === "array" || param.baseType === "tuple") {
  859. logger.throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
  860. } else if (Array.isArray(value)) {
  861. topics.push(value.map((value) => encodeTopic(param, value)));
  862. } else {
  863. topics.push(encodeTopic(param, value));
  864. }
  865. });
  866. }
  867. */
  868. // Create the filter for the event with search criteria (e.g. for eth_filterLog)
  869. encodeFilterTopics(fragment, values) {
  870. if (typeof fragment === 'string') {
  871. const f = this.getEvent(fragment);
  872. (0, ethers_3.assertArgument)(f, 'unknown event', 'eventFragment', fragment);
  873. fragment = f;
  874. }
  875. (0, ethers_3.assert)(values.length <= fragment.inputs.length, `too many arguments for ${fragment.format()}`, 'UNEXPECTED_ARGUMENT', {
  876. count: values.length,
  877. expectedCount: fragment.inputs.length,
  878. });
  879. const topics = [];
  880. if (!fragment.anonymous) {
  881. topics.push(fragment.topicHash);
  882. }
  883. // @TODO: Use the coders for this; to properly support tuples, etc.
  884. const encodeTopic = (param, value) => {
  885. if (param.type === 'string') {
  886. return (0, ethers_2.id)(value);
  887. }
  888. else if (param.type === 'bytes') {
  889. return (0, ethers_1.keccak256)((0, ethers_3.hexlify)(value));
  890. }
  891. if (param.type === 'bool' && typeof value === 'boolean') {
  892. value = value ? '0x01' : '0x00';
  893. }
  894. if (param.type.match(/^u?int/)) {
  895. value = (0, ethers_3.toBeHex)(value);
  896. }
  897. // Check addresses are valid
  898. if (param.type === 'address') {
  899. this.#abiCoder.encode(['address'], [value]);
  900. }
  901. return (0, ethers_3.zeroPadValue)((0, ethers_3.hexlify)(value), 32);
  902. //@TOOD should probably be return toHex(value, 32)
  903. };
  904. values.forEach((value, index) => {
  905. const param = fragment.inputs[index];
  906. if (!param.indexed) {
  907. (0, ethers_3.assertArgument)(value == null, 'cannot filter non-indexed parameters; must be null', 'contract.' + param.name, value);
  908. return;
  909. }
  910. if (value == null) {
  911. topics.push(null);
  912. }
  913. else if (param.baseType === 'array' || param.baseType === 'tuple') {
  914. (0, ethers_3.assertArgument)(false, 'filtering with tuples or arrays not supported', 'contract.' + param.name, value);
  915. }
  916. else if (Array.isArray(value)) {
  917. topics.push(value.map((value) => encodeTopic(param, value)));
  918. }
  919. else {
  920. topics.push(encodeTopic(param, value));
  921. }
  922. });
  923. // Trim off trailing nulls
  924. while (topics.length && topics[topics.length - 1] === null) {
  925. topics.pop();
  926. }
  927. return topics;
  928. }
  929. encodeEventLog(fragment, values) {
  930. if (typeof fragment === 'string') {
  931. const f = this.getEvent(fragment);
  932. (0, ethers_3.assertArgument)(f, 'unknown event', 'eventFragment', fragment);
  933. fragment = f;
  934. }
  935. const topics = [];
  936. const dataTypes = [];
  937. const dataValues = [];
  938. if (!fragment.anonymous) {
  939. topics.push(fragment.topicHash);
  940. }
  941. (0, ethers_3.assertArgument)(values.length === fragment.inputs.length, 'event arguments/values mismatch', 'values', values);
  942. fragment.inputs.forEach((param, index) => {
  943. const value = values[index];
  944. if (param.indexed) {
  945. if (param.type === 'string') {
  946. topics.push((0, ethers_2.id)(value));
  947. }
  948. else if (param.type === 'bytes') {
  949. topics.push((0, ethers_1.keccak256)(value));
  950. }
  951. else if (param.baseType === 'tuple' || param.baseType === 'array') {
  952. // @TODO
  953. throw new Error('not implemented');
  954. }
  955. else {
  956. topics.push(this.#abiCoder.encode([param.type], [value]));
  957. }
  958. }
  959. else {
  960. dataTypes.push(param);
  961. dataValues.push(value);
  962. }
  963. });
  964. return {
  965. data: this.#abiCoder.encode(dataTypes, dataValues),
  966. topics: topics,
  967. };
  968. }
  969. // Decode a filter for the event and the search criteria
  970. decodeEventLog(fragment, data, topics) {
  971. if (typeof fragment === 'string') {
  972. const f = this.getEvent(fragment);
  973. (0, ethers_3.assertArgument)(f, 'unknown event', 'eventFragment', fragment);
  974. fragment = f;
  975. }
  976. if (topics != null && !fragment.anonymous) {
  977. const eventTopic = fragment.topicHash;
  978. (0, ethers_3.assertArgument)((0, ethers_3.isHexString)(topics[0], 32) && topics[0].toLowerCase() === eventTopic, 'fragment/topic mismatch', 'topics[0]', topics[0]);
  979. topics = topics.slice(1);
  980. }
  981. const indexed = [];
  982. const nonIndexed = [];
  983. const dynamic = [];
  984. fragment.inputs.forEach((param, index) => {
  985. if (param.indexed) {
  986. if (param.type === 'string' ||
  987. param.type === 'bytes' ||
  988. param.baseType === 'tuple' ||
  989. param.baseType === 'array') {
  990. indexed.push(fragments_js_1.ParamType.from({ type: 'bytes32', name: param.name }));
  991. dynamic.push(true);
  992. }
  993. else {
  994. indexed.push(param);
  995. dynamic.push(false);
  996. }
  997. }
  998. else {
  999. nonIndexed.push(param);
  1000. dynamic.push(false);
  1001. }
  1002. });
  1003. const resultIndexed = topics != null ? this.#abiCoder.decode(indexed, (0, ethers_3.concat)(topics)) : null;
  1004. const resultNonIndexed = this.#abiCoder.decode(nonIndexed, data, true);
  1005. //const result: (Array<any> & { [ key: string ]: any }) = [ ];
  1006. const values = [];
  1007. const keys = [];
  1008. let nonIndexedIndex = 0, indexedIndex = 0;
  1009. fragment.inputs.forEach((param, index) => {
  1010. let value = null;
  1011. if (param.indexed) {
  1012. if (resultIndexed == null) {
  1013. value = new Indexed(null);
  1014. }
  1015. else if (dynamic[index]) {
  1016. value = new Indexed(resultIndexed[indexedIndex++]);
  1017. }
  1018. else {
  1019. try {
  1020. value = resultIndexed[indexedIndex++];
  1021. }
  1022. catch (error) {
  1023. value = error;
  1024. }
  1025. }
  1026. }
  1027. else {
  1028. try {
  1029. value = resultNonIndexed[nonIndexedIndex++];
  1030. }
  1031. catch (error) {
  1032. value = error;
  1033. }
  1034. }
  1035. values.push(value);
  1036. keys.push(param.name || null);
  1037. });
  1038. return ethers_5.Result.fromItems(values, keys);
  1039. }
  1040. /**
  1041. * Parses a transaction, finding the matching function and extracts
  1042. * the parameter values along with other useful function details.
  1043. *
  1044. * If the matching function cannot be found, return null.
  1045. */
  1046. parseTransaction(tx) {
  1047. const data = (0, ethers_3.getBytes)(tx.data, 'tx.data');
  1048. const value = (0, ethers_3.getBigInt)(tx.value != null ? tx.value : 0, 'tx.value');
  1049. const fragment = this.getFunction((0, ethers_3.hexlify)(data.slice(0, 4)));
  1050. if (!fragment) {
  1051. return null;
  1052. }
  1053. const args = this.#abiCoder.decode(fragment.inputs, data.slice(4));
  1054. return new TransactionDescription(fragment, fragment.selector, args, value);
  1055. }
  1056. parseCallResult(data) {
  1057. throw new Error('@TODO');
  1058. }
  1059. /**
  1060. * Parses a receipt log, finding the matching event and extracts
  1061. * the parameter values along with other useful event details.
  1062. *
  1063. * If the matching event cannot be found, returns null.
  1064. */
  1065. parseLog(log) {
  1066. const fragment = this.getEvent(log.topics[0]);
  1067. if (!fragment || fragment.anonymous) {
  1068. return null;
  1069. }
  1070. // @TODO: If anonymous, and the only method, and the input count matches, should we parse?
  1071. // Probably not, because just because it is the only event in the ABI does
  1072. // not mean we have the full ABI; maybe just a fragment?
  1073. return new LogDescription(fragment, fragment.topicHash, this.decodeEventLog(fragment, log.data, log.topics));
  1074. }
  1075. /**
  1076. * Parses a revert data, finding the matching error and extracts
  1077. * the parameter values along with other useful error details.
  1078. *
  1079. * If the matching event cannot be found, returns null.
  1080. */
  1081. parseError(data) {
  1082. const hexData = (0, ethers_3.hexlify)(data);
  1083. const fragment = this.getError((0, ethers_3.dataSlice)(hexData, 0, 4));
  1084. if (!fragment) {
  1085. return null;
  1086. }
  1087. const args = this.#abiCoder.decode(fragment.inputs, (0, ethers_3.dataSlice)(hexData, 4));
  1088. return new ErrorDescription(fragment, fragment.selector, args);
  1089. }
  1090. /**
  1091. * Creates a new [[Interface]] from the ABI %%value%%.
  1092. *
  1093. * The %%value%% may be provided as an existing [[Interface]] object,
  1094. * a JSON-encoded ABI or any Human-Readable ABI format.
  1095. */
  1096. static from(value) {
  1097. // Already an Interface, which is immutable
  1098. if (value instanceof Interface) {
  1099. return value;
  1100. }
  1101. // JSON
  1102. if (typeof value === 'string') {
  1103. return new Interface(JSON.parse(value));
  1104. }
  1105. // Maybe an interface from an older version, or from a symlinked copy
  1106. if (typeof value.format === 'function') {
  1107. return new Interface(value.format('json'));
  1108. }
  1109. // Array of fragments
  1110. return new Interface(value);
  1111. }
  1112. }
  1113. exports.Interface = Interface;
  1114. //# sourceMappingURL=interface.js.map