interface.js 42 KB

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