UNPKG

@ajna-finance/sdk

Version:

A typescript SDK that can be used to create Dapps in Ajna ecosystem.

197 lines 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTransaction = createTransaction; const tslib_1 = require("tslib"); const constants_1 = require("../constants"); const types_1 = require("../types"); /** * Creates a wrapped transaction object that can be used to submit, verify, and estimate gas for a transaction. * @param contract The ethers.js contract instance. * @param methodName The name of the method to call on the contract. * @param args An array of arguments to pass to the method. * @param overrides An optional object with transaction overrides, such as gasPrice and gasLimit. * @returns The wrapped transaction object. */ function createTransaction(contract, callData, overrides) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const { methodName, args = [] } = callData; const argsFiltered = args.filter(a => a !== undefined); const params = overrides ? [...argsFiltered, overrides] : [...argsFiltered]; const tx = yield contract.populateTransaction[methodName](...params); return new WrappedTransactionClass(tx, contract); }); } /** * A class representing a wrapped transaction that can be used to submit, verify, and estimate gas for a transaction. */ class WrappedTransactionClass { /** * Creates a new wrapped transaction instance. * @param transaction The populated transaction object. * @param contract The ethers.js contract instance. */ constructor(transaction, contract) { this._transaction = transaction; this._contract = contract; } /** * Verifies that the transaction can be executed by estimating its gas cost. * @returns A Promise that resolves to the estimated gas cost. * @throws {@link SdkError} An SDK error if the transaction execution failed and the error reason can be identified. * @throws The original error if the transaction execution failed and the error reason cannot be identified. */ verify() { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { return yield this._contract.provider.estimateGas(this._transaction); } catch (error) { const reason = this.parseNodeError(this._contract, error); throw new types_1.SdkError(reason, error); } }); } /** * Submits the transaction to the blockchain using the signer. * @returns The transaction receipt. */ submitResponse() { return tslib_1.__awaiter(this, void 0, void 0, function* () { return yield this._contract.signer.sendTransaction(this._transaction); }); } /** * Submits the transaction to the blockchain and waits for it to be mined. * @param confirmations The number of confirmations to wait for (default is 1). * @returns A Promise that resolves to the transaction receipt. */ submit(confirmations) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const response = yield this.submitResponse(); return yield response.wait(confirmations); }); } /** * Estimates gas, submits a transaction with gas estimate, and waits for the * node to acknowledge the transaction is pending. * @throws {@link SdkError} if transaction will fail at current block height. * @returns TransactionResponse */ verifyAndSubmitResponse() { return tslib_1.__awaiter(this, void 0, void 0, function* () { const estimatedGas = yield this.verify(); const txWithAdjustedGas = Object.assign(Object.assign({}, this._transaction), { gasLimit: +estimatedGas.mul(constants_1.GAS_MULTIPLIER) }); return yield this._contract.signer.sendTransaction(txWithAdjustedGas); }); } /** * Estimates gas, submits a transaction with gas estimate, and waits for the transaction to be * included in a block. * @param confirmations Optionally wait for specific number of confirmations. * @throws {@link SdkError} if transaction will fail at current block height. * @returns TransactionReceipt */ verifyAndSubmit(confirmations) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const response = yield this.verifyAndSubmitResponse(); return yield response.wait(confirmations); }); } /** * Reveals data emitted by a successful transaction. * @param receipt Receipt from a processed transaction. * @returns Map of events indexed by event name, and the data emitted in each event. */ getEventLogs(receipt) { const eventLogs = new Map(); let eventsForName; for (const log of receipt.logs) { try { const logDesc = this._contract.interface.parseLog(log); const eventLog = { eventName: logDesc.name, args: logDesc.args }; eventsForName = eventLogs.get(logDesc.name); if (eventsForName) eventsForName.push(eventLog); else eventLogs.set(logDesc.name, [eventLog]); } catch (ex) { // TODO: pass in an array of other contracts whose interfaces we could try parsing with if (!ex.toString().startsWith('Error: no matching event')) throw ex; } } return eventLogs; } /** * Looks through exception data to find the error hash for various node providers. * @param error Error thrown by Ethers in response to an estimateGas failure. * @returns string */ parseNodeError(contract, error) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3; // mainnet if ((_b = (_a = error === null || error === void 0 ? void 0 : error.error) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.originalError) { const errorHash = error.error.data.originalError.data; return ((_c = this.getCustomErrorFromHash(contract, errorHash)) !== null && _c !== void 0 ? _c : error.error.data.originalError.message); } if ((_d = error === null || error === void 0 ? void 0 : error.error) === null || _d === void 0 ? void 0 : _d.error) { const innerError = error.error.error; // works on mainnet-forked Ganache local testnet if ((_e = innerError.data) === null || _e === void 0 ? void 0 : _e.reason) return innerError.data.reason; if ((_f = innerError.data) === null || _f === void 0 ? void 0 : _f.result) { const errorHash = innerError.data.result; return this.getCustomErrorFromHash(contract, errorHash); } // works with Alchemy node on Goerli if (innerError.code === 3) { // if the hash does not map to a custom error, return the node-provided error const errorHash = innerError.data; return (_g = this.getCustomErrorFromHash(contract, errorHash)) !== null && _g !== void 0 ? _g : error.error.error; } } // metamask provider if ((_h = error === null || error === void 0 ? void 0 : error.data) === null || _h === void 0 ? void 0 : _h.data) { const errorHash = error.data.data.result; return ((_l = (_j = this.getCustomErrorFromHash(contract, errorHash)) !== null && _j !== void 0 ? _j : (_k = error.data.data) === null || _k === void 0 ? void 0 : _k.reason) !== null && _l !== void 0 ? _l : (_m = error.data.data) === null || _m === void 0 ? void 0 : _m.message); } // hardhat if ((_q = (_p = (_o = error === null || error === void 0 ? void 0 : error.error) === null || _o === void 0 ? void 0 : _o.data) === null || _p === void 0 ? void 0 : _p.data) === null || _q === void 0 ? void 0 : _q.data) { const errorHash = error.error.data.data.data; return ((_t = (_r = this.getCustomErrorFromHash(contract, errorHash)) !== null && _r !== void 0 ? _r : (_s = error.error.data) === null || _s === void 0 ? void 0 : _s.cause) !== null && _t !== void 0 ? _t : (_u = error.error.data) === null || _u === void 0 ? void 0 : _u.message); } // works with some L2 chains (Base, Polygon, Optimism) if ((_v = error === null || error === void 0 ? void 0 : error.error) === null || _v === void 0 ? void 0 : _v.data) { const errorHash = error.error.data; if (errorHash === null || errorHash === void 0 ? void 0 : errorHash.data) { return ((_y = (_w = this.getCustomErrorFromHash(contract, errorHash.data)) !== null && _w !== void 0 ? _w : (_x = error.error.data) === null || _x === void 0 ? void 0 : _x.cause) !== null && _y !== void 0 ? _y : (_z = error.error.data) === null || _z === void 0 ? void 0 : _z.message); } return ((_2 = (_0 = this.getCustomErrorFromHash(contract, errorHash)) !== null && _0 !== void 0 ? _0 : (_1 = error.error.data) === null || _1 === void 0 ? void 0 : _1.cause) !== null && _2 !== void 0 ? _2 : (_3 = error.error.data) === null || _3 === void 0 ? void 0 : _3.message); } return 'Revert reason unknown'; } /** * Matches error hash from node with custom errors in contract. * @param contract Instance of contract with interface prepared from ABI. * @param errorData Error hash string parsed from exception raised by node. * @returns Human-readable reason explaining why transaction would revert. */ getCustomErrorFromHash(contract, errorData) { if (!errorData) { return undefined; } // retrieve the list of custom errors available to the contract const customErrorNames = Object.keys(contract.interface.errors); // index the contract's errors by the first 8 bytes of their hash const errorsByHash = customErrorNames.reduce((acc, name) => { return Object.assign(Object.assign({}, acc), { [contract.interface.getSighash(name)]: name }); }, {}); const errorPrefix = errorData.substring(0, 10); if (errorPrefix in errorsByHash) { return errorsByHash[errorPrefix]; } return undefined; } } //# sourceMappingURL=transactions.js.map