fragments.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. "use strict";
  2. /**
  3. * A fragment is a single item from an ABI, which may represent any of:
  4. *
  5. * - [Functions](FunctionFragment)
  6. * - [Events](EventFragment)
  7. * - [Constructors](ConstructorFragment)
  8. * - Custom [Errors](ErrorFragment)
  9. * - [Fallback or Receive](FallbackFragment) functions
  10. *
  11. * @_subsection api/abi/abi-coder:Fragments [about-fragments]
  12. */
  13. var _a;
  14. Object.defineProperty(exports, "__esModule", { value: true });
  15. exports.StructFragment = exports.FunctionFragment = exports.FallbackFragment = exports.ConstructorFragment = exports.EventFragment = exports.ErrorFragment = exports.NamedFragment = exports.Fragment = exports.ParamType = void 0;
  16. const ethers_1 = require("ethers");
  17. const ethers_2 = require("ethers");
  18. // [ "a", "b" ] => { "a": 1, "b": 1 }
  19. function setify(items) {
  20. const result = new Set();
  21. items.forEach((k) => result.add(k));
  22. return Object.freeze(result);
  23. }
  24. // Visibility Keywords
  25. const _kwVisib = 'constant external internal payable private public pure view';
  26. const KwVisib = setify(_kwVisib.split(' '));
  27. const _kwTypes = 'constructor error event fallback function receive struct';
  28. const KwTypes = setify(_kwTypes.split(' '));
  29. const _kwModifiers = 'calldata memory storage payable indexed';
  30. const KwModifiers = setify(_kwModifiers.split(' '));
  31. const _kwOther = 'tuple returns';
  32. // All Keywords
  33. const _keywords = [_kwTypes, _kwModifiers, _kwOther, _kwVisib].join(' ');
  34. const Keywords = setify(_keywords.split(' '));
  35. // Single character tokens
  36. const SimpleTokens = {
  37. '(': 'OPEN_PAREN',
  38. ')': 'CLOSE_PAREN',
  39. '[': 'OPEN_BRACKET',
  40. ']': 'CLOSE_BRACKET',
  41. ',': 'COMMA',
  42. '@': 'AT',
  43. };
  44. // Parser regexes to consume the next token
  45. const regexWhitespacePrefix = new RegExp('^(\\s*)');
  46. const regexNumberPrefix = new RegExp('^([0-9]+)');
  47. const regexIdPrefix = new RegExp('^([a-zA-Z$_][a-zA-Z0-9$_]*)');
  48. // Parser regexs to check validity
  49. const regexId = new RegExp('^([a-zA-Z$_][a-zA-Z0-9$_]*)$');
  50. const regexType = new RegExp('^(trcToken|address|bool|bytes([0-9]*)|string|u?int([0-9]*))$');
  51. class TokenString {
  52. #offset;
  53. #tokens;
  54. get offset() {
  55. return this.#offset;
  56. }
  57. get length() {
  58. return this.#tokens.length - this.#offset;
  59. }
  60. constructor(tokens) {
  61. this.#offset = 0;
  62. this.#tokens = tokens.slice();
  63. }
  64. clone() {
  65. return new _a(this.#tokens);
  66. }
  67. reset() {
  68. this.#offset = 0;
  69. }
  70. #subTokenString(from = 0, to = 0) {
  71. return new _a(this.#tokens.slice(from, to).map((t) => {
  72. return Object.freeze(Object.assign({}, t, {
  73. match: t.match - from,
  74. linkBack: t.linkBack - from,
  75. linkNext: t.linkNext - from,
  76. }));
  77. }));
  78. }
  79. // Pops and returns the value of the next token, if it is a keyword in allowed; throws if out of tokens
  80. popKeyword(allowed) {
  81. const top = this.peek();
  82. if (top.type !== 'KEYWORD' || !allowed.has(top.text)) {
  83. throw new Error(`expected keyword ${top.text}`);
  84. }
  85. return this.pop().text;
  86. }
  87. // Pops and returns the value of the next token if it is `type`; throws if out of tokens
  88. popType(type) {
  89. if (this.peek().type !== type) {
  90. throw new Error(`expected ${type}; got ${JSON.stringify(this.peek())}`);
  91. }
  92. return this.pop().text;
  93. }
  94. // Pops and returns a "(" TOKENS ")"
  95. popParen() {
  96. const top = this.peek();
  97. if (top.type !== 'OPEN_PAREN') {
  98. throw new Error('bad start');
  99. }
  100. const result = this.#subTokenString(this.#offset + 1, top.match + 1);
  101. this.#offset = top.match + 1;
  102. return result;
  103. }
  104. // Pops and returns the items within "(" ITEM1 "," ITEM2 "," ... ")"
  105. popParams() {
  106. const top = this.peek();
  107. if (top.type !== 'OPEN_PAREN') {
  108. throw new Error('bad start');
  109. }
  110. const result = [];
  111. while (this.#offset < top.match - 1) {
  112. const link = this.peek().linkNext;
  113. result.push(this.#subTokenString(this.#offset + 1, link));
  114. this.#offset = link;
  115. }
  116. this.#offset = top.match + 1;
  117. return result;
  118. }
  119. // Returns the top Token, throwing if out of tokens
  120. peek() {
  121. if (this.#offset >= this.#tokens.length) {
  122. throw new Error('out-of-bounds');
  123. }
  124. return this.#tokens[this.#offset];
  125. }
  126. // Returns the next value, if it is a keyword in `allowed`
  127. peekKeyword(allowed) {
  128. const top = this.peekType('KEYWORD');
  129. return top != null && allowed.has(top) ? top : null;
  130. }
  131. // Returns the value of the next token if it is `type`
  132. peekType(type) {
  133. if (this.length === 0) {
  134. return null;
  135. }
  136. const top = this.peek();
  137. return top.type === type ? top.text : null;
  138. }
  139. // Returns the next token; throws if out of tokens
  140. pop() {
  141. const result = this.peek();
  142. this.#offset++;
  143. return result;
  144. }
  145. toString() {
  146. const tokens = [];
  147. for (let i = this.#offset; i < this.#tokens.length; i++) {
  148. const token = this.#tokens[i];
  149. tokens.push(`${token.type}:${token.text}`);
  150. }
  151. return `<TokenString ${tokens.join(' ')}>`;
  152. }
  153. }
  154. _a = TokenString;
  155. function lex(text) {
  156. const tokens = [];
  157. const throwError = (message) => {
  158. const token = offset < text.length ? JSON.stringify(text[offset]) : '$EOI';
  159. throw new Error(`invalid token ${token} at ${offset}: ${message}`);
  160. };
  161. const brackets = [];
  162. const commas = [];
  163. let offset = 0;
  164. while (offset < text.length) {
  165. // Strip off any leading whitespace
  166. let cur = text.substring(offset);
  167. let match = cur.match(regexWhitespacePrefix);
  168. if (match) {
  169. offset += match[1].length;
  170. cur = text.substring(offset);
  171. }
  172. const token = {
  173. depth: brackets.length,
  174. linkBack: -1,
  175. linkNext: -1,
  176. match: -1,
  177. type: '',
  178. text: '',
  179. offset,
  180. value: -1,
  181. };
  182. tokens.push(token);
  183. const type = SimpleTokens[cur[0]] || '';
  184. if (type) {
  185. token.type = type;
  186. token.text = cur[0];
  187. offset++;
  188. if (type === 'OPEN_PAREN') {
  189. brackets.push(tokens.length - 1);
  190. commas.push(tokens.length - 1);
  191. }
  192. else if (type == 'CLOSE_PAREN') {
  193. if (brackets.length === 0) {
  194. throwError('no matching open bracket');
  195. }
  196. token.match = brackets.pop();
  197. tokens[token.match].match = tokens.length - 1;
  198. token.depth--;
  199. token.linkBack = commas.pop();
  200. tokens[token.linkBack].linkNext = tokens.length - 1;
  201. }
  202. else if (type === 'COMMA') {
  203. token.linkBack = commas.pop();
  204. tokens[token.linkBack].linkNext = tokens.length - 1;
  205. commas.push(tokens.length - 1);
  206. }
  207. else if (type === 'OPEN_BRACKET') {
  208. token.type = 'BRACKET';
  209. }
  210. else if (type === 'CLOSE_BRACKET') {
  211. // Remove the CLOSE_BRACKET
  212. let suffix = tokens.pop().text;
  213. if (tokens.length > 0 && tokens[tokens.length - 1].type === 'NUMBER') {
  214. const value = tokens.pop().text;
  215. suffix = value + suffix;
  216. tokens[tokens.length - 1].value = (0, ethers_1.getNumber)(value);
  217. }
  218. if (tokens.length === 0 || tokens[tokens.length - 1].type !== 'BRACKET') {
  219. throw new Error('missing opening bracket');
  220. }
  221. tokens[tokens.length - 1].text += suffix;
  222. }
  223. continue;
  224. }
  225. match = cur.match(regexIdPrefix);
  226. if (match) {
  227. token.text = match[1];
  228. offset += token.text.length;
  229. if (Keywords.has(token.text)) {
  230. token.type = 'KEYWORD';
  231. continue;
  232. }
  233. if (token.text.match(regexType)) {
  234. token.type = 'TYPE';
  235. continue;
  236. }
  237. token.type = 'ID';
  238. continue;
  239. }
  240. match = cur.match(regexNumberPrefix);
  241. if (match) {
  242. token.text = match[1];
  243. token.type = 'NUMBER';
  244. offset += token.text.length;
  245. continue;
  246. }
  247. throw new Error(`unexpected token ${JSON.stringify(cur[0])} at position ${offset}`);
  248. }
  249. return new TokenString(tokens.map((t) => Object.freeze(t)));
  250. }
  251. // Check only one of `allowed` is in `set`
  252. function allowSingle(set, allowed) {
  253. const included = [];
  254. for (const key in allowed.keys()) {
  255. if (set.has(key)) {
  256. included.push(key);
  257. }
  258. }
  259. if (included.length > 1) {
  260. throw new Error(`conflicting types: ${included.join(', ')}`);
  261. }
  262. }
  263. // Functions to process a Solidity Signature TokenString from left-to-right for...
  264. // ...the name with an optional type, returning the name
  265. function consumeName(type, tokens) {
  266. if (tokens.peekKeyword(KwTypes)) {
  267. const keyword = tokens.pop().text;
  268. if (keyword !== type) {
  269. throw new Error(`expected ${type}, got ${keyword}`);
  270. }
  271. }
  272. return tokens.popType('ID');
  273. }
  274. // ...all keywords matching allowed, returning the keywords
  275. function consumeKeywords(tokens, allowed) {
  276. const keywords = new Set();
  277. // eslint-disable-next-line no-constant-condition
  278. while (true) {
  279. const keyword = tokens.peekType('KEYWORD');
  280. if (keyword == null || (allowed && !allowed.has(keyword))) {
  281. break;
  282. }
  283. tokens.pop();
  284. if (keywords.has(keyword)) {
  285. throw new Error(`duplicate keywords: ${JSON.stringify(keyword)}`);
  286. }
  287. keywords.add(keyword);
  288. }
  289. return Object.freeze(keywords);
  290. }
  291. // ...all visibility keywords, returning the coalesced mutability
  292. function consumeMutability(tokens) {
  293. const modifiers = consumeKeywords(tokens, KwVisib);
  294. // Detect conflicting modifiers
  295. allowSingle(modifiers, setify('constant payable nonpayable'.split(' ')));
  296. allowSingle(modifiers, setify('pure view payable nonpayable'.split(' ')));
  297. // Process mutability states
  298. if (modifiers.has('view')) {
  299. return 'view';
  300. }
  301. if (modifiers.has('pure')) {
  302. return 'pure';
  303. }
  304. if (modifiers.has('payable')) {
  305. return 'payable';
  306. }
  307. if (modifiers.has('nonpayable')) {
  308. return 'nonpayable';
  309. }
  310. // Process legacy `constant` last
  311. if (modifiers.has('constant')) {
  312. return 'view';
  313. }
  314. return 'nonpayable';
  315. }
  316. // ...a parameter list, returning the ParamType list
  317. function consumeParams(tokens, allowIndexed) {
  318. return tokens.popParams().map((t) => ParamType.from(t, allowIndexed));
  319. }
  320. // ...a gas limit, returning a BigNumber or null if none
  321. function consumeGas(tokens) {
  322. if (tokens.peekType('AT')) {
  323. tokens.pop();
  324. if (tokens.peekType('NUMBER')) {
  325. return (0, ethers_1.getBigInt)(tokens.pop().text);
  326. }
  327. throw new Error('invalid gas');
  328. }
  329. return null;
  330. }
  331. function consumeEoi(tokens) {
  332. if (tokens.length) {
  333. throw new Error(`unexpected tokens: ${tokens.toString()}`);
  334. }
  335. }
  336. const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/);
  337. function verifyBasicType(type) {
  338. const match = type.match(regexType);
  339. (0, ethers_1.assertArgument)(match, 'invalid type', 'type', type);
  340. if (type === 'uint') {
  341. return 'uint256';
  342. }
  343. if (type === 'int') {
  344. return 'int256';
  345. }
  346. if (match[2]) {
  347. // bytesXX
  348. const length = parseInt(match[2]);
  349. (0, ethers_1.assertArgument)(length !== 0 && length <= 32, 'invalid bytes length', 'type', type);
  350. }
  351. else if (match[3]) {
  352. // intXX or uintXX
  353. const size = parseInt(match[3]);
  354. (0, ethers_1.assertArgument)(size !== 0 && size <= 256 && size % 8 === 0, 'invalid numeric width', 'type', type);
  355. }
  356. return type;
  357. }
  358. // Make the Fragment constructors effectively private
  359. const _guard = {};
  360. const internal = Symbol.for('_ethers_internal');
  361. const ParamTypeInternal = '_ParamTypeInternal';
  362. const ErrorFragmentInternal = '_ErrorInternal';
  363. const EventFragmentInternal = '_EventInternal';
  364. const ConstructorFragmentInternal = '_ConstructorInternal';
  365. const FallbackFragmentInternal = '_FallbackInternal';
  366. const FunctionFragmentInternal = '_FunctionInternal';
  367. const StructFragmentInternal = '_StructInternal';
  368. /**
  369. * Each input and output of a [[Fragment]] is an Array of **ParamType**.
  370. */
  371. class ParamType {
  372. /**
  373. * The local name of the parameter (or ``""`` if unbound)
  374. */
  375. name;
  376. /**
  377. * The fully qualified type (e.g. ``"address"``, ``"tuple(address)"``,
  378. * ``"uint256[3][]"``)
  379. */
  380. type;
  381. /**
  382. * The base type (e.g. ``"address"``, ``"tuple"``, ``"array"``)
  383. */
  384. baseType;
  385. /**
  386. * True if the parameters is indexed.
  387. *
  388. * For non-indexable types this is ``null``.
  389. */
  390. indexed;
  391. /**
  392. * The components for the tuple.
  393. *
  394. * For non-tuple types this is ``null``.
  395. */
  396. components;
  397. /**
  398. * The array length, or ``-1`` for dynamic-lengthed arrays.
  399. *
  400. * For non-array types this is ``null``.
  401. */
  402. arrayLength;
  403. /**
  404. * The type of each child in the array.
  405. *
  406. * For non-array types this is ``null``.
  407. */
  408. arrayChildren;
  409. /**
  410. * @private
  411. */
  412. constructor(guard, name, type, baseType, indexed, components, arrayLength, arrayChildren) {
  413. (0, ethers_1.assertPrivate)(guard, _guard, 'ParamType');
  414. Object.defineProperty(this, internal, { value: ParamTypeInternal });
  415. if (components) {
  416. components = Object.freeze(components.slice());
  417. }
  418. if (baseType === 'array') {
  419. if (arrayLength == null || arrayChildren == null) {
  420. throw new Error('');
  421. }
  422. }
  423. else if (arrayLength != null || arrayChildren != null) {
  424. throw new Error('');
  425. }
  426. if (baseType === 'tuple') {
  427. if (components == null) {
  428. throw new Error('');
  429. }
  430. }
  431. else if (components != null) {
  432. throw new Error('');
  433. }
  434. (0, ethers_1.defineProperties)(this, {
  435. name,
  436. type,
  437. baseType,
  438. indexed,
  439. components,
  440. arrayLength,
  441. arrayChildren,
  442. });
  443. }
  444. /**
  445. * Return a string representation of this type.
  446. *
  447. * For example,
  448. *
  449. * ``sighash" => "(uint256,address)"``
  450. *
  451. * ``"minimal" => "tuple(uint256,address) indexed"``
  452. *
  453. * ``"full" => "tuple(uint256 foo, address bar) indexed baz"``
  454. */
  455. format(format) {
  456. if (format == null) {
  457. format = 'sighash';
  458. }
  459. if (format === 'json') {
  460. const result = {
  461. type: this.baseType === 'tuple' ? 'tuple' : this.type,
  462. name: this.name || undefined,
  463. };
  464. if (typeof this.indexed === 'boolean') {
  465. result.indexed = this.indexed;
  466. }
  467. if (this.isTuple()) {
  468. result.components = this.components.map((c) => JSON.parse(c.format(format)));
  469. }
  470. return JSON.stringify(result);
  471. }
  472. let result = '';
  473. // Array
  474. if (this.isArray()) {
  475. result += this.arrayChildren.format(format);
  476. result += `[${this.arrayLength < 0 ? '' : String(this.arrayLength)}]`;
  477. }
  478. else {
  479. if (this.isTuple()) {
  480. if (format !== 'sighash') {
  481. result += this.type;
  482. }
  483. result += '(' + this.components.map((comp) => comp.format(format)).join(format === 'full' ? ', ' : ',') + ')';
  484. }
  485. else {
  486. result += this.type;
  487. }
  488. }
  489. if (format !== 'sighash') {
  490. if (this.indexed === true) {
  491. result += ' indexed';
  492. }
  493. if (format === 'full' && this.name) {
  494. result += ' ' + this.name;
  495. }
  496. }
  497. return result;
  498. }
  499. /**
  500. * Returns true if %%this%% is an Array type.
  501. *
  502. * This provides a type gaurd ensuring that [[arrayChildren]]
  503. * and [[arrayLength]] are non-null.
  504. */
  505. isArray() {
  506. return this.baseType === 'array';
  507. }
  508. /**
  509. * Returns true if %%this%% is a Tuple type.
  510. *
  511. * This provides a type gaurd ensuring that [[components]]
  512. * is non-null.
  513. */
  514. isTuple() {
  515. return this.baseType === 'tuple';
  516. }
  517. /**
  518. * Returns true if %%this%% is an Indexable type.
  519. *
  520. * This provides a type gaurd ensuring that [[indexed]]
  521. * is non-null.
  522. */
  523. isIndexable() {
  524. return this.indexed != null;
  525. }
  526. /**
  527. * Walks the **ParamType** with %%value%%, calling %%process%%
  528. * on each type, destructing the %%value%% recursively.
  529. */
  530. walk(value, process) {
  531. if (this.isArray()) {
  532. if (!Array.isArray(value)) {
  533. throw new Error('invalid array value');
  534. }
  535. if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
  536. throw new Error('array is wrong length');
  537. }
  538. return value.map((v) => this.arrayChildren?.walk(v, process));
  539. }
  540. if (this.isTuple()) {
  541. if (!Array.isArray(value)) {
  542. throw new Error('invalid tuple value');
  543. }
  544. if (value.length !== this.components.length) {
  545. throw new Error('array is wrong length');
  546. }
  547. return value.map((v, i) => this.components?.[i].walk(v, process));
  548. }
  549. return process(this.type, value);
  550. }
  551. #walkAsync(promises, value, process, setValue) {
  552. if (this.isArray()) {
  553. if (!Array.isArray(value)) {
  554. throw new Error('invalid array value');
  555. }
  556. if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
  557. throw new Error('array is wrong length');
  558. }
  559. const childType = this.arrayChildren;
  560. const result = value.slice();
  561. result.forEach((value, index) => {
  562. childType.#walkAsync(promises, value, process, (value) => {
  563. result[index] = value;
  564. });
  565. });
  566. setValue(result);
  567. return;
  568. }
  569. if (this.isTuple()) {
  570. const components = this.components;
  571. // Convert the object into an array
  572. let result;
  573. if (Array.isArray(value)) {
  574. result = value.slice();
  575. }
  576. else {
  577. if (value == null || typeof value !== 'object') {
  578. throw new Error('invalid tuple value');
  579. }
  580. result = components.map((param) => {
  581. if (!param.name) {
  582. throw new Error('cannot use object value with unnamed components');
  583. }
  584. if (!(param.name in value)) {
  585. throw new Error(`missing value for component ${param.name}`);
  586. }
  587. return value[param.name];
  588. });
  589. }
  590. if (result.length !== this.components.length) {
  591. throw new Error('array is wrong length');
  592. }
  593. result.forEach((value, index) => {
  594. components[index].#walkAsync(promises, value, process, (value) => {
  595. result[index] = value;
  596. });
  597. });
  598. setValue(result);
  599. return;
  600. }
  601. const result = process(this.type, value);
  602. if (result.then) {
  603. promises.push((async function () {
  604. setValue(await result);
  605. })());
  606. }
  607. else {
  608. setValue(result);
  609. }
  610. }
  611. /**
  612. * Walks the **ParamType** with %%value%%, asynchronously calling
  613. * %%process%% on each type, destructing the %%value%% recursively.
  614. *
  615. * This can be used to resolve ENS naes by walking and resolving each
  616. * ``"address"`` type.
  617. */
  618. async walkAsync(value, process) {
  619. const promises = [];
  620. const result = [value];
  621. this.#walkAsync(promises, value, process, (value) => {
  622. result[0] = value;
  623. });
  624. if (promises.length) {
  625. await Promise.all(promises);
  626. }
  627. return result[0];
  628. }
  629. /**
  630. * Creates a new **ParamType** for %%obj%%.
  631. *
  632. * If %%allowIndexed%% then the ``indexed`` keyword is permitted,
  633. * otherwise the ``indexed`` keyword will throw an error.
  634. */
  635. static from(obj, allowIndexed) {
  636. if (ParamType.isParamType(obj)) {
  637. return obj;
  638. }
  639. if (typeof obj === 'string') {
  640. return ParamType.from(lex(obj), allowIndexed);
  641. }
  642. else if (obj instanceof TokenString) {
  643. let type = '', baseType = '';
  644. let comps = null;
  645. if (consumeKeywords(obj, setify(['tuple'])).has('tuple') || obj.peekType('OPEN_PAREN')) {
  646. // Tuple
  647. baseType = 'tuple';
  648. comps = obj.popParams().map((t) => ParamType.from(t));
  649. type = `tuple(${comps.map((c) => c.format()).join(',')})`;
  650. }
  651. else {
  652. // Normal
  653. type = verifyBasicType(obj.popType('TYPE'));
  654. baseType = type;
  655. }
  656. // Check for Array
  657. let arrayChildren = null;
  658. let arrayLength = null;
  659. while (obj.length && obj.peekType('BRACKET')) {
  660. const bracket = obj.pop(); //arrays[i];
  661. arrayChildren = new ParamType(_guard, '', type, baseType, null, comps, arrayLength, arrayChildren);
  662. arrayLength = bracket.value;
  663. type += bracket.text;
  664. baseType = 'array';
  665. comps = null;
  666. }
  667. let indexed = null;
  668. const keywords = consumeKeywords(obj, KwModifiers);
  669. if (keywords.has('indexed')) {
  670. if (!allowIndexed) {
  671. throw new Error('');
  672. }
  673. indexed = true;
  674. }
  675. const name = obj.peekType('ID') ? obj.pop().text : '';
  676. if (obj.length) {
  677. throw new Error('leftover tokens');
  678. }
  679. return new ParamType(_guard, name, type, baseType, indexed, comps, arrayLength, arrayChildren);
  680. }
  681. const name = obj.name;
  682. (0, ethers_1.assertArgument)(!name || (typeof name === 'string' && name.match(regexId)), 'invalid name', 'obj.name', name);
  683. let indexed = obj.indexed;
  684. if (indexed != null) {
  685. (0, ethers_1.assertArgument)(allowIndexed, 'parameter cannot be indexed', 'obj.indexed', obj.indexed);
  686. indexed = !!indexed;
  687. }
  688. let type = obj.type;
  689. const arrayMatch = type.match(regexArrayType);
  690. if (arrayMatch) {
  691. const arrayLength = parseInt(arrayMatch[2] || '-1');
  692. const arrayChildren = ParamType.from({
  693. type: arrayMatch[1],
  694. components: obj.components,
  695. });
  696. return new ParamType(_guard, name || '', type, 'array', indexed, null, arrayLength, arrayChildren);
  697. }
  698. if (type === 'tuple' || type.startsWith('tuple(' /* fix: ) */) || type.startsWith('(' /* fix: ) */)) {
  699. const comps = obj.components != null ? obj.components.map((c) => ParamType.from(c)) : null;
  700. const tuple = new ParamType(_guard, name || '', type, 'tuple', indexed, comps, null, null);
  701. // @TODO: use lexer to validate and normalize type
  702. return tuple;
  703. }
  704. type = verifyBasicType(obj.type);
  705. return new ParamType(_guard, name || '', type, type, indexed, null, null, null);
  706. }
  707. /**
  708. * Returns true if %%value%% is a **ParamType**.
  709. */
  710. static isParamType(value) {
  711. return value && value[internal] === ParamTypeInternal;
  712. }
  713. }
  714. exports.ParamType = ParamType;
  715. /**
  716. * An abstract class to represent An individual fragment from a parse ABI.
  717. */
  718. class Fragment {
  719. /**
  720. * The type of the fragment.
  721. */
  722. type;
  723. /**
  724. * The inputs for the fragment.
  725. */
  726. inputs;
  727. /**
  728. * @private
  729. */
  730. constructor(guard, type, inputs) {
  731. (0, ethers_1.assertPrivate)(guard, _guard, 'Fragment');
  732. inputs = Object.freeze(inputs.slice());
  733. (0, ethers_1.defineProperties)(this, { type, inputs });
  734. }
  735. /**
  736. * Creates a new **Fragment** for %%obj%%, wich can be any supported
  737. * ABI frgament type.
  738. */
  739. static from(obj) {
  740. if (typeof obj === 'string') {
  741. // Try parsing JSON...
  742. try {
  743. Fragment.from(JSON.parse(obj));
  744. }
  745. catch (e) {
  746. //
  747. }
  748. // ...otherwise, use the human-readable lexer
  749. return Fragment.from(lex(obj));
  750. }
  751. if (obj instanceof TokenString) {
  752. // Human-readable ABI (already lexed)
  753. const type = obj.peekKeyword(KwTypes);
  754. switch (type) {
  755. case 'constructor':
  756. return ConstructorFragment.from(obj);
  757. case 'error':
  758. return ErrorFragment.from(obj);
  759. case 'event':
  760. return EventFragment.from(obj);
  761. case 'fallback':
  762. case 'receive':
  763. return FallbackFragment.from(obj);
  764. case 'function':
  765. return FunctionFragment.from(obj);
  766. case 'struct':
  767. return StructFragment.from(obj);
  768. }
  769. }
  770. else if (typeof obj === 'object') {
  771. // JSON ABI
  772. switch (obj.type) {
  773. case 'constructor':
  774. return ConstructorFragment.from(obj);
  775. case 'error':
  776. return ErrorFragment.from(obj);
  777. case 'event':
  778. return EventFragment.from(obj);
  779. case 'fallback':
  780. case 'receive':
  781. return FallbackFragment.from(obj);
  782. case 'function':
  783. return FunctionFragment.from(obj);
  784. case 'struct':
  785. return StructFragment.from(obj);
  786. }
  787. (0, ethers_1.assert)(false, `unsupported type: ${obj.type}`, 'UNSUPPORTED_OPERATION', {
  788. operation: 'Fragment.from',
  789. });
  790. }
  791. (0, ethers_1.assertArgument)(false, 'unsupported frgament object', 'obj', obj);
  792. }
  793. /**
  794. * Returns true if %%value%% is a [[ConstructorFragment]].
  795. */
  796. static isConstructor(value) {
  797. return ConstructorFragment.isFragment(value);
  798. }
  799. /**
  800. * Returns true if %%value%% is an [[ErrorFragment]].
  801. */
  802. static isError(value) {
  803. return ErrorFragment.isFragment(value);
  804. }
  805. /**
  806. * Returns true if %%value%% is an [[EventFragment]].
  807. */
  808. static isEvent(value) {
  809. return EventFragment.isFragment(value);
  810. }
  811. /**
  812. * Returns true if %%value%% is a [[FunctionFragment]].
  813. */
  814. static isFunction(value) {
  815. return FunctionFragment.isFragment(value);
  816. }
  817. /**
  818. * Returns true if %%value%% is a [[StructFragment]].
  819. */
  820. static isStruct(value) {
  821. return StructFragment.isFragment(value);
  822. }
  823. }
  824. exports.Fragment = Fragment;
  825. /**
  826. * An abstract class to represent An individual fragment
  827. * which has a name from a parse ABI.
  828. */
  829. class NamedFragment extends Fragment {
  830. /**
  831. * The name of the fragment.
  832. */
  833. name;
  834. /**
  835. * @private
  836. */
  837. constructor(guard, type, name, inputs) {
  838. super(guard, type, inputs);
  839. (0, ethers_1.assertArgument)(typeof name === 'string' && name.match(regexId), 'invalid identifier', 'name', name);
  840. inputs = Object.freeze(inputs.slice());
  841. (0, ethers_1.defineProperties)(this, { name });
  842. }
  843. }
  844. exports.NamedFragment = NamedFragment;
  845. function joinParams(format, params) {
  846. return '(' + params.map((p) => p.format(format)).join(format === 'full' ? ', ' : ',') + ')';
  847. }
  848. /**
  849. * A Fragment which represents a //Custom Error//.
  850. */
  851. class ErrorFragment extends NamedFragment {
  852. /**
  853. * @private
  854. */
  855. constructor(guard, name, inputs) {
  856. super(guard, 'error', name, inputs);
  857. Object.defineProperty(this, internal, { value: ErrorFragmentInternal });
  858. }
  859. /**
  860. * The Custom Error selector.
  861. */
  862. get selector() {
  863. return (0, ethers_2.id)(this.format('sighash')).substring(0, 10);
  864. }
  865. /**
  866. * Returns a string representation of this fragment as %%format%%.
  867. */
  868. format(format) {
  869. if (format == null) {
  870. format = 'sighash';
  871. }
  872. if (format === 'json') {
  873. return JSON.stringify({
  874. type: 'error',
  875. name: this.name,
  876. inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
  877. });
  878. }
  879. const result = [];
  880. if (format !== 'sighash') {
  881. result.push('error');
  882. }
  883. result.push(this.name + joinParams(format, this.inputs));
  884. return result.join(' ');
  885. }
  886. /**
  887. * Returns a new **ErrorFragment** for %%obj%%.
  888. */
  889. static from(obj) {
  890. if (ErrorFragment.isFragment(obj)) {
  891. return obj;
  892. }
  893. if (typeof obj === 'string') {
  894. return ErrorFragment.from(lex(obj));
  895. }
  896. else if (obj instanceof TokenString) {
  897. const name = consumeName('error', obj);
  898. const inputs = consumeParams(obj);
  899. consumeEoi(obj);
  900. return new ErrorFragment(_guard, name, inputs);
  901. }
  902. return new ErrorFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
  903. }
  904. /**
  905. * Returns ``true`` and provides a type guard if %%value%% is an
  906. * **ErrorFragment**.
  907. */
  908. static isFragment(value) {
  909. return value && value[internal] === ErrorFragmentInternal;
  910. }
  911. }
  912. exports.ErrorFragment = ErrorFragment;
  913. /**
  914. * A Fragment which represents an Event.
  915. */
  916. class EventFragment extends NamedFragment {
  917. /**
  918. * Whether this event is anonymous.
  919. */
  920. anonymous;
  921. /**
  922. * @private
  923. */
  924. constructor(guard, name, inputs, anonymous) {
  925. super(guard, 'event', name, inputs);
  926. Object.defineProperty(this, internal, { value: EventFragmentInternal });
  927. (0, ethers_1.defineProperties)(this, { anonymous });
  928. }
  929. /**
  930. * The Event topic hash.
  931. */
  932. get topicHash() {
  933. return (0, ethers_2.id)(this.format('sighash'));
  934. }
  935. /**
  936. * Returns a string representation of this event as %%format%%.
  937. */
  938. format(format) {
  939. if (format == null) {
  940. format = 'sighash';
  941. }
  942. if (format === 'json') {
  943. return JSON.stringify({
  944. type: 'event',
  945. anonymous: this.anonymous,
  946. name: this.name,
  947. inputs: this.inputs.map((i) => JSON.parse(i.format(format))),
  948. });
  949. }
  950. const result = [];
  951. if (format !== 'sighash') {
  952. result.push('event');
  953. }
  954. result.push(this.name + joinParams(format, this.inputs));
  955. if (format !== 'sighash' && this.anonymous) {
  956. result.push('anonymous');
  957. }
  958. return result.join(' ');
  959. }
  960. /**
  961. * Return the topic hash for an event with %%name%% and %%params%%.
  962. */
  963. static getTopicHash(name, params) {
  964. params = (params || []).map((p) => ParamType.from(p));
  965. const fragment = new EventFragment(_guard, name, params, false);
  966. return fragment.topicHash;
  967. }
  968. /**
  969. * Returns a new **EventFragment** for %%obj%%.
  970. */
  971. static from(obj) {
  972. if (EventFragment.isFragment(obj)) {
  973. return obj;
  974. }
  975. if (typeof obj === 'string') {
  976. return EventFragment.from(lex(obj));
  977. }
  978. else if (obj instanceof TokenString) {
  979. const name = consumeName('event', obj);
  980. const inputs = consumeParams(obj, true);
  981. const anonymous = !!consumeKeywords(obj, setify(['anonymous'])).has('anonymous');
  982. consumeEoi(obj);
  983. return new EventFragment(_guard, name, inputs, anonymous);
  984. }
  985. return new EventFragment(_guard, obj.name, obj.inputs ? obj.inputs.map((p) => ParamType.from(p, true)) : [], !!obj.anonymous);
  986. }
  987. /**
  988. * Returns ``true`` and provides a type guard if %%value%% is an
  989. * **EventFragment**.
  990. */
  991. static isFragment(value) {
  992. return value && value[internal] === EventFragmentInternal;
  993. }
  994. }
  995. exports.EventFragment = EventFragment;
  996. /**
  997. * A Fragment which represents a constructor.
  998. */
  999. class ConstructorFragment extends Fragment {
  1000. /**
  1001. * Whether the constructor can receive an endowment.
  1002. */
  1003. payable;
  1004. /**
  1005. * The recommended gas limit for deployment or ``null``.
  1006. */
  1007. gas;
  1008. /**
  1009. * @private
  1010. */
  1011. constructor(guard, type, inputs, payable, gas) {
  1012. super(guard, type, inputs);
  1013. Object.defineProperty(this, internal, {
  1014. value: ConstructorFragmentInternal,
  1015. });
  1016. (0, ethers_1.defineProperties)(this, { payable, gas });
  1017. }
  1018. /**
  1019. * Returns a string representation of this constructor as %%format%%.
  1020. */
  1021. format(format) {
  1022. (0, ethers_1.assert)(format != null && format !== 'sighash', 'cannot format a constructor for sighash', 'UNSUPPORTED_OPERATION', {
  1023. operation: 'format(sighash)',
  1024. });
  1025. if (format === 'json') {
  1026. return JSON.stringify({
  1027. type: 'constructor',
  1028. stateMutability: this.payable ? 'payable' : 'undefined',
  1029. payable: this.payable,
  1030. gas: this.gas != null ? this.gas : undefined,
  1031. inputs: this.inputs.map((i) => JSON.parse(i.format(format))),
  1032. });
  1033. }
  1034. const result = [`constructor${joinParams(format, this.inputs)}`];
  1035. result.push(this.payable ? 'payable' : 'nonpayable');
  1036. if (this.gas != null) {
  1037. result.push(`@${this.gas.toString()}`);
  1038. }
  1039. return result.join(' ');
  1040. }
  1041. /**
  1042. * Returns a new **ConstructorFragment** for %%obj%%.
  1043. */
  1044. static from(obj) {
  1045. if (ConstructorFragment.isFragment(obj)) {
  1046. return obj;
  1047. }
  1048. if (typeof obj === 'string') {
  1049. return ConstructorFragment.from(lex(obj));
  1050. }
  1051. else if (obj instanceof TokenString) {
  1052. consumeKeywords(obj, setify(['constructor']));
  1053. const inputs = consumeParams(obj);
  1054. const payable = !!consumeKeywords(obj, setify(['payable'])).has('payable');
  1055. const gas = consumeGas(obj);
  1056. consumeEoi(obj);
  1057. return new ConstructorFragment(_guard, 'constructor', inputs, payable, gas);
  1058. }
  1059. return new ConstructorFragment(_guard, 'constructor', obj.inputs ? obj.inputs.map(ParamType.from) : [], !!obj.payable, obj.gas != null ? obj.gas : null);
  1060. }
  1061. /**
  1062. * Returns ``true`` and provides a type guard if %%value%% is a
  1063. * **ConstructorFragment**.
  1064. */
  1065. static isFragment(value) {
  1066. return value && value[internal] === ConstructorFragmentInternal;
  1067. }
  1068. }
  1069. exports.ConstructorFragment = ConstructorFragment;
  1070. /**
  1071. * A Fragment which represents a method.
  1072. */
  1073. class FallbackFragment extends Fragment {
  1074. /**
  1075. * If the function can be sent value during invocation.
  1076. */
  1077. payable;
  1078. constructor(guard, inputs, payable) {
  1079. super(guard, 'fallback', inputs);
  1080. Object.defineProperty(this, internal, { value: FallbackFragmentInternal });
  1081. (0, ethers_1.defineProperties)(this, { payable });
  1082. }
  1083. /**
  1084. * Returns a string representation of this fallback as %%format%%.
  1085. */
  1086. format(format) {
  1087. const type = this.inputs.length === 0 ? 'receive' : 'fallback';
  1088. if (format === 'json') {
  1089. const stateMutability = this.payable ? 'payable' : 'nonpayable';
  1090. return JSON.stringify({ type, stateMutability });
  1091. }
  1092. return `${type}()${this.payable ? ' payable' : ''}`;
  1093. }
  1094. /**
  1095. * Returns a new **FallbackFragment** for %%obj%%.
  1096. */
  1097. static from(obj) {
  1098. if (FallbackFragment.isFragment(obj)) {
  1099. return obj;
  1100. }
  1101. if (typeof obj === 'string') {
  1102. return FallbackFragment.from(lex(obj));
  1103. }
  1104. else if (obj instanceof TokenString) {
  1105. const errorObj = obj.toString();
  1106. const topIsValid = obj.peekKeyword(setify(['fallback', 'receive']));
  1107. (0, ethers_1.assertArgument)(topIsValid, 'type must be fallback or receive', 'obj', errorObj);
  1108. const type = obj.popKeyword(setify(['fallback', 'receive']));
  1109. // receive()
  1110. if (type === 'receive') {
  1111. const inputs = consumeParams(obj);
  1112. (0, ethers_1.assertArgument)(inputs.length === 0, `receive cannot have arguments`, 'obj.inputs', inputs);
  1113. consumeKeywords(obj, setify(['payable']));
  1114. consumeEoi(obj);
  1115. return new FallbackFragment(_guard, [], true);
  1116. }
  1117. // fallback() [payable]
  1118. // fallback(bytes) [payable] returns (bytes)
  1119. let inputs = consumeParams(obj);
  1120. if (inputs.length) {
  1121. (0, ethers_1.assertArgument)(inputs.length === 1 && inputs[0].type === 'bytes', 'invalid fallback inputs', 'obj.inputs', inputs.map((i) => i.format('minimal')).join(', '));
  1122. }
  1123. else {
  1124. inputs = [ParamType.from('bytes')];
  1125. }
  1126. const mutability = consumeMutability(obj);
  1127. (0, ethers_1.assertArgument)(mutability === 'nonpayable' || mutability === 'payable', 'fallback cannot be constants', 'obj.stateMutability', mutability);
  1128. if (consumeKeywords(obj, setify(['returns'])).has('returns')) {
  1129. const outputs = consumeParams(obj);
  1130. (0, ethers_1.assertArgument)(outputs.length === 1 && outputs[0].type === 'bytes', 'invalid fallback outputs', 'obj.outputs', outputs.map((i) => i.format('minimal')).join(', '));
  1131. }
  1132. consumeEoi(obj);
  1133. return new FallbackFragment(_guard, inputs, mutability === 'payable');
  1134. }
  1135. if (obj.type === 'receive') {
  1136. return new FallbackFragment(_guard, [], true);
  1137. }
  1138. if (obj.type === 'fallback') {
  1139. const inputs = [ParamType.from('bytes')];
  1140. const payable = obj.stateMutability === 'payable';
  1141. return new FallbackFragment(_guard, inputs, payable);
  1142. }
  1143. (0, ethers_1.assertArgument)(false, 'invalid fallback description', 'obj', obj);
  1144. }
  1145. /**
  1146. * Returns ``true`` and provides a type guard if %%value%% is a
  1147. * **FallbackFragment**.
  1148. */
  1149. static isFragment(value) {
  1150. return value && value[internal] === FallbackFragmentInternal;
  1151. }
  1152. }
  1153. exports.FallbackFragment = FallbackFragment;
  1154. /**
  1155. * A Fragment which represents a method.
  1156. */
  1157. class FunctionFragment extends NamedFragment {
  1158. /**
  1159. * If the function is constant (e.g. ``pure`` or ``view`` functions).
  1160. */
  1161. constant;
  1162. /**
  1163. * The returned types for the result of calling this function.
  1164. */
  1165. outputs;
  1166. /**
  1167. * The state mutability (e.g. ``payable``, ``nonpayable``, ``view``
  1168. * or ``pure``)
  1169. */
  1170. stateMutability;
  1171. /**
  1172. * If the function can be sent value during invocation.
  1173. */
  1174. payable;
  1175. /**
  1176. * The recommended gas limit to send when calling this function.
  1177. */
  1178. gas;
  1179. /**
  1180. * @private
  1181. */
  1182. constructor(guard, name, stateMutability, inputs, outputs, gas) {
  1183. super(guard, 'function', name, inputs);
  1184. Object.defineProperty(this, internal, { value: FunctionFragmentInternal });
  1185. outputs = Object.freeze(outputs.slice());
  1186. const constant = stateMutability === 'view' || stateMutability === 'pure';
  1187. const payable = stateMutability === 'payable';
  1188. (0, ethers_1.defineProperties)(this, {
  1189. constant,
  1190. gas,
  1191. outputs,
  1192. payable,
  1193. stateMutability,
  1194. });
  1195. }
  1196. /**
  1197. * The Function selector.
  1198. */
  1199. get selector() {
  1200. return (0, ethers_2.id)(this.format('sighash')).substring(0, 10);
  1201. }
  1202. /**
  1203. * Returns a string representation of this function as %%format%%.
  1204. */
  1205. format(format) {
  1206. if (format == null) {
  1207. format = 'sighash';
  1208. }
  1209. if (format === 'json') {
  1210. return JSON.stringify({
  1211. type: 'function',
  1212. name: this.name,
  1213. constant: this.constant,
  1214. stateMutability: this.stateMutability !== 'nonpayable' ? this.stateMutability : undefined,
  1215. payable: this.payable,
  1216. gas: this.gas != null ? this.gas : undefined,
  1217. inputs: this.inputs.map((i) => JSON.parse(i.format(format))),
  1218. outputs: this.outputs.map((o) => JSON.parse(o.format(format))),
  1219. });
  1220. }
  1221. const result = [];
  1222. if (format !== 'sighash') {
  1223. result.push('function');
  1224. }
  1225. result.push(this.name + joinParams(format, this.inputs));
  1226. if (format !== 'sighash') {
  1227. if (this.stateMutability !== 'nonpayable') {
  1228. result.push(this.stateMutability);
  1229. }
  1230. if (this.outputs && this.outputs.length) {
  1231. result.push('returns');
  1232. result.push(joinParams(format, this.outputs));
  1233. }
  1234. if (this.gas != null) {
  1235. result.push(`@${this.gas.toString()}`);
  1236. }
  1237. }
  1238. return result.join(' ');
  1239. }
  1240. /**
  1241. * Return the selector for a function with %%name%% and %%params%%.
  1242. */
  1243. static getSelector(name, params) {
  1244. params = (params || []).map((p) => ParamType.from(p));
  1245. const fragment = new FunctionFragment(_guard, name, 'view', params, [], null);
  1246. return fragment.selector;
  1247. }
  1248. /**
  1249. * Returns a new **FunctionFragment** for %%obj%%.
  1250. */
  1251. static from(obj) {
  1252. if (FunctionFragment.isFragment(obj)) {
  1253. return obj;
  1254. }
  1255. if (typeof obj === 'string') {
  1256. return FunctionFragment.from(lex(obj));
  1257. }
  1258. else if (obj instanceof TokenString) {
  1259. const name = consumeName('function', obj);
  1260. const inputs = consumeParams(obj);
  1261. const mutability = consumeMutability(obj);
  1262. let outputs = [];
  1263. if (consumeKeywords(obj, setify(['returns'])).has('returns')) {
  1264. outputs = consumeParams(obj);
  1265. }
  1266. const gas = consumeGas(obj);
  1267. consumeEoi(obj);
  1268. return new FunctionFragment(_guard, name, mutability, inputs, outputs, gas);
  1269. }
  1270. let stateMutability = obj.stateMutability;
  1271. // Use legacy Solidity ABI logic if stateMutability is missing
  1272. if (stateMutability == null) {
  1273. stateMutability = 'payable';
  1274. if (typeof obj.constant === 'boolean') {
  1275. stateMutability = 'view';
  1276. if (!obj.constant) {
  1277. stateMutability = 'payable';
  1278. if (typeof obj.payable === 'boolean' && !obj.payable) {
  1279. stateMutability = 'nonpayable';
  1280. }
  1281. }
  1282. }
  1283. else if (typeof obj.payable === 'boolean' && !obj.payable) {
  1284. stateMutability = 'nonpayable';
  1285. }
  1286. }
  1287. // @TODO: verifyState for stateMutability (e.g. throw if
  1288. // payable: false but stateMutability is "nonpayable")
  1289. return new FunctionFragment(_guard, obj.name, stateMutability, obj.inputs ? obj.inputs.map(ParamType.from) : [], obj.outputs ? obj.outputs.map(ParamType.from) : [], obj.gas != null ? obj.gas : null);
  1290. }
  1291. /**
  1292. * Returns ``true`` and provides a type guard if %%value%% is a
  1293. * **FunctionFragment**.
  1294. */
  1295. static isFragment(value) {
  1296. return value && value[internal] === FunctionFragmentInternal;
  1297. }
  1298. }
  1299. exports.FunctionFragment = FunctionFragment;
  1300. /**
  1301. * A Fragment which represents a structure.
  1302. */
  1303. class StructFragment extends NamedFragment {
  1304. /**
  1305. * @private
  1306. */
  1307. constructor(guard, name, inputs) {
  1308. super(guard, 'struct', name, inputs);
  1309. Object.defineProperty(this, internal, { value: StructFragmentInternal });
  1310. }
  1311. /**
  1312. * Returns a string representation of this struct as %%format%%.
  1313. */
  1314. format() {
  1315. throw new Error('@TODO');
  1316. }
  1317. /**
  1318. * Returns a new **StructFragment** for %%obj%%.
  1319. */
  1320. static from(obj) {
  1321. if (typeof obj === 'string') {
  1322. return StructFragment.from(lex(obj));
  1323. }
  1324. else if (obj instanceof TokenString) {
  1325. const name = consumeName('struct', obj);
  1326. const inputs = consumeParams(obj);
  1327. consumeEoi(obj);
  1328. return new StructFragment(_guard, name, inputs);
  1329. }
  1330. return new StructFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
  1331. }
  1332. // @TODO: fix this return type
  1333. /**
  1334. * Returns ``true`` and provides a type guard if %%value%% is a
  1335. * **StructFragment**.
  1336. */
  1337. static isFragment(value) {
  1338. return value && value[internal] === StructFragmentInternal;
  1339. }
  1340. }
  1341. exports.StructFragment = StructFragment;
  1342. //# sourceMappingURL=fragments.js.map