UNPKG

@r3l/app

Version:
355 lines (286 loc) 11.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getRevertReason = getRevertReason; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _providers = require("@ethersproject/providers"); var _strings = require("@ethersproject/strings"); var _constants = require("@ethersproject/constants"); // This file is a modified version of the following library: // https://github.com/authereum/eth-revert-reason // implemented changes: // - add _tx parameter so we can call a tx without a txHash // - handle Ganache errors /** * Get the revert reason from just a transaction hash * @param {string} txHash - Hash of an Ethereum transaction * @param {object} tx - Ethereum transaction object * @param {string} network - Ethereum network name * @param {number || string} blockNumber - A block number or 'latest' to make the call from * @param {*} customProvider - Custom provider (Only ethers and web3 providers are supported at thsitime) */ function getRevertReason(_x, _x2) { return _getRevertReason.apply(this, arguments); } function _getRevertReason() { _getRevertReason = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(txHash, _tx) { var network, blockNumber, customProvider, provider, tx, code, _args = arguments; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: network = _args.length > 2 && _args[2] !== undefined ? _args[2] : 'mainnet'; blockNumber = _args.length > 3 && _args[3] !== undefined ? _args[3] : undefined; customProvider = _args.length > 4 && _args[4] !== undefined ? _args[4] : undefined; // Normalize the input params network = network.toLowerCase(); blockNumber = blockNumber || 'latest'; // Perform validation before defining a provider if (!txHash) { _context.next = 8; break; } _context.next = 8; return validateInputPreProvider(txHash, network); case 8: // If a web3 provider is passed in, wrap it in an ethers provider // A standard web3 provider will have `.version`, while an ethers will not if (customProvider && customProvider.version) { customProvider = new _providers.Web3Provider(customProvider.currentProvider); } provider = customProvider || (0, _providers.getDefaultProvider)(network); // Perform validation after defining a provider _context.next = 12; return validateInputPostProvider(txHash, network, blockNumber, provider); case 12: _context.prev = 12; _context.t0 = _tx; if (_context.t0) { _context.next = 18; break; } _context.next = 17; return provider.getTransaction(txHash); case 17: _context.t0 = _context.sent; case 18: tx = _context.t0; _context.next = 21; return getCode(tx, network, blockNumber, provider); case 21: code = _context.sent; return _context.abrupt("return", decodeMessage(code, network)); case 25: _context.prev = 25; _context.t1 = _context["catch"](12); throw new Error('Unable to decode revert reason'); case 28: case "end": return _context.stop(); } } }, _callee, null, [[12, 25]]); })); return _getRevertReason.apply(this, arguments); } function validateInputPreProvider(_x3, _x4) { return _validateInputPreProvider.apply(this, arguments); } function _validateInputPreProvider() { _validateInputPreProvider = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(txHash, network) { var networks; return _regenerator.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!(!/^0x([A-Fa-f0-9]{64})$/.test(txHash) || txHash.substring(0, 2) !== '0x')) { _context2.next = 2; break; } throw new Error('Invalid transaction hash'); case 2: // Only accept valid networks networks = ['mainnet', 'kovan', 'goerli', 'ropsten', 'rinkeby']; if (networks.includes(network)) { _context2.next = 5; break; } throw new Error('Not a valid network'); case 5: case "end": return _context2.stop(); } } }, _callee2); })); return _validateInputPreProvider.apply(this, arguments); } function validateInputPostProvider(_x5, _x6, _x7, _x8) { return _validateInputPostProvider.apply(this, arguments); } function _validateInputPostProvider() { _validateInputPostProvider = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(txHash, network, blockNumber, provider) { var tx, currentBlockNumber, errCode, infuraErrCode; return _regenerator.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: if (!(network === 'kovan')) { _context3.next = 11; break; } _context3.prev = 1; _context3.next = 4; return provider.getTransaction(txHash); case 4: tx = _context3.sent; getCode(tx, network, blockNumber, provider); _context3.next = 11; break; case 8: _context3.prev = 8; _context3.t0 = _context3["catch"](1); throw new Error('Please use a provider that exposes the Parity trace methods to decode the revert reason'); case 11: if (!(blockNumber !== 'latest')) { _context3.next = 30; break; } _context3.next = 14; return provider.getBlockNumber(); case 14: currentBlockNumber = _context3.sent; blockNumber = Number(blockNumber); // The block cannot be in the future if (!(blockNumber >= currentBlockNumber)) { _context3.next = 18; break; } throw new Error('You cannot use a blocknumber that has not yet happened'); case 18: if (!(blockNumber < currentBlockNumber - 128)) { _context3.next = 30; break; } _context3.prev = 19; _context3.next = 22; return provider.getBalance(_constants.AddressZero, blockNumber); case 22: _context3.next = 30; break; case 24: _context3.prev = 24; _context3.t1 = _context3["catch"](19); errCode = JSON.parse(_context3.t1.responseText).error.code; // NOTE: This error code is specific to Infura. Alchemy offers an Archive node by default, so an Alchemy node will never throw here. infuraErrCode = -32002; if (!(errCode === infuraErrCode)) { _context3.next = 30; break; } throw new Error('You cannot use a blocknumber that is older than 128 blocks. Please use a provider that uses a full archival node.'); case 30: case "end": return _context3.stop(); } } }, _callee3, null, [[1, 8], [19, 24]]); })); return _validateInputPostProvider.apply(this, arguments); } function decodeMessage(code, network) { // NOTE: `code` may end with 0's which will return a text string with empty whitespace characters // This will truncate all 0s and set up the hex string as expected // NOTE: Parity (Kovan) returns in a different format than other clients var codeString; var fnSelectorByteLength = 4; var dataOffsetByteLength = 32; var strLengthByteLength = 32; var strLengthStartPos = 2 + (fnSelectorByteLength + dataOffsetByteLength) * 2; var strDataStartPos = 2 + (fnSelectorByteLength + dataOffsetByteLength + strLengthByteLength) * 2; if (network === 'kovan') { var strLengthHex = code.slice(strLengthStartPos).slice(0, strLengthByteLength * 2); var strLengthInt = parseInt("0x".concat(strLengthHex), 16); var strDataEndPos = strDataStartPos + strLengthInt * 2; if (codeString === '0x') return ''; codeString = "0x".concat(code.slice(strDataStartPos, strDataEndPos)); } else { codeString = "0x".concat(code.substr(138)).replace(/0+$/, ''); } // If the codeString is an odd number of characters, add a trailing 0 if (codeString.length % 2 === 1) { codeString += '0'; } return (0, _strings.toUtf8String)(codeString); } function getCode(_x9, _x10, _x11, _x12) { return _getCode.apply(this, arguments); } function _getCode() { _getCode = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(tx, network, blockNumber, provider) { var data; return _regenerator.default.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: if (!(network === 'unknown' || network === 'local')) { _context4.next = 11; break; } _context4.prev = 1; _context4.next = 4; return provider.call(tx, blockNumber); case 4: return _context4.abrupt("return", _context4.sent); case 7: _context4.prev = 7; _context4.t0 = _context4["catch"](1); data = _context4.t0.data[Object.keys(_context4.t0.data)[0]]; return _context4.abrupt("return", data.return); case 11: if (!(network === 'kovan')) { _context4.next = 21; break; } _context4.prev = 12; _context4.next = 15; return provider.call(tx, blockNumber); case 15: return _context4.abrupt("return", _context4.sent); case 18: _context4.prev = 18; _context4.t1 = _context4["catch"](12); return _context4.abrupt("return", JSON.parse(_context4.t1.responseText).error.data.substr(9)); case 21: if (!(network === 'polygon')) { _context4.next = 33; break; } _context4.prev = 22; _context4.next = 25; return provider.call(tx, blockNumber); case 25: return _context4.abrupt("return", _context4.sent); case 28: _context4.prev = 28; _context4.t2 = _context4["catch"](22); return _context4.abrupt("return", _context4.t2.error ? _context4.t2.error.message.replace('code err execution reverted: ', '') : _context4.t2.message.replace('code err execution reverted: ', '')); case 31: _context4.next = 34; break; case 33: return _context4.abrupt("return", provider.call(tx, blockNumber)); case 34: case "end": return _context4.stop(); } } }, _callee4, null, [[1, 7], [12, 18], [22, 28]]); })); return _getCode.apply(this, arguments); } //# sourceMappingURL=eth-revert-reason.js.map